mirror of
https://github.com/reactos/reactos.git
synced 2025-08-08 19:43:00 +00:00
956 lines
25 KiB
C
956 lines
25 KiB
C
/*************************************************************************
|
|
*
|
|
* File: fsctrl.c
|
|
*
|
|
* Module: Ext2 File System Driver (Kernel mode execution only)
|
|
*
|
|
* Description:
|
|
* Contains code to handle the various File System Control calls.
|
|
*
|
|
* Author: Manoj Paul Joseph
|
|
*
|
|
*
|
|
*************************************************************************/
|
|
|
|
|
|
|
|
#include "ext2fsd.h"
|
|
|
|
|
|
|
|
// define the file specific bug-check id
|
|
#define EXT2_BUG_CHECK_ID EXT2_FILE_FILE_CONTROL
|
|
#define DEBUG_LEVEL (DEBUG_TRACE_FSCTRL)
|
|
|
|
|
|
NTSTATUS
|
|
Ext2MountVolume(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp );
|
|
|
|
NTSTATUS
|
|
Ext2GetPartitionInfo(
|
|
IN PDEVICE_OBJECT TargetDeviceObject,
|
|
IN PPARTITION_INFORMATION PartitionInformation
|
|
);
|
|
|
|
NTSTATUS
|
|
Ext2GetDriveLayout(
|
|
IN PDEVICE_OBJECT TargetDeviceObject,
|
|
IN PDRIVE_LAYOUT_INFORMATION DriveLayoutInformation,
|
|
IN int BufferSize
|
|
);
|
|
|
|
BOOLEAN
|
|
Ext2PerformVerifyDiskRead(
|
|
IN PDEVICE_OBJECT TargetDeviceObject,
|
|
IN PVOID Buffer,
|
|
IN LONGLONG Lbo,
|
|
IN ULONG NumberOfBytesToRead
|
|
);
|
|
|
|
NTSTATUS Ext2UserFileSystemRequest(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp );
|
|
|
|
|
|
/*************************************************************************
|
|
*
|
|
* Function: Ext2FileSystemControl
|
|
*
|
|
* Description:
|
|
* The I/O Manager will invoke this routine to handle a
|
|
* File System Control IRP
|
|
*
|
|
* Expected Interrupt Level (for execution) :
|
|
*
|
|
* ???
|
|
*
|
|
* Arguments:
|
|
*
|
|
* DeviceObject - Supplies the volume device object where the
|
|
* file exists
|
|
*
|
|
* Irp - Supplies the Irp being processed
|
|
*
|
|
*
|
|
* Return Value:
|
|
*
|
|
* NTSTATUS - The FSD status for the IRP
|
|
*
|
|
*************************************************************************/
|
|
NTSTATUS NTAPI
|
|
Ext2FileSystemControl(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PIO_STACK_LOCATION IrpSp;
|
|
|
|
DebugTrace(DEBUG_TRACE_IRP_ENTRY, "File System Control IRP Received...", 0);
|
|
|
|
// Ext2BreakPoint();
|
|
|
|
FsRtlEnterFileSystem();
|
|
|
|
ASSERT(DeviceObject);
|
|
ASSERT(Irp);
|
|
|
|
//
|
|
// Get a pointer to the current Irp stack location
|
|
//
|
|
IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
|
|
|
|
|
if( IrpSp->MinorFunction == IRP_MN_MOUNT_VOLUME )
|
|
{
|
|
DebugTrace(DEBUG_TRACE_MOUNT, "Mount Request Received...", 0);
|
|
Status = Ext2MountVolume ( Irp, IrpSp );
|
|
Ext2CompleteRequest( Irp, Status );
|
|
}
|
|
else if( IrpSp->MinorFunction == IRP_MN_USER_FS_REQUEST )
|
|
{
|
|
DebugTrace(DEBUG_TRACE_FSCTRL, "IRP_MN_USER_FS_REQUEST received...", 0);
|
|
Status = Ext2UserFileSystemRequest( Irp, IrpSp );
|
|
Ext2CompleteRequest( Irp, Status );
|
|
}
|
|
else
|
|
{
|
|
if( IrpSp->MinorFunction == IRP_MN_VERIFY_VOLUME )
|
|
{
|
|
DebugTrace(DEBUG_TRACE_FSCTRL, "IRP_MN_VERIFY_VOLUME received...", 0);
|
|
}
|
|
else if( IrpSp->MinorFunction == IRP_MN_LOAD_FILE_SYSTEM )
|
|
{
|
|
DebugTrace(DEBUG_TRACE_FSCTRL, "IRP_MN_LOAD_FILE_SYSTEM received...", 0);
|
|
}
|
|
else
|
|
{
|
|
DebugTrace(DEBUG_TRACE_FSCTRL, "Unknown Minor IRP code received...", 0);
|
|
}
|
|
|
|
Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
Ext2CompleteRequest( Irp, Status );
|
|
}
|
|
|
|
FsRtlExitFileSystem();
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
*
|
|
* Function: Ext2MountVolume()
|
|
*
|
|
* Description:
|
|
* This routine verifies and mounts the volume;
|
|
* Called by FSCTRL IRP handler to attempt a
|
|
* volume mount.
|
|
*
|
|
* Expected Interrupt Level (for execution) :
|
|
*
|
|
* IRQL_PASSIVE_LEVEL
|
|
*
|
|
*
|
|
* Arguments:
|
|
*
|
|
* Irp - Supplies the Irp being processed
|
|
* IrpSp - Irp Stack Location pointer
|
|
*
|
|
* Return Value:
|
|
*
|
|
* NTSTATUS - The Mount status
|
|
*
|
|
*************************************************************************/
|
|
NTSTATUS
|
|
Ext2MountVolume (
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp )
|
|
{
|
|
|
|
// Volume Parameter Block
|
|
PVPB PtrVPB;
|
|
|
|
// The target device object
|
|
PDEVICE_OBJECT TargetDeviceObject = NULL;
|
|
|
|
// The new volume device object (to be created if partition is Ext2)
|
|
PDEVICE_OBJECT PtrVolumeDeviceObject = NULL;
|
|
|
|
// Return Status
|
|
NTSTATUS Status = STATUS_UNRECOGNIZED_VOLUME;
|
|
|
|
// Number of bytes to read for Volume verification...
|
|
unsigned long NumberOfBytesToRead = 0;
|
|
|
|
// Starting Offset for 'read'
|
|
LONGLONG StartingOffset = 0;
|
|
|
|
// Boot Sector information...
|
|
PPACKED_BOOT_SECTOR BootSector = NULL;
|
|
|
|
// Ext2 Super Block information...
|
|
PEXT2_SUPER_BLOCK SuperBlock = NULL;
|
|
|
|
// Volume Control Block
|
|
PtrExt2VCB PtrVCB = NULL;
|
|
|
|
// The File Object for the root directory
|
|
PFILE_OBJECT PtrRootFileObject = NULL;
|
|
|
|
// Flag
|
|
int WeClearedVerifyRequiredBit;
|
|
|
|
// Used by a for loop...
|
|
unsigned int i;
|
|
|
|
//
|
|
LARGE_INTEGER VolumeByteOffset;
|
|
|
|
unsigned long LogicalBlockSize = 0;
|
|
|
|
// Buffer Control Block
|
|
PBCB PtrBCB = NULL;
|
|
|
|
// Cache Buffer - used for pinned access of volume...
|
|
PVOID PtrCacheBuffer = NULL;
|
|
|
|
PEXT2_GROUP_DESCRIPTOR PtrGroupDescriptor = NULL;
|
|
|
|
// Inititalising variables
|
|
|
|
PtrVPB = IrpSp->Parameters.MountVolume.Vpb;
|
|
TargetDeviceObject = IrpSp->Parameters.MountVolume.DeviceObject;
|
|
|
|
try
|
|
{
|
|
//
|
|
// 1. Reading in Volume meta data
|
|
//
|
|
|
|
// Temporarily clear the DO_VERIFY_VOLUME Flag
|
|
WeClearedVerifyRequiredBit = 0;
|
|
if ( Ext2IsFlagOn( PtrVPB->RealDevice->Flags, DO_VERIFY_VOLUME ) )
|
|
{
|
|
Ext2ClearFlag( PtrVPB->RealDevice->Flags, DO_VERIFY_VOLUME );
|
|
WeClearedVerifyRequiredBit = 1;
|
|
}
|
|
|
|
// Allocating memory for reading in Boot Sector...
|
|
NumberOfBytesToRead = Ext2Align( sizeof( EXT2_SUPER_BLOCK ), TargetDeviceObject->SectorSize );
|
|
BootSector = Ext2AllocatePool( PagedPool, NumberOfBytesToRead );
|
|
RtlZeroMemory( BootSector, NumberOfBytesToRead );
|
|
|
|
// Reading in Boot Sector
|
|
StartingOffset = 0L;
|
|
Ext2PerformVerifyDiskRead ( TargetDeviceObject,
|
|
BootSector, StartingOffset, NumberOfBytesToRead );
|
|
|
|
// Reject a volume that contains fat artifacts
|
|
|
|
DebugTrace(DEBUG_TRACE_MOUNT, "OEM[%s]", BootSector->Oem);
|
|
if (BootSector->Oem[0])
|
|
{
|
|
try_return();
|
|
}
|
|
|
|
// Allocating memory for reading in Super Block...
|
|
|
|
SuperBlock = Ext2AllocatePool( PagedPool, NumberOfBytesToRead );
|
|
RtlZeroMemory( SuperBlock, NumberOfBytesToRead );
|
|
StartingOffset = 1024;
|
|
|
|
// Reading in the Super Block...
|
|
Ext2PerformVerifyDiskRead ( TargetDeviceObject,
|
|
SuperBlock, StartingOffset, NumberOfBytesToRead );
|
|
|
|
// Resetting the DO_VERIFY_VOLUME Flag
|
|
if( WeClearedVerifyRequiredBit )
|
|
{
|
|
PtrVPB->RealDevice->Flags |= DO_VERIFY_VOLUME;
|
|
}
|
|
|
|
// Verifying the Super Block..
|
|
if( SuperBlock->s_magic == EXT2_SUPER_MAGIC )
|
|
{
|
|
//
|
|
// Found a valid super block.
|
|
// No more tests for now.
|
|
// Assuming that this is an ext2 partition...
|
|
// Going ahead with mount.
|
|
//
|
|
DebugTrace(DEBUG_TRACE_MOUNT, "Valid Ext2 partition detected\nMounting %s...", SuperBlock->s_volume_name);
|
|
//
|
|
// 2. Creating a volume device object
|
|
//
|
|
if (!NT_SUCCESS( IoCreateDevice(
|
|
Ext2GlobalData.Ext2DriverObject, // (This) Driver object
|
|
Ext2QuadAlign( sizeof(Ext2VCB) ), // Device Extension
|
|
NULL, // Device Name - no name ;)
|
|
FILE_DEVICE_DISK_FILE_SYSTEM, // Disk File System
|
|
0, // DeviceCharacteristics
|
|
FALSE, // Not an exclusive device
|
|
(PDEVICE_OBJECT *)&PtrVolumeDeviceObject)) // The Volume Device Object
|
|
)
|
|
{
|
|
try_return();
|
|
}
|
|
|
|
//
|
|
// Our alignment requirement is the larger of the processor alignment requirement
|
|
// already in the volume device object and that in the TargetDeviceObject
|
|
//
|
|
|
|
if (TargetDeviceObject->AlignmentRequirement > PtrVolumeDeviceObject->AlignmentRequirement)
|
|
{
|
|
PtrVolumeDeviceObject->AlignmentRequirement = TargetDeviceObject->AlignmentRequirement;
|
|
}
|
|
|
|
//
|
|
// Clearing the Device Initialising Flag
|
|
//
|
|
Ext2ClearFlag( PtrVolumeDeviceObject->Flags, DO_DEVICE_INITIALIZING);
|
|
|
|
|
|
//
|
|
// Setting the Stack Size for the newly created Volume Device Object
|
|
//
|
|
PtrVolumeDeviceObject->StackSize = (CCHAR)(TargetDeviceObject->StackSize + 1);
|
|
|
|
|
|
//
|
|
// 3. Creating the link between Target Device Object
|
|
// and the Volume Device Object via the Volume Parameter Block
|
|
//
|
|
PtrVPB->DeviceObject = PtrVolumeDeviceObject;
|
|
|
|
// Remembring the Volume parameters in the VPB bock
|
|
for( i = 0; i < 16 ; i++ )
|
|
{
|
|
PtrVPB->VolumeLabel[i] = SuperBlock->s_volume_name[i];
|
|
if( SuperBlock->s_volume_name[i] == 0 )
|
|
break;
|
|
}
|
|
PtrVPB->VolumeLabelLength = i * 2;
|
|
PtrVPB->SerialNumber = ((ULONG*)SuperBlock->s_uuid)[0];
|
|
|
|
//
|
|
// 4. Initialise the Volume Comtrol Block
|
|
//
|
|
{
|
|
LARGE_INTEGER AllocationSize;
|
|
|
|
AllocationSize .QuadPart =
|
|
( EXT2_MIN_BLOCK_SIZE << SuperBlock->s_log_block_size ) *
|
|
SuperBlock->s_blocks_count;
|
|
|
|
Ext2InitializeVCB(
|
|
PtrVolumeDeviceObject,
|
|
TargetDeviceObject,
|
|
PtrVPB,
|
|
&AllocationSize);
|
|
PtrVCB = (PtrExt2VCB)(PtrVolumeDeviceObject->DeviceExtension);
|
|
ASSERT( PtrVCB );
|
|
}
|
|
|
|
PtrVCB->InodesCount = SuperBlock->s_inodes_count;
|
|
PtrVCB->BlocksCount = SuperBlock->s_blocks_count;
|
|
PtrVCB->ReservedBlocksCount = SuperBlock->s_r_blocks_count;
|
|
PtrVCB->FreeBlocksCount = SuperBlock->s_free_blocks_count;
|
|
PtrVCB->FreeInodesCount = SuperBlock->s_free_inodes_count;
|
|
PtrVCB->LogBlockSize = SuperBlock->s_log_block_size;
|
|
PtrVCB->InodesPerGroup = SuperBlock->s_inodes_per_group;
|
|
PtrVCB->BlocksPerGroup = SuperBlock->s_blocks_per_group;
|
|
PtrVCB->NoOfGroups = ( SuperBlock->s_blocks_count - SuperBlock->s_first_data_block
|
|
+ SuperBlock->s_blocks_per_group - 1 )
|
|
/ SuperBlock->s_blocks_per_group;
|
|
if( SuperBlock->s_rev_level )
|
|
{
|
|
PtrVCB->InodeSize = SuperBlock->s_inode_size;
|
|
}
|
|
else
|
|
{
|
|
PtrVCB->InodeSize = sizeof( EXT2_INODE );
|
|
}
|
|
|
|
PtrVCB->PtrGroupDescriptors = Ext2AllocatePool( NonPagedPool, sizeof( Ext2GroupDescriptors ) * PtrVCB->NoOfGroups );
|
|
|
|
RtlZeroMemory( PtrVCB->PtrGroupDescriptors , sizeof( Ext2GroupDescriptors ) * PtrVCB->NoOfGroups );
|
|
|
|
//
|
|
// Attempting to Read in some matadata from the Cache...
|
|
// using pin access...
|
|
//
|
|
LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;
|
|
|
|
//
|
|
// Reading Group Descriptors...
|
|
//
|
|
if( PtrVCB->LogBlockSize )
|
|
{
|
|
// First block contains the descriptors...
|
|
VolumeByteOffset.QuadPart = LogicalBlockSize;
|
|
}
|
|
else
|
|
{
|
|
// Second block contains the descriptors...
|
|
VolumeByteOffset.QuadPart = LogicalBlockSize * 2;
|
|
}
|
|
|
|
NumberOfBytesToRead = PtrVCB->NoOfGroups * sizeof( struct ext2_group_desc );
|
|
NumberOfBytesToRead = Ext2Align( NumberOfBytesToRead, LogicalBlockSize );
|
|
|
|
if (!CcMapData( PtrVCB->PtrStreamFileObject,
|
|
&VolumeByteOffset,
|
|
NumberOfBytesToRead,
|
|
TRUE,
|
|
&PtrBCB,
|
|
&PtrCacheBuffer ))
|
|
{
|
|
DebugTrace(DEBUG_TRACE_ERROR, "Cache read failiure while reading in volume meta data", 0);
|
|
try_return( Status = STATUS_INSUFFICIENT_RESOURCES );
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Saving up Often Used Group Descriptor Information in the VCB...
|
|
//
|
|
unsigned int DescIndex ;
|
|
|
|
DebugTrace(DEBUG_TRACE_MISC, "Cache hit while reading in volume meta data", 0);
|
|
PtrGroupDescriptor = (PEXT2_GROUP_DESCRIPTOR )PtrCacheBuffer;
|
|
for( DescIndex = 0; DescIndex < PtrVCB->NoOfGroups; DescIndex++ )
|
|
{
|
|
PtrVCB->PtrGroupDescriptors[ DescIndex ].InodeTablesBlock
|
|
= PtrGroupDescriptor[ DescIndex ].bg_inode_table;
|
|
|
|
PtrVCB->PtrGroupDescriptors[ DescIndex ].InodeBitmapBlock
|
|
= PtrGroupDescriptor[ DescIndex ].bg_inode_bitmap
|
|
;
|
|
PtrVCB->PtrGroupDescriptors[ DescIndex ].BlockBitmapBlock
|
|
= PtrGroupDescriptor[ DescIndex ].bg_block_bitmap
|
|
;
|
|
PtrVCB->PtrGroupDescriptors[ DescIndex ].FreeBlocksCount
|
|
= PtrGroupDescriptor[ DescIndex ].bg_free_blocks_count;
|
|
|
|
PtrVCB->PtrGroupDescriptors[ DescIndex ].FreeInodesCount
|
|
= PtrGroupDescriptor[ DescIndex ].bg_free_inodes_count;
|
|
}
|
|
CcUnpinData( PtrBCB );
|
|
PtrBCB = NULL;
|
|
}
|
|
|
|
//
|
|
// 5. Creating a Root Directory FCB
|
|
//
|
|
PtrRootFileObject = IoCreateStreamFileObject(NULL, TargetDeviceObject );
|
|
if( !PtrRootFileObject )
|
|
{
|
|
try_return();
|
|
}
|
|
//
|
|
// Associate the file stream with the Volume parameter block...
|
|
// I do it now
|
|
//
|
|
PtrRootFileObject->Vpb = PtrVCB->PtrVPB;
|
|
|
|
PtrRootFileObject->ReadAccess = TRUE;
|
|
PtrRootFileObject->WriteAccess = TRUE;
|
|
|
|
{
|
|
PtrExt2ObjectName PtrObjectName;
|
|
LARGE_INTEGER ZeroSize;
|
|
|
|
PtrObjectName = Ext2AllocateObjectName();
|
|
RtlInitUnicodeString( &PtrObjectName->ObjectName, L"\\" );
|
|
Ext2CopyWideCharToUnicodeString( &PtrObjectName->ObjectName, L"\\" );
|
|
|
|
|
|
ZeroSize.QuadPart = 0;
|
|
if ( !NT_SUCCESS( Ext2CreateNewFCB(
|
|
&PtrVCB->PtrRootDirectoryFCB, // Root FCB
|
|
ZeroSize, // AllocationSize,
|
|
ZeroSize, // EndOfFile,
|
|
PtrRootFileObject, // The Root Dircetory File Object
|
|
PtrVCB,
|
|
PtrObjectName ) ) )
|
|
{
|
|
try_return();
|
|
}
|
|
|
|
|
|
PtrVCB->PtrRootDirectoryFCB->FCBFlags |= EXT2_FCB_DIRECTORY | EXT2_FCB_ROOT_DIRECTORY;
|
|
|
|
|
|
}
|
|
|
|
PtrVCB->PtrRootDirectoryFCB->DcbFcb.Dcb.PtrDirFileObject = PtrRootFileObject;
|
|
PtrVCB->PtrRootDirectoryFCB->INodeNo = EXT2_ROOT_INO;
|
|
PtrRootFileObject->SectionObjectPointer = &(PtrVCB->PtrRootDirectoryFCB->NTRequiredFCB.SectionObject);
|
|
RtlInitUnicodeString( &PtrRootFileObject->FileName, L"\\" );
|
|
|
|
Ext2InitializeFCBInodeInfo( PtrVCB->PtrRootDirectoryFCB );
|
|
|
|
//
|
|
// Initiating caching for root directory...
|
|
//
|
|
|
|
CcInitializeCacheMap(PtrRootFileObject,
|
|
(PCC_FILE_SIZES)(&(PtrVCB->PtrRootDirectoryFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize)),
|
|
TRUE, // We will utilize pin access for directories
|
|
&(Ext2GlobalData.CacheMgrCallBacks), // callbacks
|
|
PtrVCB->PtrRootDirectoryFCB ); // The context used in callbacks
|
|
|
|
|
|
//
|
|
// 6. Update the VCB Flags
|
|
//
|
|
PtrVCB->VCBFlags |= EXT2_VCB_FLAGS_VOLUME_MOUNTED ; // | EXT2_VCB_FLAGS_VOLUME_READ_ONLY;
|
|
|
|
|
|
//
|
|
// 7. Mount Success
|
|
//
|
|
Status = STATUS_SUCCESS;
|
|
|
|
{
|
|
//
|
|
// This block is for testing....
|
|
// To be removed...
|
|
|
|
/*
|
|
EXT2_INODE Inode ;
|
|
Ext2ReadInode( PtrVCB, 100, &Inode );
|
|
DebugTrace( DEBUG_TRACE_MISC, "Inode size= %lX [FS Ctrl]", Inode.i_size );
|
|
Ext2DeallocInode( NULL, PtrVCB, 0xfb6 );
|
|
*/
|
|
}
|
|
|
|
// ObDereferenceObject( TargetDeviceObject );
|
|
}
|
|
else
|
|
{
|
|
DebugTrace(DEBUG_TRACE_MOUNT, "Failing mount. Partition not Ext2...", 0);
|
|
}
|
|
|
|
try_exit: NOTHING;
|
|
}
|
|
finally
|
|
{
|
|
// Freeing Allocated Memory...
|
|
if( SuperBlock != NULL )
|
|
{
|
|
DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [FS Ctrl]", SuperBlock );
|
|
ExFreePool( SuperBlock );
|
|
}
|
|
if( BootSector != NULL )
|
|
{
|
|
DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [FS Ctrl]", BootSector);
|
|
ExFreePool( BootSector );
|
|
}
|
|
|
|
// start unwinding if we were unsuccessful
|
|
if (!NT_SUCCESS( Status ))
|
|
{
|
|
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/*************************************************************************
|
|
*
|
|
* Function: Ext2MountVolume()
|
|
*
|
|
* Description:
|
|
* This routine is used for querying the partition information.
|
|
*
|
|
* Expected Interrupt Level (for execution) :
|
|
* IRQL_PASSIVE_LEVEL
|
|
*
|
|
* Arguments:
|
|
*
|
|
* TargetDeviceObject - The target of the query
|
|
* PartitionInformation - Receives the result of the query
|
|
*
|
|
* Return Value:
|
|
*
|
|
* NTSTATUS - The return status for the operation
|
|
*
|
|
*************************************************************************/
|
|
NTSTATUS
|
|
Ext2GetPartitionInfo (
|
|
IN PDEVICE_OBJECT TargetDeviceObject,
|
|
IN PPARTITION_INFORMATION PartitionInformation
|
|
)
|
|
{
|
|
PIRP Irp;
|
|
KEVENT *PtrEvent = NULL;
|
|
NTSTATUS Status;
|
|
IO_STATUS_BLOCK Iosb;
|
|
|
|
//
|
|
// Query the partition table
|
|
//
|
|
PtrEvent = ( KEVENT * )Ext2AllocatePool( NonPagedPool, Ext2QuadAlign( sizeof( KEVENT ) ) );
|
|
|
|
|
|
|
|
|
|
KeInitializeEvent( PtrEvent, NotificationEvent, FALSE );
|
|
|
|
Irp = IoBuildDeviceIoControlRequest( IOCTL_DISK_GET_PARTITION_INFO,
|
|
TargetDeviceObject,
|
|
NULL,
|
|
0,
|
|
PartitionInformation,
|
|
sizeof(PARTITION_INFORMATION),
|
|
FALSE,
|
|
PtrEvent,
|
|
&Iosb );
|
|
|
|
if ( Irp == NULL )
|
|
{
|
|
DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [FS Ctrl]", PtrEvent);
|
|
ExFreePool( PtrEvent );
|
|
return 0;
|
|
}
|
|
|
|
Status = IoCallDriver( TargetDeviceObject, Irp );
|
|
|
|
if ( Status == STATUS_PENDING ) {
|
|
|
|
(VOID) KeWaitForSingleObject( PtrEvent,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
(PLARGE_INTEGER)NULL );
|
|
|
|
Status = Iosb.Status;
|
|
}
|
|
DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [FS Ctrl]", PtrEvent);
|
|
ExFreePool( PtrEvent );
|
|
return Status;
|
|
}
|
|
|
|
/*************************************************************************
|
|
*
|
|
* Function: Ext2MountVolume()
|
|
*
|
|
* Description:
|
|
* This routine is used for querying the Drive Layout Information.
|
|
*
|
|
* Expected Interrupt Level (for execution) :
|
|
* IRQL_PASSIVE_LEVEL
|
|
*
|
|
* Arguments:
|
|
*
|
|
* TargetDeviceObject - The target of the query
|
|
* PartitionInformation - Receives the result of the query
|
|
*
|
|
* Return Value:
|
|
*
|
|
* NTSTATUS - The return status for the operation
|
|
*
|
|
*************************************************************************/
|
|
NTSTATUS Ext2GetDriveLayout (
|
|
IN PDEVICE_OBJECT TargetDeviceObject,
|
|
IN PDRIVE_LAYOUT_INFORMATION DriveLayoutInformation,
|
|
IN int BufferSize
|
|
)
|
|
{
|
|
PIRP Irp;
|
|
KEVENT *PtrEvent = NULL;
|
|
NTSTATUS Status;
|
|
IO_STATUS_BLOCK Iosb;
|
|
|
|
//
|
|
// Query the partition table
|
|
//
|
|
PtrEvent = ( KEVENT * )Ext2AllocatePool( NonPagedPool, Ext2QuadAlign( sizeof( KEVENT ) ) );
|
|
KeInitializeEvent( PtrEvent, NotificationEvent, FALSE );
|
|
Irp = IoBuildDeviceIoControlRequest( IOCTL_DISK_GET_DRIVE_LAYOUT,
|
|
TargetDeviceObject,
|
|
NULL,
|
|
0,
|
|
DriveLayoutInformation,
|
|
BufferSize,
|
|
FALSE,
|
|
PtrEvent,
|
|
&Iosb );
|
|
|
|
if ( Irp == NULL )
|
|
{
|
|
DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [FS Ctrl]", PtrEvent);
|
|
ExFreePool( PtrEvent );
|
|
return 0;
|
|
}
|
|
|
|
Status = IoCallDriver( TargetDeviceObject, Irp );
|
|
|
|
if ( Status == STATUS_PENDING ) {
|
|
|
|
(VOID) KeWaitForSingleObject( PtrEvent,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
(PLARGE_INTEGER)NULL );
|
|
|
|
Status = Iosb.Status;
|
|
}
|
|
DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [FS Ctrl]", PtrEvent);
|
|
ExFreePool( PtrEvent );
|
|
return Status;
|
|
}
|
|
|
|
|
|
/*************************************************************************
|
|
*
|
|
* Function: Ext2MountVolume()
|
|
*
|
|
* Description:
|
|
* This routine is used for performing a verify read...
|
|
*
|
|
* Expected Interrupt Level (for execution) :
|
|
* IRQL_PASSIVE_LEVEL
|
|
*
|
|
* Arguments:
|
|
* TargetDeviceObject - The target of the query
|
|
* PartitionInformation - Receives the result of the query
|
|
*
|
|
* Return Value:
|
|
* NTSTATUS - The return status for the operation
|
|
*
|
|
*************************************************************************/
|
|
BOOLEAN Ext2PerformVerifyDiskRead(
|
|
IN PDEVICE_OBJECT TargetDeviceObject,
|
|
IN PVOID Buffer,
|
|
IN LONGLONG Lbo,
|
|
IN ULONG NumberOfBytesToRead )
|
|
{
|
|
KEVENT Event;
|
|
PIRP Irp;
|
|
LARGE_INTEGER ByteOffset;
|
|
NTSTATUS Status;
|
|
IO_STATUS_BLOCK Iosb;
|
|
|
|
//
|
|
// Initialize the event we're going to use
|
|
//
|
|
KeInitializeEvent( &Event, NotificationEvent, FALSE );
|
|
|
|
//
|
|
// Build the irp for the operation
|
|
//
|
|
ByteOffset.QuadPart = Lbo;
|
|
Irp = IoBuildSynchronousFsdRequest( IRP_MJ_READ,
|
|
TargetDeviceObject,
|
|
Buffer,
|
|
NumberOfBytesToRead,
|
|
&ByteOffset,
|
|
&Event,
|
|
&Iosb );
|
|
|
|
if ( Irp == NULL )
|
|
{
|
|
Status = FALSE;
|
|
}
|
|
|
|
Ext2SetFlag( IoGetNextIrpStackLocation( Irp )->Flags, SL_OVERRIDE_VERIFY_VOLUME );
|
|
|
|
//
|
|
// Call the device to do the read and wait for it to finish.
|
|
//
|
|
Status = IoCallDriver( TargetDeviceObject, Irp );
|
|
if (Status == STATUS_PENDING)
|
|
{
|
|
(VOID)KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, (PLARGE_INTEGER)NULL );
|
|
Status = Iosb.Status;
|
|
}
|
|
|
|
ASSERT(Status != STATUS_VERIFY_REQUIRED);
|
|
|
|
//
|
|
// Special case this error code because this probably means we used
|
|
// the wrong sector size and we want to reject STATUS_WRONG_VOLUME.
|
|
//
|
|
|
|
if (Status == STATUS_INVALID_PARAMETER)
|
|
{
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// If it doesn't succeed then either return or raise the error.
|
|
//
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// And return to our caller
|
|
//
|
|
return TRUE;
|
|
}
|
|
|
|
/*************************************************************************
|
|
*
|
|
* Function: Ext2UserFileSystemRequest()
|
|
*
|
|
* Description:
|
|
* This routine handles User File System Requests
|
|
*
|
|
* Expected Interrupt Level (for execution) :
|
|
*
|
|
* IRQL_PASSIVE_LEVEL
|
|
*
|
|
*
|
|
* Arguments:
|
|
*
|
|
* Irp - Supplies the Irp being processed
|
|
* IrpSp - Irp Stack Location pointer
|
|
*
|
|
* Return Value: NT_STATUS
|
|
*
|
|
*************************************************************************/
|
|
NTSTATUS Ext2UserFileSystemRequest (
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp )
|
|
{
|
|
NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
ULONG FsControlCode;
|
|
|
|
IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
|
|
|
try
|
|
{
|
|
#ifdef _GNU_NTIFS_
|
|
FsControlCode = ((PEXTENDED_IO_STACK_LOCATION)IrpSp)->Parameters.FileSystemControl.FsControlCode;
|
|
#else
|
|
FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
|
|
#endif
|
|
|
|
switch ( FsControlCode )
|
|
{
|
|
|
|
case FSCTL_REQUEST_OPLOCK_LEVEL_1:
|
|
DebugTrace(DEBUG_TRACE_FSCTRL, "FSCTL_REQUEST_OPLOCK_LEVEL_1", 0);
|
|
break;
|
|
case FSCTL_REQUEST_OPLOCK_LEVEL_2:
|
|
DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL ", 0);
|
|
break;
|
|
case FSCTL_REQUEST_BATCH_OPLOCK:
|
|
DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_REQUEST_OPLOCK_LEVEL_2 ", 0);
|
|
break;
|
|
case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:
|
|
DebugTrace(DEBUG_TRACE_MISC, " FSCTL_OPLOCK_BREAK_ACKNOWLEDGE ", 0);
|
|
break;
|
|
case FSCTL_OPBATCH_ACK_CLOSE_PENDING:
|
|
DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_OPBATCH_ACK_CLOSE_PENDING ", 0);
|
|
break;
|
|
case FSCTL_OPLOCK_BREAK_NOTIFY:
|
|
DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_OPLOCK_BREAK_NOTIFY ", 0);
|
|
break;
|
|
case FSCTL_OPLOCK_BREAK_ACK_NO_2:
|
|
DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_OPLOCK_BREAK_ACK_NO_2 ", 0);
|
|
break;
|
|
case FSCTL_LOCK_VOLUME:
|
|
DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_LOCK_VOLUME ", 0);
|
|
break;
|
|
case FSCTL_UNLOCK_VOLUME:
|
|
DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_UNLOCK_VOLUME ", 0);
|
|
break;
|
|
case FSCTL_DISMOUNT_VOLUME:
|
|
DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_DISMOUNT_VOLUME ", 0);
|
|
break;
|
|
case FSCTL_MARK_VOLUME_DIRTY:
|
|
DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_MARK_VOLUME_DIRTY ", 0);
|
|
break;
|
|
case FSCTL_IS_VOLUME_DIRTY:
|
|
DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_IS_VOLUME_DIRTY ", 0);
|
|
break;
|
|
case FSCTL_IS_VOLUME_MOUNTED:
|
|
Status = Ext2VerifyVolume(Irp, IrpSp );
|
|
DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_IS_VOLUME_MOUNTED ", 0);
|
|
break;
|
|
case FSCTL_IS_PATHNAME_VALID:
|
|
DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_IS_PATHNAME_VALID ", 0);
|
|
break;
|
|
case FSCTL_QUERY_RETRIEVAL_POINTERS:
|
|
DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_QUERY_RETRIEVAL_POINTERS ", 0);
|
|
break;
|
|
case FSCTL_QUERY_FAT_BPB:
|
|
DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_QUERY_FAT_BPB ", 0);
|
|
break;
|
|
case FSCTL_FILESYSTEM_GET_STATISTICS:
|
|
DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_FILESYSTEM_GET_STATISTICS ", 0);
|
|
break;
|
|
case FSCTL_GET_VOLUME_BITMAP:
|
|
DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_GET_VOLUME_BITMAP ", 0);
|
|
break;
|
|
case FSCTL_GET_RETRIEVAL_POINTERS:
|
|
DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_GET_RETRIEVAL_POINTERS ", 0);
|
|
break;
|
|
case FSCTL_MOVE_FILE:
|
|
DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_MOVE_FILE ", 0);
|
|
break;
|
|
case FSCTL_ALLOW_EXTENDED_DASD_IO:
|
|
DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_ALLOW_EXTENDED_DASD_IO ", 0);
|
|
break;
|
|
default :
|
|
DebugTrace(DEBUG_TRACE_FSCTRL, "Unknown FSCTRL !!!", 0);
|
|
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS NTAPI Ext2VerifyVolume (
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp )
|
|
{
|
|
|
|
PVPB PtrVPB;
|
|
|
|
PtrVPB = IrpSp->Parameters.VerifyVolume.Vpb;
|
|
if( IrpSp->FileObject )
|
|
{
|
|
PtrVPB = IrpSp->FileObject->Vpb;
|
|
}
|
|
if( !PtrVPB )
|
|
{
|
|
PtrVPB = IrpSp->Parameters.VerifyVolume.Vpb;
|
|
}
|
|
|
|
if( !PtrVPB )
|
|
{
|
|
return STATUS_WRONG_VOLUME;
|
|
}
|
|
|
|
|
|
if ( Ext2IsFlagOn( PtrVPB->RealDevice->Flags, DO_VERIFY_VOLUME ) )
|
|
{
|
|
//
|
|
// Not doing a verify!
|
|
// Just acting as if everyting is fine!
|
|
// THis should do for now
|
|
//
|
|
Ext2ClearFlag( PtrVPB->RealDevice->Flags, DO_VERIFY_VOLUME );
|
|
|
|
}
|
|
return STATUS_SUCCESS;
|
|
}
|