/************************************************************************* * * 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; }
NTSTATUS Ext2ReadDisk( IN PEXT2_VCB Vcb, IN ULONGLONG Offset, IN ULONG Size, IN PVOID Buffer, IN BOOLEAN bVerify ) { NTSTATUS Status; PUCHAR Buf; ULONG Length; ULONGLONG Lba; Lba = Offset & (~((ULONGLONG)SECTOR_SIZE - 1)); Length = (ULONG)(Size + Offset + SECTOR_SIZE - 1 - Lba) & (~((ULONG)SECTOR_SIZE - 1)); Buf = Ext2AllocatePool(PagedPool, Length, EXT2_DATA_MAGIC); if (!Buf) { DEBUG(DL_ERR, ( "Ext2ReadDisk: failed to allocate Buffer.\n")); Status = STATUS_INSUFFICIENT_RESOURCES; goto errorout; } INC_MEM_COUNT(PS_DISK_BUFFER, Buf, Length); Status = Ext2ReadSync( Vcb, Lba, Length, Buf, FALSE ); if (!NT_SUCCESS(Status)) { DEBUG(DL_ERR, ( "Ext2ReadDisk: disk device error.\n")); goto errorout; } RtlCopyMemory(Buffer, &Buf[Offset - Lba], Size); errorout: if (Buf) { Ext2FreePool(Buf, EXT2_DATA_MAGIC); DEC_MEM_COUNT(PS_DISK_BUFFER, Buf, Length); } return Status; }
VOID Ext2StartFloppyFlushDpc ( PEXT2_VCB Vcb, PEXT2_FCB Fcb, PFILE_OBJECT FileObject ) { LARGE_INTEGER OneSecond; PEXT2_FLPFLUSH_CONTEXT Context; ASSERT(IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK)); Context = Ext2AllocatePool( NonPagedPool, sizeof(EXT2_FLPFLUSH_CONTEXT), EXT2_FLPFLUSH_MAGIC ); if (!Context) { DEBUG(DL_ERR, ( "Ex2StartFloppy...: failed to allocate Context\n")); DbgBreak(); return; } KeInitializeTimer(&Context->Timer); KeInitializeDpc( &Context->Dpc, Ext2FloppyFlushDpc, Context ); ExInitializeWorkItem( &Context->Item, Ext2FloppyFlush, Context ); Context->Vcb = Vcb; Context->Fcb = Fcb; Context->FileObject = FileObject; if (FileObject) { ObReferenceObject(FileObject); } OneSecond.QuadPart = (LONGLONG)-1*1000*1000*10; KeSetTimer( &Context->Timer, OneSecond, &Context->Dpc ); }
/************************************************************************* * * 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; }
/* * NAME: DriverEntry * FUNCTION: Called by the system to initalize the driver * * ARGUMENTS: * DriverObject = object describing this driver * RegistryPath = path to our configuration entries * RETURNS: Success or failure */ NTSTATUS DriverEntry ( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ) { PDEVICE_OBJECT DiskdevObject = NULL; PDEVICE_OBJECT CdromdevObject = NULL; UNICODE_STRING DeviceName; UNICODE_STRING DosDeviceName; PFAST_IO_DISPATCH FastIoDispatch; PCACHE_MANAGER_CALLBACKS CacheManagerCallbacks; NTSTATUS Status; int rc = 0; BOOLEAN linux_lib_inited = FALSE; BOOLEAN journal_module_inited = FALSE; /* Verity super block ... */ ASSERT(sizeof(EXT2_SUPER_BLOCK) == 1024); ASSERT(FIELD_OFFSET(EXT2_SUPER_BLOCK, s_magic) == 56); DbgPrint( "Ext2Fsd --" #ifdef _WIN2K_TARGET_ " Win2k --" #endif " Version " EXT2FSD_VERSION #if EXT2_DEBUG " Checked" #else " Free" #endif " -- " __DATE__ " " __TIME__ ".\n"); DEBUG(DL_FUN, ( "Ext2 DriverEntry ...\n")); /* initialize winlib structures */ if (ext2_init_linux()) { Status = STATUS_INSUFFICIENT_RESOURCES; goto errorout; } linux_lib_inited = TRUE; /* initialize journal module structures */ LOAD_MODULE(journal_init); if (rc != 0) { Status = STATUS_INSUFFICIENT_RESOURCES; goto errorout; } journal_module_inited = TRUE; /* allocate memory for Ext2Global */ Ext2Global = Ext2AllocatePool(NonPagedPool, sizeof(EXT2_GLOBAL), 'LG2E'); if (!Ext2Global) { Status = STATUS_INSUFFICIENT_RESOURCES; goto errorout; } /* initialize Ext2Global */ RtlZeroMemory(Ext2Global, sizeof(EXT2_GLOBAL)); Ext2Global->Identifier.Type = EXT2FGD; Ext2Global->Identifier.Size = sizeof(EXT2_GLOBAL); InitializeListHead(&(Ext2Global->VcbList)); ExInitializeResourceLite(&(Ext2Global->Resource)); /* query registry settings */ Ext2QueryRegistrySettings(RegistryPath); /* create Ext2Fsd cdrom fs deivce */ RtlInitUnicodeString(&DeviceName, CDROM_NAME); Status = IoCreateDevice( DriverObject, 0, &DeviceName, FILE_DEVICE_CD_ROM_FILE_SYSTEM, 0, FALSE, &CdromdevObject ); if (!NT_SUCCESS(Status)) { DEBUG(DL_ERR, ( "IoCreateDevice cdrom device object error.\n")); goto errorout; } /* create Ext2Fsd disk fs deivce */ RtlInitUnicodeString(&DeviceName, DEVICE_NAME); Status = IoCreateDevice( DriverObject, 0, &DeviceName, FILE_DEVICE_DISK_FILE_SYSTEM, 0, FALSE, &DiskdevObject ); if (!NT_SUCCESS(Status)) { DEBUG(DL_ERR, ( "IoCreateDevice disk device object error.\n")); goto errorout; } Status= Ext2StartReaper( &Ext2Global->FcbReaper, Ext2FcbReaperThread); if (!NT_SUCCESS(Status)) { goto errorout; } /* start resource reaper thread */ Status= Ext2StartReaper( &Ext2Global->McbReaper, Ext2McbReaperThread); if (!NT_SUCCESS(Status)) { Ext2StopReaper(&Ext2Global->FcbReaper); goto errorout; } Status= Ext2StartReaper( &Ext2Global->bhReaper, Ext2bhReaperThread); if (!NT_SUCCESS(Status)) { Ext2StopReaper(&Ext2Global->FcbReaper); Ext2StopReaper(&Ext2Global->McbReaper); goto errorout; } /* initializing */ Ext2Global->DiskdevObject = DiskdevObject; Ext2Global->CdromdevObject = CdromdevObject; DriverObject->MajorFunction[IRP_MJ_CREATE] = Ext2BuildRequest; DriverObject->MajorFunction[IRP_MJ_CLOSE] = Ext2BuildRequest; DriverObject->MajorFunction[IRP_MJ_READ] = Ext2BuildRequest; DriverObject->MajorFunction[IRP_MJ_WRITE] = Ext2BuildRequest; DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = Ext2BuildRequest; DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = Ext2BuildRequest; DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] = Ext2BuildRequest; DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] = Ext2BuildRequest; DriverObject->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] = Ext2BuildRequest; DriverObject->MajorFunction[IRP_MJ_SET_VOLUME_INFORMATION] = Ext2BuildRequest; DriverObject->MajorFunction[IRP_MJ_DIRECTORY_CONTROL] = Ext2BuildRequest; DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = Ext2BuildRequest; DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = Ext2BuildRequest; DriverObject->MajorFunction[IRP_MJ_LOCK_CONTROL] = Ext2BuildRequest; DriverObject->MajorFunction[IRP_MJ_CLEANUP] = Ext2BuildRequest; #if (_WIN32_WINNT >= 0x0500) DriverObject->MajorFunction[IRP_MJ_PNP] = Ext2BuildRequest; #endif //(_WIN32_WINNT >= 0x0500) #if EXT2_UNLOAD DriverObject->DriverUnload = DriverUnload; #else DriverObject->DriverUnload = NULL; #endif // // Initialize the fast I/O entry points // FastIoDispatch = &(Ext2Global->FastIoDispatch); FastIoDispatch->SizeOfFastIoDispatch = sizeof(FAST_IO_DISPATCH); FastIoDispatch->FastIoCheckIfPossible = Ext2FastIoCheckIfPossible; FastIoDispatch->FastIoRead = Ext2FastIoRead; FastIoDispatch->FastIoWrite = Ext2FastIoWrite; FastIoDispatch->FastIoQueryBasicInfo = Ext2FastIoQueryBasicInfo; FastIoDispatch->FastIoQueryStandardInfo = Ext2FastIoQueryStandardInfo; FastIoDispatch->FastIoLock = Ext2FastIoLock; FastIoDispatch->FastIoUnlockSingle = Ext2FastIoUnlockSingle; FastIoDispatch->FastIoUnlockAll = Ext2FastIoUnlockAll; FastIoDispatch->FastIoUnlockAllByKey = Ext2FastIoUnlockAllByKey; FastIoDispatch->FastIoQueryNetworkOpenInfo = Ext2FastIoQueryNetworkOpenInfo; FastIoDispatch->AcquireForModWrite = Ext2AcquireFileForModWrite; FastIoDispatch->ReleaseForModWrite = Ext2ReleaseFileForModWrite; FastIoDispatch->AcquireForModWrite = Ext2AcquireFileForModWrite; FastIoDispatch->ReleaseForModWrite = Ext2ReleaseFileForModWrite; FastIoDispatch->AcquireForCcFlush = Ext2AcquireFileForCcFlush; FastIoDispatch->ReleaseForCcFlush = Ext2ReleaseFileForCcFlush; FastIoDispatch->AcquireFileForNtCreateSection = Ext2AcquireForCreateSection; FastIoDispatch->ReleaseFileForNtCreateSection = Ext2ReleaseForCreateSection; DriverObject->FastIoDispatch = FastIoDispatch; // // initializing structure sizes for statistics // 1 means flexible/not fixed for all allocations (for different volumes). // Ext2Global->PerfStat.Magic = EXT2_PERF_STAT_MAGIC; Ext2Global->PerfStat.Version = EXT2_PERF_STAT_VER2; Ext2Global->PerfStat.Length = sizeof(EXT2_PERF_STATISTICS_V2); Ext2Global->PerfStat.Unit.Slot[PS_IRP_CONTEXT] = sizeof(EXT2_IRP_CONTEXT); /* 0 */ Ext2Global->PerfStat.Unit.Slot[PS_VCB] = sizeof(EXT2_VCB); /* 1 */ Ext2Global->PerfStat.Unit.Slot[PS_FCB] = sizeof(EXT2_FCB); /* 2 */ Ext2Global->PerfStat.Unit.Slot[PS_CCB] = sizeof(EXT2_CCB); /* 3 */ Ext2Global->PerfStat.Unit.Slot[PS_MCB] = sizeof(EXT2_MCB); /* 4 */ Ext2Global->PerfStat.Unit.Slot[PS_EXTENT] = sizeof(EXT2_EXTENT); /* 5 */ Ext2Global->PerfStat.Unit.Slot[PS_RW_CONTEXT] = sizeof(EXT2_RW_CONTEXT); /* 6 */ Ext2Global->PerfStat.Unit.Slot[PS_VPB] = sizeof(VPB); /* 7 */ Ext2Global->PerfStat.Unit.Slot[PS_FILE_NAME] = 1; /* 8 */ Ext2Global->PerfStat.Unit.Slot[PS_MCB_NAME] = 1; /* 9 */ Ext2Global->PerfStat.Unit.Slot[PS_INODE_NAME] = 1; /* a */ Ext2Global->PerfStat.Unit.Slot[PS_DIR_ENTRY] = sizeof(EXT2_DIR_ENTRY2); /* b */ Ext2Global->PerfStat.Unit.Slot[PS_DIR_PATTERN] = 1; /* c */ Ext2Global->PerfStat.Unit.Slot[PS_DISK_EVENT] = sizeof(KEVENT); /* d */ Ext2Global->PerfStat.Unit.Slot[PS_DISK_BUFFER] = 1; /* e */ Ext2Global->PerfStat.Unit.Slot[PS_BLOCK_DATA] = 1; /* f */ Ext2Global->PerfStat.Unit.Slot[PS_EXT2_INODE] = 1; /* 10 */ Ext2Global->PerfStat.Unit.Slot[PS_DENTRY] = sizeof(struct dentry); /* 11 */ Ext2Global->PerfStat.Unit.Slot[PS_BUFF_HEAD] = sizeof(struct buffer_head); /* 12 */ switch ( MmQuerySystemSize() ) { case MmSmallSystem: Ext2Global->MaxDepth = 64; break; case MmMediumSystem: Ext2Global->MaxDepth = 128; break; case MmLargeSystem: Ext2Global->MaxDepth = 256; break; } // // Initialize the Cache Manager callbacks // CacheManagerCallbacks = &(Ext2Global->CacheManagerCallbacks); CacheManagerCallbacks->AcquireForLazyWrite = Ext2AcquireForLazyWrite; CacheManagerCallbacks->ReleaseFromLazyWrite = Ext2ReleaseFromLazyWrite; CacheManagerCallbacks->AcquireForReadAhead = Ext2AcquireForReadAhead; CacheManagerCallbacks->ReleaseFromReadAhead = Ext2ReleaseFromReadAhead; Ext2Global->CacheManagerNoOpCallbacks.AcquireForLazyWrite = Ext2NoOpAcquire; Ext2Global->CacheManagerNoOpCallbacks.ReleaseFromLazyWrite = Ext2NoOpRelease; Ext2Global->CacheManagerNoOpCallbacks.AcquireForReadAhead = Ext2NoOpAcquire; Ext2Global->CacheManagerNoOpCallbacks.ReleaseFromReadAhead = Ext2NoOpRelease; #ifndef _WIN2K_TARGET_ // // Initialize FS Filter callbacks // RtlZeroMemory(&Ext2Global->FilterCallbacks, sizeof(FS_FILTER_CALLBACKS)); Ext2Global->FilterCallbacks.SizeOfFsFilterCallbacks = sizeof(FS_FILTER_CALLBACKS); Ext2Global->FilterCallbacks.PreAcquireForSectionSynchronization = Ext2PreAcquireForCreateSection; FsRtlRegisterFileSystemFilterCallbacks(DriverObject, &Ext2Global->FilterCallbacks ); #endif // // Initialize the global data // ExInitializeNPagedLookasideList( &(Ext2Global->Ext2IrpContextLookasideList), NULL, NULL, 0, sizeof(EXT2_IRP_CONTEXT), 'PRIE', 0 ); ExInitializeNPagedLookasideList( &(Ext2Global->Ext2FcbLookasideList), NULL, NULL, 0, sizeof(EXT2_FCB), 'BCFE', 0 ); ExInitializeNPagedLookasideList( &(Ext2Global->Ext2CcbLookasideList), NULL, NULL, 0, sizeof(EXT2_CCB), 'BCCE', 0 ); ExInitializeNPagedLookasideList( &(Ext2Global->Ext2McbLookasideList), NULL, NULL, 0, sizeof(EXT2_MCB), 'BCME', 0 ); ExInitializeNPagedLookasideList( &(Ext2Global->Ext2ExtLookasideList), NULL, NULL, 0, sizeof(EXT2_EXTENT), 'STXE', 0 ); ExInitializeNPagedLookasideList( &(Ext2Global->Ext2DentryLookasideList), NULL, NULL, 0, sizeof(struct dentry), 'TNED', 0 ); RtlInitUnicodeString(&DosDeviceName, DOS_DEVICE_NAME); IoCreateSymbolicLink(&DosDeviceName, &DeviceName); #if EXT2_DEBUG ProcessNameOffset = Ext2GetProcessNameOffset(); #endif Ext2LoadAllNls(); Ext2Global->Codepage.PageTable = load_nls(Ext2Global->Codepage.AnsiName); /* register file system devices for disk and cdrom */ IoRegisterFileSystem(DiskdevObject); ObReferenceObject(DiskdevObject); IoRegisterFileSystem(CdromdevObject); ObReferenceObject(CdromdevObject); errorout: if (!NT_SUCCESS(Status)) { /* * stop reaper thread ... */ /* * cleanup resources ... */ if (Ext2Global) { ExDeleteResourceLite(&Ext2Global->Resource); Ext2FreePool(Ext2Global, 'LG2E'); } if (CdromdevObject) { IoDeleteDevice(CdromdevObject); } if (DiskdevObject) { IoDeleteDevice(DiskdevObject); } if (journal_module_inited) { /* cleanup journal related caches */ UNLOAD_MODULE(journal_exit); } if (linux_lib_inited) { /* cleanup linux lib */ ext2_destroy_linux(); } } return Status; }
BOOLEAN Ext2QueryRegistrySettings(IN PUNICODE_STRING RegistryPath) { UNICODE_STRING ParameterPath; UNICODE_STRING UniName; ANSI_STRING AnsiName; ULONG WritingSupport = 0; ULONG CheckingBitmap = 0; ULONG Ext3ForceWriting = 0; ULONG AutoMount = 0; WCHAR UniBuffer[CODEPAGE_MAXLEN]; USHORT Buffer[HIDINGPAT_LEN]; NTSTATUS Status; ParameterPath.Length = 0; ParameterPath.MaximumLength = RegistryPath->Length + sizeof(PARAMETERS_KEY) + sizeof(WCHAR); ParameterPath.Buffer = (PWSTR) Ext2AllocatePool( PagedPool, ParameterPath.MaximumLength, 'LG2E' ); if (!ParameterPath.Buffer) { DbgBreak(); DEBUG(DL_ERR, ( "Ex2QueryParameters: failed to allocate Parameters...\n")); return FALSE; } RtlCopyUnicodeString(&ParameterPath, RegistryPath); RtlAppendUnicodeToString(&ParameterPath, PARAMETERS_KEY); /* enable automount of ext2/3/4 volumes */ SetLongFlag(Ext2Global->Flags, EXT2_AUTO_MOUNT); /* query parameter settings from registry */ Ext2QueryGlobalParameters(&ParameterPath); /* set global codepage settings */ if (wcslen(&Ext2Global->Codepage.PageName[0])) { UniName.Length = sizeof(WCHAR) * wcslen(&Ext2Global->Codepage.PageName[0]); UniName.MaximumLength = CODEPAGE_MAXLEN * sizeof(WCHAR); UniName.Buffer = &Ext2Global->Codepage.PageName[0]; AnsiName.MaximumLength = CODEPAGE_MAXLEN; AnsiName.Length = 0; AnsiName.Buffer = &Ext2Global->Codepage.AnsiName[0]; Status = RtlUnicodeStringToAnsiString( &AnsiName, &UniName, FALSE); if (!NT_SUCCESS(Status)) { DEBUG(DL_ERR, ( "Ext2QueryParameters: Wrong CodePage %wZ ...\n", &UniName)); RtlCopyMemory(&(Ext2Global->Codepage.AnsiName[0]),"default\0", 8); } } else { DEBUG(DL_ERR, ( "Ext2QueryParameters: CodePage not specified.\n")); RtlCopyMemory(&(Ext2Global->Codepage.AnsiName[0]),"default\0", 8); } Ext2Global->Codepage.AnsiName[CODEPAGE_MAXLEN - 1] = 0; /* set global hidden prefix pattern */ if (wcslen(&Ext2Global->wHidingPrefix[0])) { UniName.Length = sizeof(WCHAR) * wcslen(&Ext2Global->wHidingPrefix[0]); UniName.MaximumLength = HIDINGPAT_LEN * sizeof(WCHAR); UniName.Buffer = &Ext2Global->wHidingPrefix[0]; AnsiName.MaximumLength = HIDINGPAT_LEN; AnsiName.Length = 0; AnsiName.Buffer = &(Ext2Global->sHidingPrefix[0]); Status = RtlUnicodeStringToAnsiString( &AnsiName, &UniName, FALSE); if (NT_SUCCESS(Status)) { Ext2Global->bHidingPrefix = TRUE; } else { DEBUG(DL_ERR, ( "Ext2QueryParameters: Wrong HidingPrefix ...\n")); } } else { DEBUG(DL_ERR, ( "Ext2QueryParameters: HidingPrefix not specified.\n")); } Ext2Global->sHidingPrefix[HIDINGPAT_LEN - 1] = 0; /* set global hidden suffix pattern */ if (wcslen(&Ext2Global->wHidingSuffix[0])) { UniName.Length = sizeof(WCHAR) * wcslen(&Ext2Global->wHidingSuffix[0]); UniName.MaximumLength = HIDINGPAT_LEN * sizeof(WCHAR); UniName.Buffer = &Ext2Global->wHidingSuffix[0]; AnsiName.MaximumLength = HIDINGPAT_LEN; AnsiName.Length = 0; AnsiName.Buffer = &(Ext2Global->sHidingSuffix[0]); Status = RtlUnicodeStringToAnsiString( &AnsiName, &UniName, FALSE); if (NT_SUCCESS(Status)) { Ext2Global->bHidingSuffix = TRUE; } else { DEBUG(DL_ERR, ( "Ext2QueryParameters: Wrong HidingSuffix ...\n")); } } else { DEBUG(DL_ERR, ( "Ext2QueryParameters: HidingSuffix not specified.\n")); } Ext2Global->sHidingPrefix[HIDINGPAT_LEN - 1] = 0; Ext2Global->RegistryPath.Buffer = ParameterPath.Buffer; Ext2Global->RegistryPath.Length = 0; Ext2Global->RegistryPath.MaximumLength = ParameterPath.MaximumLength; RtlCopyUnicodeString(&Ext2Global->RegistryPath, RegistryPath); RtlAppendUnicodeToString(&Ext2Global->RegistryPath, VOLUMES_KEY); return TRUE; }
/************************************************************************* * * Function: Ext2PassDownMultiReadWriteIRP() * * Description: * pass down multiple read IRPs as Associated IRPs * * Expected Interrupt Level (for execution) : * * ? * * Return Value: STATUS_SUCCESS / STATUS_PENDING / Error * *************************************************************************/ NTSTATUS NTAPI Ext2PassDownMultiReadWriteIRP( PEXT2_IO_RUN PtrIoRuns, UINT Count, ULONG TotalReadWriteLength, PtrExt2IrpContext PtrIrpContext, PtrExt2FCB PtrFCB, BOOLEAN SynchronousIo) { PIRP PtrMasterIrp; PIRP PtrAssociatedIrp; PIO_STACK_LOCATION PtrIrpSp; PMDL PtrMdl; PtrExt2VCB PtrVCB; UINT i; ULONG BufferOffset; PEXT2_IO_CONTEXT PtrIoContext = NULL; PKEVENT PtrSyncEvent = NULL; ULONG LogicalBlockSize; ULONG ReadWriteLength; NTSTATUS RC = STATUS_SUCCESS; PtrVCB = PtrFCB->PtrVCB; PtrMasterIrp = PtrIrpContext->Irp; LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; try { if( !SynchronousIo ) { IoMarkIrpPending( PtrIrpContext->Irp ); // We will be returning STATUS_PENDING... } if( !PtrMasterIrp->MdlAddress ) { Ext2LockCallersBuffer( PtrMasterIrp, TRUE, TotalReadWriteLength ); } if( SynchronousIo ) { PtrSyncEvent = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( sizeof(KEVENT) ) ); if ( !PtrSyncEvent ) { RC = STATUS_INSUFFICIENT_RESOURCES; try_return(); } KeInitializeEvent( PtrSyncEvent, SynchronizationEvent, FALSE ); } // // Allocate and initialize a completion context // PtrIoContext = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( sizeof(EXT2_IO_CONTEXT) ) ); if ( !PtrIoContext ) { RC = STATUS_INSUFFICIENT_RESOURCES; try_return(); } RtlZeroMemory( PtrIoContext, sizeof(EXT2_IO_CONTEXT) ); PtrIoContext->Count = Count; PtrIoContext->NodeIdentifier.NodeType = EXT2_NODE_TYPE_IO_CONTEXT; PtrIoContext->NodeIdentifier.NodeSize = sizeof( EXT2_IO_CONTEXT ); PtrIoContext->PtrMasterIrp = PtrMasterIrp; PtrIoContext->PtrSyncEvent = PtrSyncEvent; PtrIoContext->ReadWriteLength = TotalReadWriteLength; for( ReadWriteLength = 0, BufferOffset = 0, i = 0; i < Count; i++, BufferOffset += ReadWriteLength ) { ReadWriteLength = PtrIoRuns[ i].EndOffset - PtrIoRuns[ i].StartOffset; // // Allocating an Associated IRP... // PtrAssociatedIrp = IoMakeAssociatedIrp( PtrMasterIrp, (CCHAR) (PtrVCB->TargetDeviceObject->StackSize + 1 ) ); PtrIoRuns[ i].PtrAssociatedIrp = PtrAssociatedIrp; ASSERT ( PtrAssociatedIrp ); PtrMasterIrp->AssociatedIrp.IrpCount ++; // // Allocating a Memory Descriptor List... // PtrMdl = IoAllocateMdl( (PCHAR) PtrMasterIrp->UserBuffer + BufferOffset, // Virtual Address ReadWriteLength, FALSE, FALSE, PtrAssociatedIrp ); // // and building a partial MDL... // IoBuildPartialMdl( PtrMasterIrp->MdlAddress, PtrMdl, (PCHAR)PtrMasterIrp->UserBuffer + BufferOffset, ReadWriteLength ); // // Create an Irp stack location for ourselves... // IoSetNextIrpStackLocation( PtrAssociatedIrp ); PtrIrpSp = IoGetCurrentIrpStackLocation( PtrAssociatedIrp ); // // Setup the Stack location to describe our read. // PtrIrpSp->MajorFunction = PtrIrpContext->MajorFunction; if( PtrIrpContext->MajorFunction == IRP_MJ_READ ) { PtrIrpSp->Parameters.Read.Length = ReadWriteLength; PtrIrpSp->Parameters.Read.ByteOffset.QuadPart = PtrIoRuns[i].LogicalBlock * ( LogicalBlockSize ); } else if( PtrIrpContext->MajorFunction == IRP_MJ_WRITE ) { PtrIrpSp->Parameters.Write.Length = ReadWriteLength; PtrIrpSp->Parameters.Write.ByteOffset.QuadPart = PtrIoRuns[i].LogicalBlock * ( LogicalBlockSize ); } // PtrIrpSp->Parameters.Read.Length = ReadWriteLength; // PtrIrpSp->Parameters.Read.ByteOffset.QuadPart = PtrIoRuns[i].LogicalBlock; // // Setup a completion routine... // IoSetCompletionRoutine( PtrAssociatedIrp, SynchronousIo ? Ext2MultiSyncCompletionRoutine : Ext2MultiAsyncCompletionRoutine, PtrIoContext, TRUE, TRUE, TRUE ); // // Initialise the next stack location for the driver below us to use... // PtrIrpSp = IoGetNextIrpStackLocation( PtrAssociatedIrp ); PtrIrpSp->MajorFunction = PtrIrpContext->MajorFunction; if( PtrIrpContext->MajorFunction == IRP_MJ_READ ) { PtrIrpSp->Parameters.Read.Length = ReadWriteLength; PtrIrpSp->Parameters.Read.ByteOffset.QuadPart = PtrIoRuns[i].LogicalBlock * ( LogicalBlockSize ); } else if( PtrIrpContext->MajorFunction == IRP_MJ_WRITE ) { PtrIrpSp->Parameters.Write.Length = ReadWriteLength; PtrIrpSp->Parameters.Write.ByteOffset.QuadPart = PtrIoRuns[i].LogicalBlock * ( LogicalBlockSize ); } // PtrIrpSp->Parameters.Read.Length = ReadWriteLength; // PtrIrpSp->Parameters.Read.ByteOffset.QuadPart = // PtrIoRuns[i].LogicalBlock * ( LogicalBlockSize ); } for( i = 0; i < Count; i++ ) { // DbgPrint("PASSING DOWN IRP %d TO TARGET DEVICE\n", i); IoCallDriver( PtrVCB->TargetDeviceObject, PtrIoRuns[ i].PtrAssociatedIrp ); } if( SynchronousIo ) { // // Synchronous IO // Wait for the IO to complete... // DbgPrint("DEADLY WAIT (%d)\n", KeGetCurrentIrql()); KeWaitForSingleObject( PtrSyncEvent, Executive, KernelMode, FALSE, (PLARGE_INTEGER)NULL ); DbgPrint("DEADLY WAIT DONE\n"); try_return(); } else { // Asynchronous IO... RC = STATUS_PENDING; try_return(); } try_exit: NOTHING; } finally { if( PtrSyncEvent ) { DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [io]", PtrSyncEvent ); ExFreePool( PtrSyncEvent ); } if( PtrIoContext && ! ( RC == STATUS_PENDING || RC == STATUS_SUCCESS ) ) { // // This means we are getting out of // this function without doing a read // due to an error, maybe... // DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [io]", PtrIoContext); ExFreePool( PtrIoContext ); } } return(RC); }
NTSTATUS NTAPI Ext2PassDownSingleReadWriteIRP( PtrExt2IrpContext PtrIrpContext, PIRP PtrIrp, PtrExt2VCB PtrVCB, LARGE_INTEGER ByteOffset, uint32 ReadWriteLength, BOOLEAN SynchronousIo) { NTSTATUS RC = STATUS_SUCCESS; PEXT2_IO_CONTEXT PtrIoContext = NULL; PKEVENT PtrSyncEvent = NULL; PIO_STACK_LOCATION PtrIrpNextSp = NULL; try { if( !PtrIrp->MdlAddress ) { Ext2LockCallersBuffer( PtrIrp, TRUE, ReadWriteLength ); } if( SynchronousIo ) { PtrSyncEvent = Ext2AllocatePool( NonPagedPool, Ext2QuadAlign( sizeof(KEVENT) ) ); if ( !PtrSyncEvent ) { RC = STATUS_INSUFFICIENT_RESOURCES; try_return(); } KeInitializeEvent( PtrSyncEvent, SynchronizationEvent, FALSE ); } // // Allocate and initialize a completion context // PtrIoContext = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( sizeof(EXT2_IO_CONTEXT) ) ); if ( !PtrIoContext ) { RC = STATUS_INSUFFICIENT_RESOURCES; try_return(); } RtlZeroMemory( PtrIoContext, sizeof(EXT2_IO_CONTEXT) ); PtrIoContext->Count = 1; PtrIoContext->NodeIdentifier.NodeType = EXT2_NODE_TYPE_IO_CONTEXT; PtrIoContext->NodeIdentifier.NodeSize = sizeof( EXT2_IO_CONTEXT ); PtrIoContext->PtrMasterIrp = NULL; PtrIoContext->PtrSyncEvent = PtrSyncEvent; PtrIoContext->ReadWriteLength = ReadWriteLength; IoSetCompletionRoutine( PtrIrp, SynchronousIo ? Ext2SingleSyncCompletionRoutine: Ext2SingleAsyncCompletionRoutine, PtrIoContext, TRUE, TRUE, TRUE ); // // Setup the next IRP stack location in the associated Irp for the disk // driver beneath us. // PtrIrpNextSp = IoGetNextIrpStackLocation( PtrIrp ); // // Setup the Stack location to do a read from the disk driver. // PtrIrpNextSp->MajorFunction = PtrIrpContext->MajorFunction; if( PtrIrpContext->MajorFunction == IRP_MJ_READ ) { PtrIrpNextSp->Parameters.Read.Length = ReadWriteLength; PtrIrpNextSp->Parameters.Read.ByteOffset = ByteOffset; } else if( PtrIrpContext->MajorFunction == IRP_MJ_WRITE ) { PtrIrpNextSp->Parameters.Write.Length = ReadWriteLength; PtrIrpNextSp->Parameters.Write.ByteOffset = ByteOffset; } // // Issue the read / write request // RC = IoCallDriver(PtrVCB->TargetDeviceObject, PtrIrp); if( SynchronousIo ) { // // Wait for completion... // RC = KeWaitForSingleObject( &PtrIoContext->PtrSyncEvent, Executive, KernelMode, FALSE, (PLARGE_INTEGER)NULL ); RC = STATUS_SUCCESS; } else { RC = STATUS_PENDING; } try_exit: NOTHING; } finally { if( PtrSyncEvent ) { DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [io]", PtrSyncEvent ); ExFreePool( PtrSyncEvent ); } if( PtrIoContext && !( RC == STATUS_PENDING || RC == STATUS_SUCCESS ) ) { // // This means we are getting out of // this function without doing a read / write // due to an error, maybe... // DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [io]", PtrIoContext ); ExFreePool( PtrIoContext ); } } return RC; }
BOOLEAN Ext2QueryGlobalParameters( IN PUNICODE_STRING RegistryPath) { NTSTATUS Status; UNICODE_STRING ParameterPath; RTL_QUERY_REGISTRY_TABLE QueryTable[2]; ULONG WritingSupport = 0; ULONG CheckingBitmap = 0; ULONG Ext3ForceWriting = 0; ULONG AutoMount = 0; UNICODE_STRING UniName; ANSI_STRING AnsiName; WCHAR UniBuffer[CODEPAGE_MAXLEN]; USHORT Buffer[HIDINGPAT_LEN]; ParameterPath.Length = 0; ParameterPath.MaximumLength = RegistryPath->Length + sizeof(PARAMETERS_KEY) + sizeof(WCHAR); ParameterPath.Buffer = (PWSTR) Ext2AllocatePool( PagedPool, ParameterPath.MaximumLength, 'LG2E' ); if (!ParameterPath.Buffer) { DbgBreak(); DEBUG(DL_ERR, ( "Ex2QueryParameters: failed to allocate Parameters...\n")); return FALSE; } RtlCopyUnicodeString(&ParameterPath, RegistryPath); RtlAppendUnicodeToString(&ParameterPath, PARAMETERS_KEY); /* querying value of WritingSupport */ RtlZeroMemory(&QueryTable[0], sizeof(RTL_QUERY_REGISTRY_TABLE) * 2); QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED; QueryTable[0].Name = WRITING_SUPPORT; QueryTable[0].EntryContext = &WritingSupport; Status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE, ParameterPath.Buffer, &QueryTable[0], NULL, NULL ); DEBUG(DL_ERR, ( "Ext2QueryParameters: WritingSupport=%xh\n", WritingSupport)); /* querying value of CheckingBitmap */ RtlZeroMemory(&QueryTable[0], sizeof(RTL_QUERY_REGISTRY_TABLE) * 2); QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED; QueryTable[0].Name = CHECKING_BITMAP; QueryTable[0].EntryContext = &CheckingBitmap; Status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE, ParameterPath.Buffer, &QueryTable[0], NULL, NULL ); DEBUG(DL_ERR, ( "Ext2QueryParameters: CheckingBitmap=%xh\n", CheckingBitmap)); /* querying value of Ext3ForceWriting */ RtlZeroMemory(&QueryTable[0], sizeof(RTL_QUERY_REGISTRY_TABLE) * 2); QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED; QueryTable[0].Name = EXT3_FORCEWRITING; QueryTable[0].EntryContext = &Ext3ForceWriting; Status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE, ParameterPath.Buffer, &QueryTable[0], NULL, NULL ); DEBUG(DL_ERR, ( "Ext2QueryParameters: Ext3ForceWriting=%xh\n", Ext3ForceWriting)); /* querying value of AutoMount */ RtlZeroMemory(&QueryTable[0], sizeof(RTL_QUERY_REGISTRY_TABLE) * 2); QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED; QueryTable[0].Name = AUTO_MOUNT; QueryTable[0].EntryContext = &AutoMount; Status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE, ParameterPath.Buffer, &QueryTable[0], NULL, NULL ); SetLongFlag(Ext2Global->Flags, EXT2_AUTO_MOUNT); if (NT_SUCCESS(Status) && AutoMount == 0) { ClearLongFlag(Ext2Global->Flags, EXT2_AUTO_MOUNT); } DEBUG(DL_ERR, ( "Ext2QueryParameters: AutoMount=%xh\n", AutoMount)); /* querying codepage */ RtlZeroMemory(&QueryTable[0], sizeof(RTL_QUERY_REGISTRY_TABLE) * 2); QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED; QueryTable[0].Name = CODEPAGE_NAME; QueryTable[0].EntryContext = &(UniName); UniName.MaximumLength = CODEPAGE_MAXLEN * sizeof(WCHAR); UniName.Length = 0; UniName.Buffer = (PWSTR)UniBuffer; Status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE, ParameterPath.Buffer, &QueryTable[0], NULL, NULL ); if (NT_SUCCESS(Status)) { DEBUG(DL_ERR, ( "Ext2QueryParameters: Ext2CodePage=%wZ\n", &UniName)); AnsiName.MaximumLength = CODEPAGE_MAXLEN; AnsiName.Length = 0; AnsiName.Buffer = &(Ext2Global->Codepage.AnsiName[0]); Status = RtlUnicodeStringToAnsiString( &AnsiName, &UniName, FALSE); if (!NT_SUCCESS(Status)) { DEBUG(DL_ERR, ( "Ext2QueryParameters: Wrong CodePage %wZ ...\n", &UniName)); RtlCopyMemory(&(Ext2Global->Codepage.AnsiName[0]),"default\0", 8); } } else { DEBUG(DL_ERR, ( "Ext2QueryParameters: CodePage not specified.\n")); RtlCopyMemory(&(Ext2Global->Codepage.AnsiName[0]),"default\0", 8); } Ext2Global->Codepage.AnsiName[CODEPAGE_MAXLEN - 1] = 0; /* querying name hiding patterns: prefix*/ RtlZeroMemory(&QueryTable[0], sizeof(RTL_QUERY_REGISTRY_TABLE) * 2); QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED; QueryTable[0].Name = HIDING_PREFIX; QueryTable[0].EntryContext = &(UniName); UniName.MaximumLength = HIDINGPAT_LEN * sizeof(WCHAR); UniName.Length = 0; UniName.Buffer = Buffer; Status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE, ParameterPath.Buffer, &QueryTable[0], NULL, NULL ); if (NT_SUCCESS(Status)) { DEBUG(DL_ERR, ( "Ext2QueryParameters: HidingPrefix=%wZ\n", &UniName)); AnsiName.MaximumLength =HIDINGPAT_LEN; AnsiName.Length = 0; AnsiName.Buffer = &(Ext2Global->sHidingPrefix[0]); Status = RtlUnicodeStringToAnsiString( &AnsiName, &UniName, FALSE); if (NT_SUCCESS(Status)) { Ext2Global->bHidingPrefix = TRUE; } else { DEBUG(DL_ERR, ( "Ext2QueryParameters: Wrong HidingPrefix ...\n")); } } else { DEBUG(DL_ERR, ( "Ext2QueryParameters: HidingPrefix not specified.\n")); } Ext2Global->sHidingPrefix[HIDINGPAT_LEN - 1] = 0; /* querying name hiding patterns: suffix */ RtlZeroMemory(&QueryTable[0], sizeof(RTL_QUERY_REGISTRY_TABLE) * 2); QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED; QueryTable[0].Name = HIDING_SUFFIX; QueryTable[0].EntryContext = &(UniName); UniName.MaximumLength = HIDINGPAT_LEN * sizeof(WCHAR); UniName.Length = 0; UniName.Buffer = Buffer; Status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE, ParameterPath.Buffer, &QueryTable[0], NULL, NULL ); if (NT_SUCCESS(Status)) { DEBUG(DL_ERR, ( "Ext2QueryParameters: HidingSuffix=%wZ\n", &UniName)); AnsiName.MaximumLength = HIDINGPAT_LEN; AnsiName.Length = 0; AnsiName.Buffer = &(Ext2Global->sHidingSuffix[0]); Status = RtlUnicodeStringToAnsiString( &AnsiName, &UniName, FALSE); if (NT_SUCCESS(Status)) { Ext2Global->bHidingSuffix = TRUE; } else { DEBUG(DL_ERR, ( "Ext2QueryParameters: Wrong HidingSuffix ...\n")); } } else { DEBUG(DL_ERR, ( "Ext2QueryParameters: HidingSuffix not specified.\n")); } Ext2Global->sHidingPrefix[HIDINGPAT_LEN - 1] = 0; { if (WritingSupport) { SetLongFlag(Ext2Global->Flags, EXT2_SUPPORT_WRITING); } else { ClearLongFlag(Ext2Global->Flags, EXT2_SUPPORT_WRITING); } if (CheckingBitmap) { SetLongFlag(Ext2Global->Flags, EXT2_CHECKING_BITMAP); } else { ClearLongFlag(Ext2Global->Flags, EXT2_CHECKING_BITMAP); } if (Ext3ForceWriting) { DbgPrint("Ext2Fsd -- Warning: Ext3ForceWriting enabled !!!\n"); SetLongFlag(Ext2Global->Flags, EXT3_FORCE_WRITING); SetLongFlag(Ext2Global->Flags, EXT2_SUPPORT_WRITING); } else { ClearLongFlag(Ext2Global->Flags, EXT3_FORCE_WRITING); } } Ext2Global->RegistryPath.Buffer = ParameterPath.Buffer; Ext2Global->RegistryPath.Length = 0; Ext2Global->RegistryPath.MaximumLength = ParameterPath.MaximumLength; RtlCopyUnicodeString(&Ext2Global->RegistryPath, RegistryPath); RtlAppendUnicodeToString(&Ext2Global->RegistryPath, VOLUMES_KEY); return TRUE; }
NTSTATUS Ext2ReadSync( IN PEXT2_VCB Vcb, IN ULONGLONG Offset, IN ULONG Length, OUT PVOID Buffer, BOOLEAN bVerify ) { PKEVENT Event = NULL; PIRP Irp; IO_STATUS_BLOCK IoStatus; NTSTATUS Status = STATUS_INSUFFICIENT_RESOURCES; ASSERT(Vcb != NULL); ASSERT(Vcb->TargetDeviceObject != NULL); ASSERT(Buffer != NULL); __try { Event = Ext2AllocatePool(NonPagedPool, sizeof(KEVENT), 'EK2E'); if (NULL == Event) { DEBUG(DL_ERR, ( "Ex2ReadSync: failed to allocate Event.\n")); __leave; } INC_MEM_COUNT(PS_DISK_EVENT, Event, sizeof(KEVENT)); KeInitializeEvent(Event, NotificationEvent, FALSE); Irp = IoBuildSynchronousFsdRequest( IRP_MJ_READ, Vcb->TargetDeviceObject, Buffer, Length, (PLARGE_INTEGER)(&Offset), Event, &IoStatus ); if (!Irp) { Status = STATUS_INSUFFICIENT_RESOURCES; __leave; } if (bVerify) { SetFlag( IoGetNextIrpStackLocation(Irp)->Flags, SL_OVERRIDE_VERIFY_VOLUME ); } Status = IoCallDriver(Vcb->TargetDeviceObject, Irp); if (Status == STATUS_PENDING) { KeWaitForSingleObject( Event, Suspended, KernelMode, FALSE, NULL ); Status = IoStatus.Status; } } __finally { if (Event) { Ext2FreePool(Event, 'EK2E'); DEC_MEM_COUNT(PS_DISK_EVENT, Event, sizeof(KEVENT)); } } return Status; }
NTSTATUS Ext2ReadWriteBlocks( IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_VCB Vcb, IN PEXT2_EXTENT Chain, IN ULONG Length ) { PIRP Irp; PIRP MasterIrp = IrpContext->Irp; PIO_STACK_LOCATION IrpSp; PMDL Mdl; PEXT2_RW_CONTEXT pContext = NULL; PEXT2_EXTENT Extent; KEVENT Wait; NTSTATUS Status = STATUS_SUCCESS; BOOLEAN bMasterCompleted = FALSE; BOOLEAN bBugCheck = FALSE; ASSERT(MasterIrp); __try { pContext = Ext2AllocatePool(NonPagedPool, sizeof(EXT2_RW_CONTEXT), EXT2_RWC_MAGIC); if (!pContext) { DEBUG(DL_ERR, ( "Ex2ReadWriteBlocks: failed to allocate pContext.\n")); Status = STATUS_INSUFFICIENT_RESOURCES; __leave; } INC_MEM_COUNT(PS_RW_CONTEXT, pContext, sizeof(EXT2_RW_CONTEXT)); RtlZeroMemory(pContext, sizeof(EXT2_RW_CONTEXT)); pContext->Wait = Ext2CanIWait(); pContext->MasterIrp = MasterIrp; pContext->Length = Length; if (IrpContext->MajorFunction == IRP_MJ_WRITE) { SetFlag(pContext->Flags, EXT2_RW_CONTEXT_WRITE); } if (pContext->Wait) { KeInitializeEvent(&(pContext->Event), NotificationEvent, FALSE); } else if (IrpContext->Fcb->Identifier.Type == EXT2FCB) { if (IsFlagOn(MasterIrp->Flags, IRP_PAGING_IO)) { pContext->Resource = &IrpContext->Fcb->PagingIoResource; } else { pContext->Resource = &IrpContext->Fcb->MainResource; } pContext->FileObject = IrpContext->FileObject; pContext->ThreadId = ExGetCurrentResourceThread(); } if (NULL == Chain->Next && 0 == Chain->Offset) { /* we get only 1 extent to dispatch, then don't bother allocating new irps */ /* setup the Stack location to do a read from the disk driver. */ IrpSp = IoGetNextIrpStackLocation(MasterIrp); IrpSp->MajorFunction = IrpContext->MajorFunction; IrpSp->Parameters.Read.Length = Chain->Length; IrpSp->Parameters.Read.ByteOffset.QuadPart = Chain->Lba; if (IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH)) { SetFlag(IrpSp->Flags, SL_WRITE_THROUGH); } if (IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_VERIFY_READ)) { SetFlag(IrpSp->Flags, SL_OVERRIDE_VERIFY_VOLUME); } IoSetCompletionRoutine( MasterIrp, Ext2CanIWait() ? Ext2ReadWriteBlockSyncCompletionRoutine : Ext2ReadWriteBlockAsyncCompletionRoutine, (PVOID) pContext, TRUE, TRUE, TRUE ); /* intialize context block */ Chain->Irp = MasterIrp; pContext->Blocks = 1; } else { for (Extent = Chain; Extent != NULL; Extent = Extent->Next) { Irp = IoMakeAssociatedIrp( MasterIrp, (CCHAR)(Vcb->TargetDeviceObject->StackSize + 1) ); if (!Irp) { Status = STATUS_INSUFFICIENT_RESOURCES; __leave; } Mdl = IoAllocateMdl( (PCHAR)MasterIrp->UserBuffer + Extent->Offset, Extent->Length, FALSE, FALSE, Irp ); if (!Mdl) { Status = STATUS_INSUFFICIENT_RESOURCES; __leave; } IoBuildPartialMdl( MasterIrp->MdlAddress, Mdl, (PCHAR)MasterIrp->UserBuffer +Extent->Offset, Extent->Length ); IoSetNextIrpStackLocation(Irp); IrpSp = IoGetCurrentIrpStackLocation(Irp); IrpSp->MajorFunction = IrpContext->MajorFunction; IrpSp->Parameters.Read.Length = Extent->Length; IrpSp->Parameters.Read.ByteOffset.QuadPart = Extent->Lba; IoSetCompletionRoutine( Irp, Ext2CanIWait() ? Ext2ReadWriteBlockSyncCompletionRoutine : Ext2ReadWriteBlockAsyncCompletionRoutine, (PVOID) pContext, TRUE, TRUE, TRUE ); IrpSp = IoGetNextIrpStackLocation(Irp); IrpSp->MajorFunction = IrpContext->MajorFunction; IrpSp->Parameters.Read.Length =Extent->Length; IrpSp->Parameters.Read.ByteOffset.QuadPart = Extent->Lba; /* set write through flag */ if (IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH)) { SetFlag( IrpSp->Flags, SL_WRITE_THROUGH ); } /* set verify flag */ if (IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_VERIFY_READ)) { SetFlag(IrpSp->Flags, SL_OVERRIDE_VERIFY_VOLUME); } Extent->Irp = Irp; pContext->Blocks += 1; } MasterIrp->AssociatedIrp.IrpCount = pContext->Blocks; if (Ext2CanIWait()) { MasterIrp->AssociatedIrp.IrpCount += 1; } } if (!Ext2CanIWait()) { /* mark MasterIrp pending */ IoMarkIrpPending(pContext->MasterIrp); } bBugCheck = TRUE; for (Extent = Chain; Extent != NULL; Extent = Extent->Next) { Status = IoCallDriver ( Vcb->TargetDeviceObject, Extent->Irp); Extent->Irp = NULL; } if (Ext2CanIWait()) { KeWaitForSingleObject( &(pContext->Event), Executive, KernelMode, FALSE, NULL ); KeClearEvent( &(pContext->Event) ); } else { bMasterCompleted = TRUE; } } __finally { for (Extent = Chain; Extent != NULL; Extent = Extent->Next) { if (Extent->Irp != NULL ) { if (Extent->Irp->MdlAddress != NULL) { IoFreeMdl(Extent->Irp->MdlAddress ); } IoFreeIrp(Extent->Irp); } } if (IrpContext->ExceptionInProgress) { if (bBugCheck) { Ext2BugCheck(EXT2_BUGCHK_BLOCK, 0, 0, 0); } } else { if (Ext2CanIWait()) { if (MasterIrp) { Status = MasterIrp->IoStatus.Status; } if (pContext) { Ext2FreePool(pContext, EXT2_RWC_MAGIC); DEC_MEM_COUNT(PS_RW_CONTEXT, pContext, sizeof(EXT2_RW_CONTEXT)); } } else { if (bMasterCompleted) { IrpContext->Irp = NULL; Status = STATUS_PENDING; } } } } return Status; }
NTSTATUS Ext2ExpandLast( IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_VCB Vcb, IN PEXT2_MCB Mcb, IN ULONG Base, IN ULONG Layer, IN PULONG * Data, IN PULONG Hint, IN PULONG Block, IN OUT PULONG Number ) { PULONG pData = NULL; ULONG i; NTSTATUS Status = STATUS_SUCCESS; if (Layer > 0 || IsMcbDirectory(Mcb)) { /* allocate buffer for new block */ pData = (ULONG *) Ext2AllocatePool( PagedPool, BLOCK_SIZE, EXT2_DATA_MAGIC ); if (!pData) { DEBUG(DL_ERR, ( "Ex2ExpandBlock: failed to allocate memory for Data.\n")); Status = STATUS_INSUFFICIENT_RESOURCES; goto errorout; } RtlZeroMemory(pData, BLOCK_SIZE); INC_MEM_COUNT(PS_BLOCK_DATA, pData, BLOCK_SIZE); } /* allocate block from disk */ Status = Ext2NewBlock( IrpContext, Vcb, (Mcb->Inode.i_ino - 1) / BLOCKS_PER_GROUP, *Hint, Block, Number ); if (!NT_SUCCESS(Status)) { goto errorout; } /* increase inode i_blocks */ Mcb->Inode.i_blocks += (*Number << (BLOCK_BITS - 9)); if (Layer == 0) { if (IsMcbDirectory(Mcb)) { /* for directory we need initialize it's entry structure */ PEXT2_DIR_ENTRY2 pEntry; pEntry = (PEXT2_DIR_ENTRY2) pData; pEntry->rec_len = (USHORT)(BLOCK_SIZE); ASSERT(*Number == 1); Ext2SaveBlock(IrpContext, Vcb, *Block, (PVOID)pData); } /* add new Extent into Mcb */ if (!Ext2AddBlockExtent(Vcb, Mcb, Base, (*Block), *Number)) { DbgBreak(); ClearFlag(Mcb->Flags, MCB_ZONE_INITED); Ext2ClearAllExtents(&Mcb->Extents); } } else { /* zero the content of all meta blocks */ for (i = 0; i < *Number; i++) { Ext2SaveBlock(IrpContext, Vcb, *Block + i, (PVOID)pData); /* add block to meta extents */ if (!Ext2AddMcbMetaExts(Vcb, Mcb, *Block + i, 1)) { DbgBreak(); Ext2Sleep(500); Ext2AddMcbMetaExts(Vcb, Mcb, *Block + i, 1); } } } errorout: if (NT_SUCCESS(Status)) { *Hint = *Block + *Number; if (Data) { *Data = pData; ASSERT(*Number == 1); } else { if (pData) { Ext2FreePool(pData, EXT2_DATA_MAGIC); DEC_MEM_COUNT(PS_BLOCK_DATA, pData, BLOCK_SIZE); } } } else { if (pData) { Ext2FreePool(pData, EXT2_DATA_MAGIC); DEC_MEM_COUNT(PS_BLOCK_DATA, pData, BLOCK_SIZE); } if (*Block) { Ext2FreeBlock(IrpContext, Vcb, *Block, *Number); Mcb->Inode.i_blocks -= (*Number << (BLOCK_BITS - 9)); *Block = 0; } } return Status; }
/************************************************************************* * * Function: Ext2QueryDirectory() * * Description: * Query directory request. * * Expected Interrupt Level (for execution) : * * IRQL_PASSIVE_LEVEL * * Return Value: STATUS_SUCCESS/Error * *************************************************************************/ NTSTATUS NTAPI Ext2QueryDirectory( PtrExt2IrpContext PtrIrpContext, PIRP PtrIrp, #ifdef _GNU_NTIFS_ PEXTENDED_IO_STACK_LOCATION PtrIoStackLocation, #else PIO_STACK_LOCATION PtrIoStackLocation, #endif PFILE_OBJECT PtrFileObject, PtrExt2FCB PtrFCB, PtrExt2CCB PtrCCB) { NTSTATUS RC = STATUS_SUCCESS; BOOLEAN PostRequest = FALSE; PtrExt2NTRequiredFCB PtrReqdFCB = NULL; BOOLEAN CanWait = FALSE; PtrExt2VCB PtrVCB = NULL; BOOLEAN AcquiredFCB = FALSE; unsigned long BufferLength = 0; unsigned long BufferIndex = 0; unsigned long FileIndex = 0; PUNICODE_STRING PtrSearchPattern = NULL; FILE_INFORMATION_CLASS FileInformationClass; BOOLEAN RestartScan = FALSE; BOOLEAN ReturnSingleEntry = FALSE; BOOLEAN IndexSpecified = FALSE; unsigned char *Buffer = NULL; BOOLEAN FirstTimeQuery = FALSE; unsigned long StartingIndexForSearch = 0; unsigned long BytesReturned = 0; BOOLEAN BufferUsedup = FALSE; BOOLEAN SearchWithWildCards = FALSE; PFILE_BOTH_DIR_INFORMATION BothDirInformation = NULL; PFILE_DIRECTORY_INFORMATION DirectoryInformation = NULL; PEXT2_DIR_ENTRY PtrDirEntry = NULL; PEXT2_INODE PtrInode = NULL; unsigned long LogicalBlockSize; unsigned long ThisBlock; // The starting Physical Block No... //LARGE_INTEGER StartPhysicalBlock; LARGE_INTEGER StartBufferOffset ; ULONG PinBufferLength; // Buffer Control Block PBCB PtrBCB = NULL; BYTE * PtrPinnedBlockBuffer = NULL; unsigned int j; DebugTrace(DEBUG_TRACE_MISC, " === Querying Directory %S", PtrFCB->FCBName->ObjectName.Buffer ); try { // Validate the sent-in FCB if ((PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB) || !(PtrFCB->FCBFlags & EXT2_FCB_DIRECTORY)) { // We will only allow notify requests on directories. RC = STATUS_INVALID_PARAMETER; } PtrReqdFCB = &(PtrFCB->NTRequiredFCB); CanWait = ((PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE); PtrVCB = PtrFCB->PtrVCB; // // Asynchronous IO requested // Posting request... // /* * This is incorrect because posted IRP_MJ_DIRECTORY_CONTROL * requests aren't handled in the worker thread yet. I tried * adding handling of them to the worked routine, but there * were problems with accessing the PtrIoStackLocation-> * Parameters.QueryDirectory.FileName variable. * -- Filip Navara, 18/08/2004 */ #if 0 if (!CanWait) { PostRequest = TRUE; try_return(RC = STATUS_PENDING); } #endif // Obtain the callers parameters BufferLength = PtrIoStackLocation->Parameters.QueryDirectory.Length; PtrSearchPattern = ( PUNICODE_STRING ) PtrIoStackLocation->Parameters.QueryDirectory.FileName; FileInformationClass = PtrIoStackLocation->Parameters.QueryDirectory.FileInformationClass; FileIndex = PtrIoStackLocation->Parameters.QueryDirectory.FileIndex; // Some additional arguments that affect the FSD behavior RestartScan = (PtrIoStackLocation->Flags & SL_RESTART_SCAN); ReturnSingleEntry = (PtrIoStackLocation->Flags & SL_RETURN_SINGLE_ENTRY); IndexSpecified = (PtrIoStackLocation->Flags & SL_INDEX_SPECIFIED); // // Acquiring exclusive access to the FCB. // This is not mandatory // DebugTrace(DEBUG_TRACE_MISC, "*** Going into a block to acquire FCB Exclusively[DirCtrl]", 0); DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [DirCtrl]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters ); ExAcquireResourceExclusiveLite(&(PtrReqdFCB->MainResource), TRUE); DebugTrace(DEBUG_TRACE_MISC, "*** FCB acquired [DirCtrl]", 0); AcquiredFCB = TRUE; // We must determine the buffer pointer to be used. Since this // routine could either be invoked directly in the context of the // calling thread, or in the context of a worker thread, here is // a general way of determining what we should use. Buffer = Ext2GetCallersBuffer ( PtrIrp ); // The method of determining where to look from and what to look for is // unfortunately extremely confusing. However, here is a methodology you // you can broadly adopt: // (a) You have to maintain a search buffer per CCB structure. // (b) This search buffer is initialized the very first time // a query directory operation is performed using the file object. // (For the sample FSD, the search buffer is stored in the // DirectorySearchPattern field) // However, the caller still has the option of "overriding" this stored // search pattern by supplying a new one in a query directory operation. // if( PtrCCB->DirectorySearchPattern.Length ) { if( PtrCCB->DirectorySearchPattern.Buffer[PtrCCB->DirectorySearchPattern.Length/2] != 0 ) { DebugTrace(DEBUG_TRACE_MISC, "&&&&&&&&& PtrCCB->DirectorySearchPattern not NULL terminated!", 0); } DebugTrace(DEBUG_TRACE_MISC, " === Old Search pattern %S", PtrCCB->DirectorySearchPattern.Buffer ); } if (PtrSearchPattern != NULL) { // User has supplied a search pattern // Now validate that the search pattern is legitimate if ( PtrCCB->DirectorySearchPattern.Length == 0 ) { // This must be the very first query request. FirstTimeQuery = TRUE; } else { // We should ignore the search pattern in the CCB and instead, // use the user-supplied pattern for this particular query // directory request. Ext2DeallocateUnicodeString( &PtrCCB->DirectorySearchPattern ); } // Now, allocate enough memory to contain the caller // supplied search pattern and fill in the DirectorySearchPattern // field in the CCB Ext2CopyUnicodeString( &PtrCCB->DirectorySearchPattern, PtrSearchPattern ); /* PtrCCB->DirectorySearchPattern = Ext2AllocatePool(PagedPool, sizeof( PtrSearchPattern ) ); ASSERT(PtrCCB->DirectorySearchPattern); RtlCopyMemory( PtrCCB->DirectorySearchPattern, PtrSearchPattern, sizeof( PtrSearchPattern ) ); */ } else if ( PtrCCB->DirectorySearchPattern.Length == 0 ) { // This MUST be the first directory query operation (else the // DirectorySearchPattern field would never be empty. Also, the caller // has neglected to provide a pattern so we MUST invent one. // Use "*" (following NT conventions) as your search pattern // and store it in the PtrCCB->DirectorySearchPattern field. /* PtrCCB->DirectorySearchPattern = Ext2AllocatePool(PagedPool, sizeof(L"*") ); ASSERT(PtrCCB->DirectorySearchPattern); RtlCopyMemory( PtrCCB->DirectorySearchPattern, L"*", 4 );*/ Ext2CopyWideCharToUnicodeString( &PtrCCB->DirectorySearchPattern, L"*" ); FirstTimeQuery = TRUE; } else { // The caller has not supplied any search pattern... // Using previously supplied pattern PtrSearchPattern = &PtrCCB->DirectorySearchPattern; } if( PtrCCB->DirectorySearchPattern.Buffer[PtrCCB->DirectorySearchPattern.Length/2] != 0 ) { DebugTrace(DEBUG_TRACE_MISC, "&&&&&&&&& PtrCCB->DirectorySearchPattern not NULL terminated!", 0 ); } DebugTrace(DEBUG_TRACE_MISC, " === Search pattern %S", PtrCCB->DirectorySearchPattern.Buffer ); SearchWithWildCards = FsRtlDoesNameContainWildCards( PtrSearchPattern ); // There is one other piece of information that your FSD must store // in the CCB structure for query directory support. This is the index // value (i.e. the offset in your on-disk directory structure) from // which you should start searching. // However, the flags supplied with the IRP can make us override this // as well. if (FileIndex) { // Caller has told us wherefrom to begin. // You may need to round this to an appropriate directory entry // entry alignment value. StartingIndexForSearch = FileIndex; } else if (RestartScan) { StartingIndexForSearch = 0; } else { // Get the starting offset from the CCB. StartingIndexForSearch = PtrCCB->CurrentByteOffset.LowPart; } // Read in the file inode if it hasn't already been read... Ext2InitializeFCBInodeInfo( PtrFCB ); if (PtrFileObject->PrivateCacheMap == NULL) { CcInitializeCacheMap(PtrFileObject, (PCC_FILE_SIZES)(&(PtrReqdFCB->CommonFCBHeader.AllocationSize)), TRUE, // We will utilize pin access for directories &(Ext2GlobalData.CacheMgrCallBacks), // callbacks PtrCCB); // The context used in callbacks } // // Read in the next Data Block of this directory // LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; StartBufferOffset.QuadPart = ( StartingIndexForSearch / LogicalBlockSize ); StartBufferOffset.QuadPart *= LogicalBlockSize; // This should be the StartBufferOffset alaigned to LBlock boundary... PinBufferLength = PtrReqdFCB->CommonFCBHeader.FileSize.LowPart - StartBufferOffset.LowPart; if ( !CcMapData( PtrFileObject, &StartBufferOffset, PinBufferLength, TRUE, &PtrBCB, (PVOID*)&PtrPinnedBlockBuffer ) ) { // Read Failure DebugTrace(DEBUG_TRACE_MISC, "Cache read failiure while reading in volume meta data", 0); try_return(); } else { DebugTrace(DEBUG_TRACE_MISC, "Cache hit while reading in volume meta data", 0); } PtrInode = Ext2AllocatePool( PagedPool, sizeof( EXT2_INODE ) ); // // Walking through the directory entries... for( BufferUsedup = FALSE, BufferIndex = 0; !BufferUsedup && StartingIndexForSearch < ( PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart - 1) ; ) { PtrDirEntry = (PEXT2_DIR_ENTRY) &PtrPinnedBlockBuffer[ StartingIndexForSearch - StartBufferOffset.LowPart ]; StartingIndexForSearch += PtrDirEntry->rec_len; PtrCCB->CurrentByteOffset.LowPart = StartingIndexForSearch; if( PtrDirEntry->inode == 0 ) { continue; } if( PtrDirEntry->name_len == 0 || PtrDirEntry->rec_len == 0 ) { // // This should not happen // Hqw can this be so!!! // Ext2BreakPoint(); if( BothDirInformation ) { BothDirInformation->NextEntryOffset = 0; } if( !BytesReturned ) { if( FirstTimeQuery ) RC = STATUS_NO_SUCH_FILE; else RC = STATUS_NO_MORE_FILES; } break; } // Does this entry match the search criterian? // Checking // { UNICODE_STRING FileName; LONG Matched = 0; // Constructing a counted Unicode string out of PtrDirEntry Ext2CopyCharToUnicodeString( &FileName, PtrDirEntry->name, PtrDirEntry->name_len ); if ( SearchWithWildCards ) { Matched = FsRtlIsNameInExpression ( PtrSearchPattern, &FileName, FALSE, NULL ); } else { Matched = ! RtlCompareUnicodeString( PtrSearchPattern, &FileName, FALSE ); } Ext2DeallocateUnicodeString( &FileName ); if( !Matched ) { continue; } } switch( FileInformationClass ) { case FileBothDirectoryInformation: DebugTrace(DEBUG_TRACE_DIRINFO, " === FileBothDirectoryInformation", 0 ); ThisBlock = sizeof( FILE_BOTH_DIR_INFORMATION ); ThisBlock += PtrDirEntry->name_len*2; ThisBlock = Ext2QuadAlign( ThisBlock ); if( ( BufferIndex + ThisBlock ) > BufferLength ) { // // Next entry won't fit into the buffer... // will have to return... // :( // if( BothDirInformation ) BothDirInformation->NextEntryOffset = 0; if( !BytesReturned ) RC = STATUS_NO_MORE_FILES; BufferUsedup = TRUE; break; } Ext2ReadInode( PtrVCB, PtrDirEntry->inode, PtrInode ); if( !PtrInode ) { try_return( RC = STATUS_UNSUCCESSFUL ); } BothDirInformation = ( PFILE_BOTH_DIR_INFORMATION ) ( Buffer + ( BufferIndex ) ); BothDirInformation->EaSize = 0; BothDirInformation->AllocationSize.QuadPart = PtrInode->i_blocks * 512; BothDirInformation->EndOfFile.QuadPart = PtrInode->i_size; BothDirInformation->ChangeTime.QuadPart = 0; BothDirInformation->CreationTime.QuadPart = ( __int64 ) PtrInode->i_ctime * 10000000; BothDirInformation->CreationTime.QuadPart += Ext2GlobalData.TimeDiff.QuadPart; BothDirInformation->LastAccessTime.QuadPart = Ext2GlobalData.TimeDiff.QuadPart + ( ( __int64 ) PtrInode->i_atime * 10000000 ); BothDirInformation->LastWriteTime.QuadPart = Ext2GlobalData.TimeDiff.QuadPart + ( ( __int64 )PtrInode->i_mtime * 10000000 ); // Getting the file type... BothDirInformation->FileAttributes = FILE_ATTRIBUTE_NORMAL; if( ! Ext2IsModeRegularFile( PtrInode->i_mode ) ) { // Not a reqular file... if( Ext2IsModeDirectory( PtrInode->i_mode) ) { // Directory... BothDirInformation->FileAttributes |= FILE_ATTRIBUTE_DIRECTORY; } else { // Special File... // Treated with respect... ;) // BothDirInformation->FileAttributes |= ( FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY); // FILE_ATTRIBUTE_DEVICE } if ( Ext2IsModeHidden( PtrInode->i_mode ) ) { BothDirInformation->FileAttributes |= FILE_ATTRIBUTE_HIDDEN; } if ( Ext2IsModeReadOnly( PtrInode->i_mode ) ) { BothDirInformation->FileAttributes |= FILE_ATTRIBUTE_READONLY; } } BothDirInformation->FileIndex = StartingIndexForSearch; BothDirInformation->FileNameLength = PtrDirEntry->name_len*2 + 2; BothDirInformation->ShortNameLength = 0; BothDirInformation->ShortName[0] = 0; // Copying out the name as WCHAR null terminated strings for( j = 0; j< PtrDirEntry->name_len ; j ++ ) { // BothDirInformation->ShortName[ j ] = PtrDirEntry->name[j]; BothDirInformation->FileName[ j ] = PtrDirEntry->name[j]; // if( j < 11 ) // BothDirInformation->ShortName[j] = PtrDirEntry->name[j]; } /* if( j < 11 ) { BothDirInformation->ShortNameLength = j * 2 + 2; BothDirInformation->ShortName[ j ] = 0; } else { BothDirInformation->ShortNameLength = 24; BothDirInformation->ShortName[ 11 ] = 0; }*/ BothDirInformation->FileName[ j ] = 0; BytesReturned += ThisBlock; BufferIndex += ThisBlock; if( !ReturnSingleEntry && ( StartingIndexForSearch < ( PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart - 1) )) BothDirInformation->NextEntryOffset = ThisBlock; else BothDirInformation->NextEntryOffset = 0; break; case FileDirectoryInformation: // DirectoryInformation DebugTrace(DEBUG_TRACE_DIRINFO, " === FileDirectoryInformation", 0 ); ThisBlock = sizeof( FILE_DIRECTORY_INFORMATION ); ThisBlock += PtrDirEntry->name_len*2; ThisBlock = Ext2QuadAlign( ThisBlock ); if( ( BufferIndex + ThisBlock ) > BufferLength ) { // // Next entry won't fit into the buffer... // will have to return... // :( // if( DirectoryInformation ) DirectoryInformation->NextEntryOffset = 0; if( !BytesReturned ) RC = STATUS_NO_MORE_FILES; BufferUsedup = TRUE; break; } Ext2ReadInode( PtrVCB, PtrDirEntry->inode, PtrInode ); if( !PtrInode ) { try_return( RC = STATUS_UNSUCCESSFUL ); } DirectoryInformation = ( PFILE_DIRECTORY_INFORMATION ) ( Buffer + ( BufferIndex ) ); DirectoryInformation->AllocationSize.QuadPart = PtrInode->i_blocks * 512; DirectoryInformation->EndOfFile.QuadPart = PtrInode->i_size; DirectoryInformation->ChangeTime.QuadPart = 0; DirectoryInformation->CreationTime.QuadPart = ( __int64 ) PtrInode->i_ctime * 10000000; DirectoryInformation->CreationTime.QuadPart += Ext2GlobalData.TimeDiff.QuadPart; DirectoryInformation->LastAccessTime.QuadPart = Ext2GlobalData.TimeDiff.QuadPart + ( ( __int64 ) PtrInode->i_atime * 10000000 ); DirectoryInformation->LastWriteTime.QuadPart = Ext2GlobalData.TimeDiff.QuadPart + ( ( __int64 )PtrInode->i_mtime * 10000000 ); // Getting the file type... DirectoryInformation->FileAttributes = FILE_ATTRIBUTE_NORMAL; if( ! Ext2IsModeRegularFile( PtrInode->i_mode ) ) { // Not a reqular file... if( Ext2IsModeDirectory( PtrInode->i_mode) ) { // Directory... DirectoryInformation->FileAttributes |= FILE_ATTRIBUTE_DIRECTORY; } else { // Special File... // Treated with respect... ;) // DirectoryInformation->FileAttributes |= ( FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY); // FILE_ATTRIBUTE_DEVICE } if ( Ext2IsModeHidden( PtrInode->i_mode ) ) { DirectoryInformation->FileAttributes |= FILE_ATTRIBUTE_HIDDEN; } if ( Ext2IsModeReadOnly( PtrInode->i_mode ) ) { DirectoryInformation->FileAttributes |= FILE_ATTRIBUTE_READONLY; } } DirectoryInformation->FileIndex = StartingIndexForSearch; DirectoryInformation->FileNameLength = PtrDirEntry->name_len*2 + 2; // Copying out the name as WCHAR null terminated strings for( j = 0; j< PtrDirEntry->name_len ; j ++ ) { DirectoryInformation->FileName[ j ] = PtrDirEntry->name[j]; } DirectoryInformation->FileName[ j ] = 0; BytesReturned += ThisBlock; BufferIndex += ThisBlock; if( !ReturnSingleEntry && ( StartingIndexForSearch < ( PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart - 1) )) DirectoryInformation->NextEntryOffset = ThisBlock; else DirectoryInformation->NextEntryOffset = 0; break; case FileFullDirectoryInformation: // FullDirInformation-> DebugTrace(DEBUG_TRACE_DIRINFO, " === FileFullDirectoryInformation - Not handled", 0 ); try_return(); case FileNamesInformation: // NamesInformation-> DebugTrace(DEBUG_TRACE_DIRINFO, " === FileNamesInformation - Not handled", 0 ); try_return(); default: DebugTrace(DEBUG_TRACE_DIRINFO, " === Invalid Dir Info class - Not handled", 0 ); try_return( RC = STATUS_INVALID_INFO_CLASS ); } if( ReturnSingleEntry ) { break; } }// end of for... if( !BytesReturned && StartingIndexForSearch >= ( PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart) ) { Ext2DeallocateUnicodeString( &PtrCCB->DirectorySearchPattern ); PtrCCB->CurrentByteOffset.QuadPart = 0; if( FirstTimeQuery ) RC = STATUS_NO_SUCH_FILE; else RC = STATUS_NO_MORE_FILES; try_return(); } else if( BytesReturned ) { BothDirInformation->NextEntryOffset = 0; } try_exit: NOTHING; } finally { if( PtrInode ) { DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [DirCtrl]", PtrInode ); ExFreePool( PtrInode ); } if( PtrBCB ) { CcUnpinData( PtrBCB ); PtrBCB = NULL; } if (PostRequest) { if (AcquiredFCB) { Ext2ReleaseResource(&(PtrReqdFCB->MainResource)); DebugTrace(DEBUG_TRACE_MISC, "*** FCB Released in [DirCtrl]", 0); DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [DirCtrl]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters ); } // Map the users buffer and then post the request. RC = Ext2LockCallersBuffer(PtrIrp, TRUE, BufferLength); ASSERT(NT_SUCCESS(RC)); RC = Ext2PostRequest(PtrIrpContext, PtrIrp); } else if (!(PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_EXCEPTION)) { if (AcquiredFCB) { Ext2ReleaseResource(&(PtrReqdFCB->MainResource)); DebugTrace(DEBUG_TRACE_MISC, "*** FCB Released [DirCtrl]", 0); DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [DirCtrl]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters ); } // Complete the request. PtrIrp->IoStatus.Status = RC; PtrIrp->IoStatus.Information = BytesReturned; // Free up the Irp Context Ext2ReleaseIrpContext(PtrIrpContext); // complete the IRP IoCompleteRequest(PtrIrp, IO_DISK_INCREMENT); } // Flush the saved BCBs... // Ext2FlushSavedBCBs ( PtrIrpContext ); } return(RC); }