⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fs_rec.c

📁 微软win2k的fsrec源码,驱动中展示了如何启动文件系统驱动程序,如何根据硬盘和光盘上的文件系统类型调用不同的文件系统驱动程序
💻 C
📖 第 1 页 / 共 2 页
字号:

    while (DriverObject->DeviceObject) {
        IoDeleteDevice( DriverObject->DeviceObject );
    }

    ExFreePool( FsRecLoadSync );

    return;
}


NTSTATUS
FsRecLoadFileSystem (
    IN PDEVICE_OBJECT DeviceObject,
    IN PWCHAR DriverServiceName
    )

/*++


Routine Description:

    This routine performs the common work of loading a filesystem on behalf
    of one of our recognizers.

Arguments:

    DeviceObject - Pointer to the device object for the recognizer.

    DriverServiceName - Specifies the name of the node in the registry
        associated with the driver to be loaded.

Return Value:

    NTSTATUS.  The recognizer will be set into a transparent mode on return.
    
--*/

{
    UNICODE_STRING driverName;
    PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
    NTSTATUS status = STATUS_IMAGE_ALREADY_LOADED;

    PAGED_CODE();

    //
    //  Quickly check if the recognizer has already fired.
    //
    
    if (deviceExtension->State != Transparent) {
    
        //
        //  Serialize all threads trying to load this filesystem.
        //
        //  We need to do this for several reasons.  With the new behavior in
        //  IoRegisterFileSystem, we do not know ahead of time whether the
        //  filesystem has been loaded ahead or behind this recognizer in the
        //  scan queue.  This means that we cannot make this recognizer transparent
        //  before the real filesystem has become registered, or else if the
        //  filesystem loads behind us we may let threads go through that will
        //  not find it in that window of time.
        //
        //  The reason this is possible is that NtLoadDriver does not guarantee
        //  that if it returns STATUS_IMAGE_ALREADY_LOADED, that the driver in
        //  question has actually initialized itself, which *is* guaranteed if
        //  it returns STATUS_SUCCESS.  We have to keep these threads bottled
        //  up until they can rescan with the promise that what they need is there.
        //
        //  As a bonus, we can now guarantee that the recognizer goes away in
        //  all cases, not just when the driver successfully loads itself.
        //
        
        KeWaitForSingleObject( FsRecLoadSync,
                               Executive,
                               KernelMode,
                               FALSE,
                               NULL );
        KeEnterCriticalRegion();
    
        //
        //  Attempt the filesystem load precisely once for all recognizers
        //  of a given filesystem.
        //
        
        if (deviceExtension->State == Active) {

            //
            //  For bonus points, in the future we may want to log an event
            //  on failure.
            //

            RtlInitUnicodeString( &driverName, DriverServiceName );
            status = ZwLoadDriver( &driverName );

            //
            //  Now walk all codependant recognizers and instruct them to go
            //  into the fast unload state.  Since IO only expects the fsDO
            //  it is asking to load a filesystem to to unregister itself, if
            //  we unregistered all of the co-recognizers they would dangle.
            //  Unfortunately, this means that fsrec may wind up hanging around
            //  quite a bit longer than strictly neccesary.
            //
            //  Note: we come right back to the original DeviceObject at the
            //  end of this loop (important).  It is also very important that
            //  we only did this once since after we release the mutex the co-
            //  recognizers may begin going away in any order.
            //

            while (deviceExtension->State != FastUnload) {

                deviceExtension->State = FastUnload;

                DeviceObject = deviceExtension->CoRecognizer;
                deviceExtension = DeviceObject->DeviceExtension;
            } 
        }
        
        //
        //  Unregister this recognizer precisely once.
        //

        if (deviceExtension->State != Transparent) {
            
            IoUnregisterFileSystem( DeviceObject );
            deviceExtension->State = Transparent;
        }
        
        KeSetEvent( FsRecLoadSync, 0, FALSE );
        KeLeaveCriticalRegion();
    }
    
    return status;
}


BOOLEAN
FsRecGetDeviceSectors (
    IN PDEVICE_OBJECT DeviceObject,
    IN ULONG BytesPerSector,
    OUT PLARGE_INTEGER NumberOfSectors
    )

/*++

Routine Description:

    This routine returns information about the partition represented by the
    device object.

Arguments:

    DeviceObject - Pointer to the device object from which to read.

    BytesPerSector - The number of bytes per sector for the device being read.

    NumberOfSectors - Variable to receive the number of sectors for this
        partition.

Return Value:

    The function value is TRUE if the information was found, otherwise FALSE.

--*/

{
    PARTITION_INFORMATION partitionInfo;
    IO_STATUS_BLOCK ioStatus;
    KEVENT event;
    PIRP irp;
    NTSTATUS status;
    ULONG remainder;

    PAGED_CODE();

    //
    //  We only do this for disks right now. This is likely to change when we
    //  have to recognize CDUDF media.
    //

    if (DeviceObject->DeviceType != FILE_DEVICE_DISK) {

        return FALSE;
    }

    //
    // Get the number of sectors on this partition.
    //

    KeInitializeEvent( &event, SynchronizationEvent, FALSE );

    irp = IoBuildDeviceIoControlRequest( IOCTL_DISK_GET_PARTITION_INFO,
                                         DeviceObject,
                                         (PVOID) NULL,
                                         0,
                                         &partitionInfo,
                                         sizeof( partitionInfo ),
                                         FALSE,
                                         &event,
                                         &ioStatus );
    if (!irp) {
        return FALSE;
    }

    //
    //  Override verify logic - we don't care. The fact we're in the picture means
    //  someone is trying to mount new/changed media in the first place.
    //
    
    SetFlag( IoGetNextIrpStackLocation( irp )->Flags, SL_OVERRIDE_VERIFY_VOLUME );

    status = IoCallDriver( DeviceObject, irp );
    if (status == STATUS_PENDING) {
        (VOID) KeWaitForSingleObject( &event,
                                      Executive,
                                      KernelMode,
                                      FALSE,
                                      (PLARGE_INTEGER) NULL );
        status = ioStatus.Status;
    }

    if (!NT_SUCCESS( status )) {
        return FALSE;
    }

    *NumberOfSectors = RtlExtendedLargeIntegerDivide( partitionInfo.PartitionLength,
                                                      BytesPerSector,
                                                      &remainder );

    return TRUE;
}


BOOLEAN
FsRecGetDeviceSectorSize (
    IN PDEVICE_OBJECT DeviceObject,
    OUT PULONG BytesPerSector
    )

/*++

Routine Description:

    This routine returns the sector size of the underlying device.

Arguments:

    DeviceObject - Pointer to the device object from which to read.

    BytesPerSector - Variable to receive the number of bytes per sector for the
        device being read.

Return Value:

    The function value is TRUE if the information was found, otherwise FALSE.

--*/

{
    DISK_GEOMETRY diskGeometry;
    IO_STATUS_BLOCK ioStatus;
    KEVENT event;
    PIRP irp;
    NTSTATUS status;
    ULONG ControlCode;

    PAGED_CODE();

    //
    //  Figure out what kind of device we have so we can use the right IOCTL.
    //

    switch (DeviceObject->DeviceType) {
        case FILE_DEVICE_CD_ROM:
            ControlCode = IOCTL_CDROM_GET_DRIVE_GEOMETRY;
            break;

        case FILE_DEVICE_DISK:
            ControlCode = IOCTL_DISK_GET_DRIVE_GEOMETRY;
            break;

        default:
            return FALSE;
    }

    KeInitializeEvent( &event, SynchronizationEvent, FALSE );
    irp = IoBuildDeviceIoControlRequest( ControlCode,
                                         DeviceObject,
                                         (PVOID) NULL,
                                         0,
                                         &diskGeometry,
                                         sizeof( diskGeometry ),
                                         FALSE,
                                         &event,
                                         &ioStatus );

    if (!irp) {
        return FALSE;
    }

    //
    //  Override verify logic - we don't care. The fact we're in the picture means
    //  someone is trying to mount new/changed media in the first place.
    //
    
    SetFlag( IoGetNextIrpStackLocation( irp )->Flags, SL_OVERRIDE_VERIFY_VOLUME );
    
    status = IoCallDriver( DeviceObject, irp );
    if (status == STATUS_PENDING) {
        (VOID) KeWaitForSingleObject( &event,
                                      Executive,
                                      KernelMode,
                                      FALSE,
                                      (PLARGE_INTEGER) NULL );
        status = ioStatus.Status;
    }

    if (!NT_SUCCESS( status )) {
        return FALSE;
    }

    //
    // Ensure that the drive actually knows how many bytes there are per
    // sector.  Floppy drives do not know if the media is unformatted.
    //

    if (!diskGeometry.BytesPerSector) {
        return FALSE;
    }

    //
    // Store the return values for the caller.
    //

    *BytesPerSector = diskGeometry.BytesPerSector;

    return TRUE;
}


BOOLEAN
FsRecReadBlock(
    IN PDEVICE_OBJECT DeviceObject,
    IN PLARGE_INTEGER ByteOffset,
    IN ULONG MinimumBytes,
    IN ULONG BytesPerSector,
    OUT PVOID *Buffer,
    OUT PBOOLEAN IsDeviceFailure OPTIONAL
    )

/*++

Routine Description:

    This routine reads a minimum numbers of bytes into a buffer starting at
    the byte offset from the base of the device represented by the device
    object.

Arguments:

    DeviceObject - Pointer to the device object from which to read.

    ByteOffset - Pointer to a 64-bit byte offset from the base of the device
        from which to start the read.

    MinimumBytes - Supplies the minimum number of bytes to be read.

    BytesPerSector - The number of bytes per sector for the device being read.

    Buffer - Variable to receive a pointer to the allocated buffer containing
        the bytes read.
        
    IsDeviceFailure - Variable to receive an indication whether a failure
        was a result of talking to the device.

Return Value:

    The function value is TRUE if the bytes were read, otherwise FALSE.

--*/

{
    #define RoundUp( x, y ) ( ((x + (y-1)) / y) * y )

    IO_STATUS_BLOCK ioStatus;
    KEVENT event;
    PIRP irp;
    NTSTATUS status;

    PAGED_CODE();

    if (IsDeviceFailure) {
        *IsDeviceFailure = FALSE;
    }
    
    KeInitializeEvent( &event, SynchronizationEvent, FALSE );

    //
    // Set the minimum number of bytes to read to the maximum of the bytes that
    // the caller wants to read, and the number of bytes in a sector.
    //

    if (MinimumBytes < BytesPerSector) {
        MinimumBytes = BytesPerSector;
    } else {
        MinimumBytes = RoundUp( MinimumBytes, BytesPerSector );
    }

    //
    // Allocate a buffer large enough to contain the bytes required, round the
    // request to a page boundary to solve any alignment requirements.
    //

    if (!*Buffer) {

        *Buffer = ExAllocatePoolWithTag( NonPagedPool,
					 (MinimumBytes + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1),
					 FSREC_POOL_TAG );
        if (!*Buffer) {
            return FALSE;
        }
    }

    //
    // Read the actual bytes off of the media.
    //

    irp = IoBuildSynchronousFsdRequest( IRP_MJ_READ,
                                        DeviceObject,
                                        *Buffer,
                                        MinimumBytes,
                                        ByteOffset,
                                        &event,
                                        &ioStatus );
    if (!irp) {
        return FALSE;
    }
    
    //
    //  Override verify logic - we don't care. The fact we're in the picture means
    //  someone is trying to mount new/changed media in the first place.
    //
    
    SetFlag( IoGetNextIrpStackLocation( irp )->Flags, SL_OVERRIDE_VERIFY_VOLUME );

    status = IoCallDriver( DeviceObject, irp );
    if (status == STATUS_PENDING) {
        (VOID) KeWaitForSingleObject( &event,
                                      Executive,
                                      KernelMode,
                                      FALSE,
                                      (PLARGE_INTEGER) NULL );
        status = ioStatus.Status;
    }

    if (!NT_SUCCESS( status )) {

        if (IsDeviceFailure) {
            *IsDeviceFailure = TRUE;
        }
        return FALSE;
    }

    return TRUE;
}


#if DBG
BOOLEAN
FsRecDebugTrace (
    LONG IndentIncrement,
    ULONG TraceMask,
    PCHAR Format,
    ...
    )

/*++

Routine Description:

    This routine is a simple debug info printer that returns a constant boolean value.  This
    makes it possible to splice it into the middle of boolean expressions to discover which
    elements are firing.
    
    We will use this as our general debug printer.  See udfdata.h for how we use the DebugTrace
    macro to accomplish the effect.
    
Arguments:

    IndentIncrement - amount to change the indentation by.
    
    TraceMask - specification of what debug trace level this call should be noisy at.

Return Value:

    USHORT - The 16bit CRC

--*/

{
    va_list Arglist;
    LONG i;
    UCHAR Buffer[128];
    int Bytes;

#define Min(a, b)   ((a) < (b) ? (a) : (b))
    
    if (TraceMask == 0 || (FsRecDebugTraceLevel & TraceMask) != 0) {

        //
        //  Emit a preamble of our thread ID.
        //
        
        DbgPrint( "%p:", PsGetCurrentThread());

        if (IndentIncrement < 0) {
            
            FsRecDebugTraceIndent += IndentIncrement;
        }

        if (FsRecDebugTraceIndent < 0) {
            
            FsRecDebugTraceIndent = 0;
        }

        //
        //  Build the indent in big chunks since calling DbgPrint repeatedly is expensive.
        //
        
        for (i = FsRecDebugTraceIndent; i > 0; i -= (sizeof(Buffer) - 1)) {

            RtlFillMemory( Buffer, Min( i, (sizeof(Buffer) - 1 )), ' ');
            *(Buffer + Min( i, (sizeof(Buffer) - 1 ))) = '\0';
            
            DbgPrint( Buffer );
        }

        //
        // Format the output into a buffer and then print it.
        //

        va_start( Arglist, Format );
        Bytes = _vsnprintf( Buffer, sizeof(Buffer), Format, Arglist );
        va_end( Arglist );

        //
        // detect buffer overflow
        //

        if (Bytes == -1) {

            Buffer[sizeof(Buffer) - 1] = '\n';
        }

        DbgPrint( Buffer );

        if (IndentIncrement > 0) {

            FsRecDebugTraceIndent += IndentIncrement;
        }
    }

    return TRUE;
}
#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -