1185 lines
31 KiB
C
1185 lines
31 KiB
C
/*++
|
||
|
||
Copyright (c) 1992 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
fs_rec.c
|
||
|
||
Abstract:
|
||
|
||
This module contains the main functions for the mini-file system recognizer
|
||
driver.
|
||
|
||
Author:
|
||
|
||
Darryl E. Havens (darrylh) 22-nov-1993
|
||
|
||
Environment:
|
||
|
||
Kernel mode, local to I/O system
|
||
|
||
Revision History:
|
||
|
||
|
||
--*/
|
||
|
||
#include "fs_rec.h"
|
||
|
||
//
|
||
// The local debug trace level
|
||
//
|
||
|
||
#define Dbg (FSREC_DEBUG_LEVEL_FSREC)
|
||
|
||
#if DBG
|
||
|
||
#include <stdarg.h>
|
||
#include <stdio.h>
|
||
|
||
LONG FsRecDebugTraceLevel = 0;
|
||
LONG FsRecDebugTraceIndent = 0;
|
||
|
||
#endif
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(INIT,DriverEntry)
|
||
#pragma alloc_text(INIT,FsRecCreateAndRegisterDO)
|
||
|
||
#pragma alloc_text(PAGE,FsRecCleanupClose)
|
||
#pragma alloc_text(PAGE,FsRecCreate)
|
||
#pragma alloc_text(PAGE,FsRecFsControl)
|
||
#pragma alloc_text(PAGE,FsRecGetDeviceSectorSize)
|
||
#pragma alloc_text(PAGE,FsRecGetDeviceSectors)
|
||
#pragma alloc_text(PAGE,FsRecLoadFileSystem)
|
||
#pragma alloc_text(PAGE,FsRecReadBlock)
|
||
#pragma alloc_text(PAGE,FsRecUnload)
|
||
#pragma alloc_text(PAGE,FsRecShutdown)
|
||
#endif // ALLOC_PRAGMA
|
||
|
||
//
|
||
// Pointer to a mutex for serializing driver loads. Note this a pointer
|
||
// and not a static KEVENT because it must be nonpaged and this entire
|
||
// driver is paged.
|
||
//
|
||
|
||
PKEVENT FsRecLoadSync;
|
||
|
||
|
||
NTSTATUS
|
||
DriverEntry (
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PUNICODE_STRING RegistryPath
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is invoked once when the driver is loaded to allow the driver
|
||
to initialize itself. The initialization for the driver consists of simply
|
||
creating a device object for each type of file system recognized by this
|
||
driver, and then registering each as active file systems.
|
||
|
||
Arguments:
|
||
|
||
DriverObject - Pointer to the driver object for this driver.
|
||
|
||
RegistryPath - Pointer to the registry service node for this driver.
|
||
|
||
Return Value:
|
||
|
||
The function value is the final status of the initialization for the driver.
|
||
|
||
--*/
|
||
|
||
{
|
||
PDEVICE_OBJECT UdfsMainRecognizerDeviceObject;
|
||
PDEVICE_OBJECT FatMainRecognizerDeviceObject;
|
||
NTSTATUS status;
|
||
ULONG count = 0;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Mark the entire driver as pagable.
|
||
//
|
||
|
||
MmPageEntireDriver ((PVOID)DriverEntry);
|
||
|
||
//
|
||
// Begin by initializing the driver object so that it the driver is
|
||
// prepared to provide services.
|
||
//
|
||
|
||
DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = FsRecFsControl;
|
||
DriverObject->MajorFunction[IRP_MJ_CREATE] = FsRecCreate;
|
||
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = FsRecCleanupClose;
|
||
DriverObject->MajorFunction[IRP_MJ_CLOSE] = FsRecCleanupClose;
|
||
DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = FsRecShutdown;
|
||
DriverObject->DriverUnload = FsRecUnload;
|
||
|
||
FsRecLoadSync = ExAllocatePoolWithTag( NonPagedPool, sizeof(KEVENT), FSREC_POOL_TAG );
|
||
|
||
if (FsRecLoadSync == NULL) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
KeInitializeEvent( FsRecLoadSync, SynchronizationEvent, TRUE );
|
||
|
||
//
|
||
// Create and initialize each of the file system driver type device
|
||
// objects.
|
||
//
|
||
|
||
status = FsRecCreateAndRegisterDO( DriverObject,
|
||
NULL,
|
||
NULL,
|
||
L"\\Cdfs",
|
||
L"\\FileSystem\\CdfsRecognizer",
|
||
CdfsFileSystem,
|
||
FILE_DEVICE_CD_ROM_FILE_SYSTEM );
|
||
if (NT_SUCCESS( status )) {
|
||
count++;
|
||
}
|
||
|
||
status = FsRecCreateAndRegisterDO( DriverObject,
|
||
NULL,
|
||
&UdfsMainRecognizerDeviceObject,
|
||
L"\\UdfsCdRom",
|
||
L"\\FileSystem\\UdfsCdRomRecognizer",
|
||
UdfsFileSystem,
|
||
FILE_DEVICE_CD_ROM_FILE_SYSTEM );
|
||
if (NT_SUCCESS( status )) {
|
||
count++;
|
||
}
|
||
|
||
status = FsRecCreateAndRegisterDO( DriverObject,
|
||
UdfsMainRecognizerDeviceObject,
|
||
NULL,
|
||
L"\\UdfsDisk",
|
||
L"\\FileSystem\\UdfsDiskRecognizer",
|
||
UdfsFileSystem,
|
||
FILE_DEVICE_DISK_FILE_SYSTEM );
|
||
if (NT_SUCCESS( status )) {
|
||
count++;
|
||
}
|
||
|
||
status = FsRecCreateAndRegisterDO( DriverObject,
|
||
NULL,
|
||
&FatMainRecognizerDeviceObject,
|
||
L"\\FatDisk",
|
||
L"\\FileSystem\\FatDiskRecognizer",
|
||
FatFileSystem,
|
||
FILE_DEVICE_DISK_FILE_SYSTEM );
|
||
if (NT_SUCCESS( status )) {
|
||
count++;
|
||
}
|
||
|
||
status = FsRecCreateAndRegisterDO( DriverObject,
|
||
FatMainRecognizerDeviceObject,
|
||
NULL,
|
||
L"\\FatCdrom",
|
||
L"\\FileSystem\\FatCdRomRecognizer",
|
||
FatFileSystem,
|
||
FILE_DEVICE_CD_ROM_FILE_SYSTEM );
|
||
if (NT_SUCCESS( status )) {
|
||
count++;
|
||
}
|
||
|
||
status = FsRecCreateAndRegisterDO( DriverObject,
|
||
NULL,
|
||
NULL,
|
||
L"\\Ntfs",
|
||
L"\\FileSystem\\NtfsRecognizer",
|
||
NtfsFileSystem,
|
||
FILE_DEVICE_DISK_FILE_SYSTEM );
|
||
if (NT_SUCCESS( status )) {
|
||
count++;
|
||
}
|
||
|
||
if (count) {
|
||
return STATUS_SUCCESS;
|
||
} else {
|
||
return STATUS_IMAGE_ALREADY_LOADED;
|
||
}
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
FsRecCleanupClose (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is invoked when someone attempts to cleanup or close one of
|
||
the system recognizer's registered device objects.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - Pointer to the device object being closed.
|
||
|
||
Irp - Pointer to the cleanup/close IRP.
|
||
|
||
Return Value:
|
||
|
||
The final function value is STATUS_SUCCESS.
|
||
|
||
--*/
|
||
|
||
{
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Simply complete the request successfully (note that IoStatus.Status in
|
||
// Irp is already initialized to STATUS_SUCCESS).
|
||
//
|
||
|
||
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
FsRecCreate (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is invoked when someone attempts to open one of the file
|
||
system recognizer's registered device objects.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - Pointer to the device object being opened.
|
||
|
||
Irp - Pointer to the create IRP.
|
||
|
||
Return Value:
|
||
|
||
The final function value indicates whether or not the open was successful.
|
||
|
||
--*/
|
||
|
||
{
|
||
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation( Irp );
|
||
NTSTATUS status;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Simply ensure that the name of the "file" being opened is NULL, and
|
||
// complete the request accordingly.
|
||
//
|
||
|
||
if (irpSp->FileObject->FileName.Length) {
|
||
status = STATUS_OBJECT_PATH_NOT_FOUND;
|
||
} else {
|
||
status = STATUS_SUCCESS;
|
||
}
|
||
|
||
Irp->IoStatus.Status = status;
|
||
Irp->IoStatus.Information = FILE_OPENED;
|
||
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||
return status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
FsRecCreateAndRegisterDO (
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PDEVICE_OBJECT HeadRecognizer OPTIONAL,
|
||
OUT PDEVICE_OBJECT *NewRecognizer OPTIONAL,
|
||
IN PWCHAR RecFileSystem,
|
||
IN PWCHAR FileSystemName,
|
||
IN FILE_SYSTEM_TYPE FileSystemType,
|
||
IN DEVICE_TYPE DeviceType
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine creates a device object for the specified file system type and
|
||
registers it as an active file system.
|
||
|
||
Arguments:
|
||
|
||
DriverObject - Pointer to the driver object for this driver.
|
||
|
||
HeadRecognizer - Optionally supplies a pre-existing recognizer that the
|
||
newly created DO should be jointly serialized and unregistered with.
|
||
This is useful if a given filesystem exists on multiple device types
|
||
and thus requires multiple recognizers.
|
||
|
||
NewDeviceObject - Receives the created DO on success..
|
||
|
||
RecFileSystem - Name of the file system to be recognized.
|
||
|
||
FileSystemName - Name of file system device object to be registered.
|
||
|
||
FileSystemType - Type of this file system recognizer device object.
|
||
|
||
DeviceType - Type of media this file system recognizer device object will inspect.
|
||
|
||
Return Value:
|
||
|
||
The final function value indicates whether or not the device object was
|
||
successfully created and registered.
|
||
|
||
--*/
|
||
|
||
{
|
||
PDEVICE_OBJECT deviceObject;
|
||
NTSTATUS status;
|
||
UNICODE_STRING nameString;
|
||
OBJECT_ATTRIBUTES objectAttributes;
|
||
HANDLE fsHandle;
|
||
IO_STATUS_BLOCK ioStatus;
|
||
PDEVICE_EXTENSION deviceExtension;
|
||
|
||
PAGED_CODE();
|
||
|
||
if (NewRecognizer) {
|
||
|
||
*NewRecognizer = NULL;
|
||
}
|
||
|
||
//
|
||
// Begin by attempting to open the file system driver's device object. If
|
||
// it works, then the file system is already loaded, so don't load this
|
||
// driver. Otherwise, this mini-driver is the one that should be loaded.
|
||
//
|
||
|
||
RtlInitUnicodeString( &nameString, RecFileSystem );
|
||
InitializeObjectAttributes( &objectAttributes,
|
||
&nameString,
|
||
OBJ_CASE_INSENSITIVE,
|
||
(HANDLE) NULL,
|
||
(PSECURITY_DESCRIPTOR) NULL );
|
||
|
||
status = ZwCreateFile( &fsHandle,
|
||
SYNCHRONIZE,
|
||
&objectAttributes,
|
||
&ioStatus,
|
||
(PLARGE_INTEGER) NULL,
|
||
0,
|
||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||
FILE_OPEN,
|
||
0,
|
||
(PVOID) NULL,
|
||
0 );
|
||
|
||
if (NT_SUCCESS( status )) {
|
||
ZwClose( fsHandle );
|
||
} else if (status != STATUS_OBJECT_NAME_NOT_FOUND) {
|
||
status = STATUS_SUCCESS;
|
||
}
|
||
|
||
if (NT_SUCCESS( status )) {
|
||
return STATUS_IMAGE_ALREADY_LOADED;
|
||
}
|
||
|
||
//
|
||
// Attempt to create a device object for this driver. This device object
|
||
// will be used to represent the driver as an active file system in the
|
||
// system.
|
||
//
|
||
|
||
RtlInitUnicodeString( &nameString, FileSystemName );
|
||
|
||
status = IoCreateDevice( DriverObject,
|
||
sizeof( DEVICE_EXTENSION ),
|
||
&nameString,
|
||
DeviceType,
|
||
0,
|
||
FALSE,
|
||
&deviceObject );
|
||
if (!NT_SUCCESS( status )) {
|
||
return status;
|
||
}
|
||
|
||
status = IoRegisterShutdownNotification (deviceObject);
|
||
if (!NT_SUCCESS( status )) {
|
||
IoDeleteDevice (deviceObject);
|
||
return status;
|
||
}
|
||
|
||
//
|
||
// Initialize the device extension for this device object.
|
||
//
|
||
|
||
deviceExtension = (PDEVICE_EXTENSION) deviceObject->DeviceExtension;
|
||
deviceExtension->FileSystemType = FileSystemType;
|
||
deviceExtension->State = Active;
|
||
|
||
//
|
||
// Is this a filesystem being jointly recognized by recognizers for
|
||
// different device types?
|
||
//
|
||
|
||
if (HeadRecognizer) {
|
||
|
||
//
|
||
// Link into the list.
|
||
//
|
||
|
||
deviceExtension->CoRecognizer = ((PDEVICE_EXTENSION)HeadRecognizer->DeviceExtension)->CoRecognizer;
|
||
((PDEVICE_EXTENSION)HeadRecognizer->DeviceExtension)->CoRecognizer = deviceObject;
|
||
|
||
} else {
|
||
|
||
//
|
||
// Initialize the list of codependant recognizer objects.
|
||
//
|
||
|
||
deviceExtension->CoRecognizer = deviceObject;
|
||
}
|
||
|
||
#if _PNP_POWER_
|
||
deviceObject->DeviceObjectExtension->PowerControlNeeded = FALSE;
|
||
#endif
|
||
|
||
//
|
||
// Finally, register this driver as an active, loaded file system and
|
||
// return to the caller.
|
||
//
|
||
|
||
if (NewRecognizer) {
|
||
|
||
*NewRecognizer = deviceObject;
|
||
}
|
||
|
||
IoRegisterFileSystem( deviceObject );
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
FsRecFsControl (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function performs the mount and driver reload functions for this mini-
|
||
file system recognizer driver.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - Pointer to this driver's device object.
|
||
|
||
Irp - Pointer to the I/O Request Packet (IRP) representing the function to
|
||
be performed.
|
||
|
||
Return Value:
|
||
|
||
The function value is the final status of the operation.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
PDEVICE_EXTENSION deviceExtension;
|
||
PIO_STACK_LOCATION irpSp;
|
||
NTSTATUS status;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Simply vector to the appropriate FS control function given the type
|
||
// of file system being interrogated.
|
||
//
|
||
|
||
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
|
||
irpSp = IoGetCurrentIrpStackLocation( Irp );
|
||
|
||
//
|
||
// Handle the inactive recognizer states directly.
|
||
//
|
||
|
||
if (deviceExtension->State != Active && irpSp->MinorFunction == IRP_MN_MOUNT_VOLUME) {
|
||
|
||
if (deviceExtension->State == Transparent) {
|
||
|
||
status = STATUS_UNRECOGNIZED_VOLUME;
|
||
|
||
} else {
|
||
|
||
status = STATUS_FS_DRIVER_REQUIRED;
|
||
}
|
||
|
||
Irp->IoStatus.Status = status;
|
||
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||
return status;
|
||
}
|
||
|
||
switch ( deviceExtension->FileSystemType ) {
|
||
|
||
case FatFileSystem:
|
||
|
||
status = FatRecFsControl( DeviceObject, Irp );
|
||
break;
|
||
|
||
case NtfsFileSystem:
|
||
|
||
status = NtfsRecFsControl( DeviceObject, Irp );
|
||
break;
|
||
|
||
case CdfsFileSystem:
|
||
|
||
status = CdfsRecFsControl( DeviceObject, Irp );
|
||
break;
|
||
|
||
case UdfsFileSystem:
|
||
|
||
status = UdfsRecFsControl( DeviceObject, Irp );
|
||
break;
|
||
|
||
default:
|
||
|
||
status = STATUS_INVALID_DEVICE_REQUEST;
|
||
}
|
||
|
||
return status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
FsRecShutdown (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function is the shutdown handle for each of the recognisers file systems
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - Pointer to this driver's device object.
|
||
|
||
Irp - Shutdown IRP
|
||
|
||
Return Value:
|
||
|
||
The function value is the final status of the operation.
|
||
|
||
|
||
--*/
|
||
{
|
||
PDEVICE_EXTENSION DeviceExtension;
|
||
|
||
DeviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
|
||
|
||
if (DeviceExtension->State != Transparent) {
|
||
IoUnregisterFileSystem (DeviceObject);
|
||
DeviceExtension->State = Transparent;
|
||
}
|
||
IoDeleteDevice (DeviceObject);
|
||
|
||
Irp->IoStatus.Status = STATUS_SUCCESS;
|
||
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
VOID
|
||
FsRecUnload (
|
||
IN PDRIVER_OBJECT DriverObject
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine cleans up the driver's data structures so that it can be
|
||
unloaded.
|
||
|
||
Arguments:
|
||
|
||
DriverObject - Pointer to the driver object for this driver.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PAGED_CODE();
|
||
|
||
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.
|
||
//
|
||
|
||
KeEnterCriticalRegion();
|
||
|
||
KeWaitForSingleObject( FsRecLoadSync,
|
||
Executive,
|
||
KernelMode,
|
||
FALSE,
|
||
NULL );
|
||
|
||
//
|
||
// 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.
|
||
|
||
--*/
|
||
|
||
{
|
||
GET_LENGTH_INFORMATION lengthInfo;
|
||
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_LENGTH_INFO,
|
||
DeviceObject,
|
||
(PVOID) NULL,
|
||
0,
|
||
&lengthInfo,
|
||
sizeof( lengthInfo ),
|
||
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( lengthInfo.Length,
|
||
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
|
||
|