NTSTATUS Ext2ExpandBlock( IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_VCB Vcb, IN PEXT2_MCB Mcb, IN ULONG Base, IN ULONG Layer, IN ULONG Start, IN ULONG SizeArray, IN PULONG BlockArray, IN PULONG Hint, IN PULONG Extra ) { ULONG i = 0; ULONG j; ULONG Slot; ULONG Block = 0; LARGE_INTEGER Offset; PBCB Bcb = NULL; PULONG pData = NULL; ULONG Skip = 0; ULONG Number; ULONG Wanted; NTSTATUS Status = STATUS_SUCCESS; if (Layer == 1) { /* * try to make all leaf block continuous to avoid fragments */ Number = min(SizeArray, ((*Extra + (Start & (BLOCK_SIZE/4 - 1))) * 4 / BLOCK_SIZE)); Wanted = 0; DEBUG(DL_BLK, ("Ext2ExpandBlock: SizeArray=%xh Extra=%xh Start=%xh %xh\n", SizeArray, *Extra, Start, Number )); for (i=0; i < Number; i++) { if (BlockArray[i] == 0) { Wanted += 1; } } i = 0; while (Wanted > 0) { Number = Wanted; Status = Ext2ExpandLast( IrpContext, Vcb, Mcb, Base, Layer, NULL, Hint, &Block, &Number ); if (!NT_SUCCESS(Status)) { goto errorout; } ASSERT(Number > 0); Wanted -= Number; while (Number) { if (BlockArray[i] == 0) { BlockArray[i] = Block++; Number--; } i++; } } } else if (Layer == 0) { /* * bulk allocation for inode data blocks */ i = 0; while (*Extra && i < SizeArray) { Wanted = 0; Number = 1; for (j = i; j < SizeArray && j < i + *Extra; j++) { if (BlockArray[j] >= TOTAL_BLOCKS) { DbgBreak(); BlockArray[j] = 0; } if (BlockArray[j] == 0) { Wanted += 1; } else { break; } } if (Wanted == 0) { /* add block extent into Mcb */ ASSERT(BlockArray[i] != 0); if (!Ext2AddBlockExtent(Vcb, Mcb, Base + i, BlockArray[i], 1)) { DbgBreak(); ClearFlag(Mcb->Flags, MCB_ZONE_INITED); Ext2ClearAllExtents(&Mcb->Extents); } } else { Number = Wanted; Status = Ext2ExpandLast( IrpContext, Vcb, Mcb, Base + i, 0, NULL, Hint, &Block, &Number ); if (!NT_SUCCESS(Status)) { goto errorout; } ASSERT(Number > 0); for (j = 0; j < Number; j++) { BlockArray[i + j] = Block++; } } *Extra -= Number; i += Number; } goto errorout; } /* * only for meta blocks allocation */ for (i = 0; *Extra && i < SizeArray; i++) { if (Layer <= 3) { if (BlockArray[i] >= TOTAL_BLOCKS) { DbgBreak(); BlockArray[i] = 0; } if (BlockArray[i] == 0) { Number = 1; Status = Ext2ExpandLast( IrpContext, Vcb, Mcb, Base, Layer, &pData, Hint, &BlockArray[i], &Number ); if (!NT_SUCCESS(Status)) { goto errorout; } } else { Offset.QuadPart = (((LONGLONG)BlockArray[i]) << BLOCK_BITS); if (!CcPinRead( Vcb->Volume, &Offset, BLOCK_SIZE, PIN_WAIT, &Bcb, (void **)&pData )) { DEBUG(DL_ERR, ( "Ext2ExpandInode: failed to PinLock offset :%I64xh...\n", Offset.QuadPart)); Status = STATUS_CANT_WAIT; DbgBreak(); goto errorout; } /* add block to meta extents */ if (!Ext2AddMcbMetaExts(Vcb, Mcb, BlockArray[i], 1)) { DbgBreak(); Ext2Sleep(500); Ext2AddMcbMetaExts(Vcb, Mcb, BlockArray[i], 1); } } Skip = Vcb->max_blocks_per_layer[Layer] * i; if (i == 0) { if (Layer > 1) { Slot = Start / Vcb->max_blocks_per_layer[Layer - 1]; Start = Start % Vcb->max_blocks_per_layer[Layer - 1]; Skip += Slot * Vcb->max_blocks_per_layer[Layer - 1]; } else { Slot = Start; Start = 0; Skip += Slot; } } else { Start = 0; Slot = 0; } Status = Ext2ExpandBlock( IrpContext, Vcb, Mcb, Base + Skip, Layer - 1, Start, BLOCK_SIZE/4 - Slot, &pData[Slot], Hint, Extra ); if (Bcb) { CcSetDirtyPinnedData(Bcb, NULL); if (!Ext2AddBlockExtent(Vcb, NULL, BlockArray[i], BlockArray[i], 1)) { DbgBreak(); Ext2Sleep(500); if (!Ext2AddBlockExtent(Vcb, NULL, BlockArray[i], BlockArray[i], 1)) { } } } else { Ext2SaveBlock(IrpContext, Vcb, BlockArray[i], (PVOID)pData); } if (pData) { if (Bcb) { CcUnpinData(Bcb); Bcb = NULL; } else { Ext2FreePool(pData, EXT2_DATA_MAGIC); DEC_MEM_COUNT(PS_BLOCK_DATA, pData, BLOCK_SIZE); } pData = NULL; } if (!NT_SUCCESS(Status)) { DbgBreak(); break; } } } errorout: 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; }
NTSTATUS Ext2GetBlock( IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_VCB Vcb, IN PEXT2_MCB Mcb, IN ULONG Base, IN ULONG Layer, IN ULONG Start, IN ULONG SizeArray, IN PULONG BlockArray, IN BOOLEAN bAlloc, IN OUT PULONG Hint, OUT PULONG Block, OUT PULONG Number ) { NTSTATUS Status = STATUS_SUCCESS; PBCB Bcb = NULL; PULONG pData = NULL; ULONG Slot = 0, i = 0; ULONG Unit = 1; LARGE_INTEGER Offset; if (Layer == 0) { *Number = 1; if (BlockArray[0] == 0 && bAlloc) { /* now allocate new block */ Status = Ext2ExpandLast( IrpContext, Vcb, Mcb, Base, Layer, NULL, Hint, &BlockArray[0], Number ); if (!NT_SUCCESS(Status)) { goto errorout; } } else { /* check the block is valid or not */ if (BlockArray[0] >= TOTAL_BLOCKS) { DbgBreak(); Status = STATUS_DISK_CORRUPT_ERROR; goto errorout; } } *Block = BlockArray[0]; for (i=1; i < SizeArray; i++) { if (BlockArray[i] == BlockArray[i-1] + 1) { *Number = *Number + 1; } else { break; } } *Hint = BlockArray[*Number - 1]; } else if (Layer <= 3) { /* check the block is valid or not */ if (BlockArray[0] == 0 || BlockArray[0] >= TOTAL_BLOCKS) { DbgBreak(); Status = STATUS_DISK_CORRUPT_ERROR; goto errorout; } /* add block to meta extents */ if (!Ext2AddMcbMetaExts(Vcb, Mcb, BlockArray[0], 1)) { DbgBreak(); Ext2Sleep(500); Ext2AddMcbMetaExts(Vcb, Mcb, BlockArray[0], 1); } /* map memory in cache for the index block */ Offset.QuadPart = ((LONGLONG)BlockArray[0]) << BLOCK_BITS; if ( !CcPinRead( Vcb->Volume, (PLARGE_INTEGER) (&Offset), BLOCK_SIZE, PIN_WAIT, &Bcb, (void **)&pData )) { DEBUG(DL_ERR, ( "Ext2GetBlock: Failed to PinLock block: %xh ...\n", BlockArray[0] )); Status = STATUS_CANT_WAIT; goto errorout; } if (Layer > 1) { Unit = Vcb->max_blocks_per_layer[Layer - 1]; } else { Unit = 1; } Slot = Start / Unit; Start = Start % Unit; if (pData[Slot] == 0) { if (bAlloc) { /* we need allocate new block and zero all data in case it's an in-direct block. Index stores the new block no. */ ULONG Count = 1; Status = Ext2ExpandLast( IrpContext, Vcb, Mcb, Base, Layer, NULL, Hint, &pData[Slot], &Count ); if (!NT_SUCCESS(Status)) { goto errorout; } /* refresh hint block */ *Hint = pData[Slot]; /* set dirty bit to notify system to flush */ CcSetDirtyPinnedData(Bcb, NULL ); SetFlag(Vcb->Volume->Flags, FO_FILE_MODIFIED); if (!Ext2AddVcbExtent(Vcb, Offset.QuadPart, (LONGLONG)BLOCK_SIZE)) { DbgBreak(); Ext2Sleep(100); if (!Ext2AddVcbExtent(Vcb, Offset.QuadPart, (LONGLONG)BLOCK_SIZE)) { Status = STATUS_INSUFFICIENT_RESOURCES; goto errorout; } } /* save inode information here */ Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode); } else { *Number = 1; if (Layer == 1) { for (i = Slot + 1; i < BLOCK_SIZE/4; i++) { if (pData[i] == 0) { *Number = *Number + 1; } else { break; } } } else if (Layer == 2) { *Number = BLOCK_SIZE/4 - Start; } else { *Number = BLOCK_SIZE/4; } goto errorout; } } /* transfer to next recursion call */ Status = Ext2GetBlock( IrpContext, Vcb, Mcb, Base, Layer - 1, Start, BLOCK_SIZE/4 - Slot, &pData[Slot], bAlloc, Hint, Block, Number ); if (!NT_SUCCESS(Status)) { goto errorout; } } errorout: /* free the memory of pData */ if (Bcb) { CcUnpinData(Bcb); } if (!NT_SUCCESS(Status)) { *Block = 0; } return Status; }
NTSTATUS Ext2TruncateIndirectFast( PEXT2_IRP_CONTEXT IrpContext, PEXT2_VCB Vcb, PEXT2_MCB Mcb ) { LONGLONG Vba; LONGLONG Lba; LONGLONG Length; NTSTATUS Status = STATUS_SUCCESS; int i; /* try to load all indirect blocks if mcb zone is not initialized */ if (!IsZoneInited(Mcb)) { Status = Ext2InitializeZone(IrpContext, Vcb, Mcb); if (!NT_SUCCESS(Status)) { DbgBreak(); ClearLongFlag(Mcb->Flags, MCB_ZONE_INITED); goto errorout; } } ASSERT (IsZoneInited(Mcb)); /* delete all data blocks here */ if (FsRtlNumberOfRunsInLargeMcb(&Mcb->Extents) != 0) { for (i = 0; FsRtlGetNextLargeMcbEntry(&Mcb->Extents, i, &Vba, &Lba, &Length); i++) { /* ignore the non-existing runs */ if (-1 == Lba || Vba == 0 || Length <= 0) continue; /* now do data block free */ Ext2FreeBlock(IrpContext, Vcb, (ULONG)(Lba - 1), (ULONG)Length); } } /* delete all meta blocks here */ if (FsRtlNumberOfRunsInLargeMcb(&Mcb->MetaExts) != 0) { for (i = 0; FsRtlGetNextLargeMcbEntry(&Mcb->MetaExts, i, &Vba, &Lba, &Length); i++) { /* ignore the non-existing runs */ if (-1 == Lba || Vba == 0 || Length <= 0) continue; /* now do meta block free */ Ext2FreeBlock(IrpContext, Vcb, (ULONG)(Lba - 1), (ULONG)Length); } } /* clear data and meta extents */ Ext2ClearAllExtents(&Mcb->Extents); Ext2ClearAllExtents(&Mcb->MetaExts); ClearFlag(Mcb->Flags, MCB_ZONE_INITED); /* clear inode blocks & sizes */ Mcb->Inode.i_blocks = 0; Mcb->Inode.i_size = 0; memset(&Mcb->Inode.i_block[0], 0, sizeof(__u32) * 15); /* the caller will do inode save */ errorout: return Status; }
__drv_mustHoldCriticalRegion NTSTATUS RfsdQueryVolumeInformation (IN PRFSD_IRP_CONTEXT IrpContext) { PDEVICE_OBJECT DeviceObject; NTSTATUS Status = STATUS_UNSUCCESSFUL; PRFSD_VCB Vcb = 0; PIRP Irp; PIO_STACK_LOCATION IoStackLocation; FS_INFORMATION_CLASS FsInformationClass; ULONG Length; PVOID Buffer; BOOLEAN VcbResourceAcquired = FALSE; PAGED_CODE(); _SEH2_TRY { ASSERT(IrpContext != NULL); ASSERT((IrpContext->Identifier.Type == RFSDICX) && (IrpContext->Identifier.Size == sizeof(RFSD_IRP_CONTEXT))); DeviceObject = IrpContext->DeviceObject; // // This request is not allowed on the main device object // if (DeviceObject == RfsdGlobal->DeviceObject) { Status = STATUS_INVALID_DEVICE_REQUEST; _SEH2_LEAVE; } Vcb = (PRFSD_VCB) DeviceObject->DeviceExtension; ASSERT(Vcb != NULL); ASSERT((Vcb->Identifier.Type == RFSDVCB) && (Vcb->Identifier.Size == sizeof(RFSD_VCB))); ASSERT(IsMounted(Vcb)); if (!ExAcquireResourceSharedLite( &Vcb->MainResource, IrpContext->IsSynchronous )) { Status = STATUS_PENDING; _SEH2_LEAVE; } VcbResourceAcquired = TRUE; Irp = IrpContext->Irp; IoStackLocation = IoGetCurrentIrpStackLocation(Irp); FsInformationClass = IoStackLocation->Parameters.QueryVolume.FsInformationClass; Length = IoStackLocation->Parameters.QueryVolume.Length; Buffer = Irp->AssociatedIrp.SystemBuffer; RtlZeroMemory(Buffer, Length); switch (FsInformationClass) { case FileFsVolumeInformation: { PFILE_FS_VOLUME_INFORMATION FsVolInfo; ULONG VolumeLabelLength; ULONG RequiredLength; if (Length < sizeof(FILE_FS_VOLUME_INFORMATION)) { Status = STATUS_INFO_LENGTH_MISMATCH; _SEH2_LEAVE; } FsVolInfo = (PFILE_FS_VOLUME_INFORMATION) Buffer; FsVolInfo->VolumeCreationTime.QuadPart = 0; FsVolInfo->VolumeSerialNumber = Vcb->Vpb->SerialNumber; VolumeLabelLength = Vcb->Vpb->VolumeLabelLength; FsVolInfo->VolumeLabelLength = VolumeLabelLength; // I don't know what this means FsVolInfo->SupportsObjects = FALSE; RequiredLength = sizeof(FILE_FS_VOLUME_INFORMATION) + VolumeLabelLength - sizeof(WCHAR); if (Length < RequiredLength) { Irp->IoStatus.Information = sizeof(FILE_FS_VOLUME_INFORMATION); Status = STATUS_BUFFER_OVERFLOW; _SEH2_LEAVE; } RtlCopyMemory(FsVolInfo->VolumeLabel, Vcb->Vpb->VolumeLabel, Vcb->Vpb->VolumeLabelLength); Irp->IoStatus.Information = RequiredLength; Status = STATUS_SUCCESS; _SEH2_LEAVE; } case FileFsSizeInformation: { PFILE_FS_SIZE_INFORMATION FsSizeInfo; if (Length < sizeof(FILE_FS_SIZE_INFORMATION)) { Status = STATUS_INFO_LENGTH_MISMATCH; _SEH2_LEAVE; } FsSizeInfo = (PFILE_FS_SIZE_INFORMATION) Buffer; FsSizeInfo->TotalAllocationUnits.QuadPart = Vcb->SuperBlock->s_blocks_count; FsSizeInfo->AvailableAllocationUnits.QuadPart = Vcb->SuperBlock->s_free_blocks_count; FsSizeInfo->SectorsPerAllocationUnit = Vcb->BlockSize / Vcb->DiskGeometry.BytesPerSector; FsSizeInfo->BytesPerSector = Vcb->DiskGeometry.BytesPerSector; Irp->IoStatus.Information = sizeof(FILE_FS_SIZE_INFORMATION); Status = STATUS_SUCCESS; _SEH2_LEAVE; } case FileFsDeviceInformation: { PFILE_FS_DEVICE_INFORMATION FsDevInfo; if (Length < sizeof(FILE_FS_DEVICE_INFORMATION)) { Status = STATUS_INFO_LENGTH_MISMATCH; _SEH2_LEAVE; } FsDevInfo = (PFILE_FS_DEVICE_INFORMATION) Buffer; FsDevInfo->DeviceType = Vcb->TargetDeviceObject->DeviceType; if (FsDevInfo->DeviceType != FILE_DEVICE_DISK) { DbgBreak(); } FsDevInfo->Characteristics = Vcb->TargetDeviceObject->Characteristics; if (FlagOn(Vcb->Flags, VCB_READ_ONLY)) { SetFlag( FsDevInfo->Characteristics, FILE_READ_ONLY_DEVICE ); } Irp->IoStatus.Information = sizeof(FILE_FS_DEVICE_INFORMATION); Status = STATUS_SUCCESS; _SEH2_LEAVE; } case FileFsAttributeInformation: { PFILE_FS_ATTRIBUTE_INFORMATION FsAttrInfo; ULONG RequiredLength; if (Length < sizeof(FILE_FS_ATTRIBUTE_INFORMATION)) { Status = STATUS_INFO_LENGTH_MISMATCH; _SEH2_LEAVE; } FsAttrInfo = (PFILE_FS_ATTRIBUTE_INFORMATION) Buffer; FsAttrInfo->FileSystemAttributes = FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES; FsAttrInfo->MaximumComponentNameLength = RFSD_NAME_LEN; FsAttrInfo->FileSystemNameLength = 10; RequiredLength = sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + 10 - sizeof(WCHAR); if (Length < RequiredLength) { Irp->IoStatus.Information = sizeof(FILE_FS_ATTRIBUTE_INFORMATION); Status = STATUS_BUFFER_OVERFLOW; _SEH2_LEAVE; } RtlCopyMemory( FsAttrInfo->FileSystemName, L"RFSD\0", 10); Irp->IoStatus.Information = RequiredLength; Status = STATUS_SUCCESS; _SEH2_LEAVE; } #if (_WIN32_WINNT >= 0x0500) case FileFsFullSizeInformation: { PFILE_FS_FULL_SIZE_INFORMATION PFFFSI; if (Length < sizeof(FILE_FS_FULL_SIZE_INFORMATION)) { Status = STATUS_INFO_LENGTH_MISMATCH; _SEH2_LEAVE; } PFFFSI = (PFILE_FS_FULL_SIZE_INFORMATION) Buffer; /* typedef struct _FILE_FS_FULL_SIZE_INFORMATION { LARGE_INTEGER TotalAllocationUnits; LARGE_INTEGER CallerAvailableAllocationUnits; LARGE_INTEGER ActualAvailableAllocationUnits; ULONG SectorsPerAllocationUnit; ULONG BytesPerSector; } FILE_FS_FULL_SIZE_INFORMATION, *PFILE_FS_FULL_SIZE_INFORMATION; */ { PFFFSI->TotalAllocationUnits.QuadPart = Vcb->SuperBlock->s_blocks_count; PFFFSI->CallerAvailableAllocationUnits.QuadPart = Vcb->SuperBlock->s_free_blocks_count; /* - Vcb->SuperBlock->s_r_blocks_count; */ PFFFSI->ActualAvailableAllocationUnits.QuadPart = Vcb->SuperBlock->s_free_blocks_count; } PFFFSI->SectorsPerAllocationUnit = Vcb->BlockSize / Vcb->DiskGeometry.BytesPerSector; PFFFSI->BytesPerSector = Vcb->DiskGeometry.BytesPerSector; Irp->IoStatus.Information = sizeof(FILE_FS_FULL_SIZE_INFORMATION); Status = STATUS_SUCCESS; _SEH2_LEAVE; } #endif // (_WIN32_WINNT >= 0x0500) default: Status = STATUS_INVALID_INFO_CLASS; } } _SEH2_FINALLY { if (VcbResourceAcquired) { ExReleaseResourceForThreadLite( &Vcb->MainResource, ExGetCurrentResourceThread() ); } if (!IrpContext->ExceptionInProgress) { if (Status == STATUS_PENDING) { RfsdQueueRequest(IrpContext); } else { RfsdCompleteIrpContext(IrpContext, Status); } } } _SEH2_END; return Status; }
NTSTATUS Ext2QueryVolumeInformation (IN PEXT2_IRP_CONTEXT IrpContext) { PDEVICE_OBJECT DeviceObject; PEXT2_VCB Vcb = NULL; PIRP Irp = NULL; PIO_STACK_LOCATION IoStackLocation = NULL; PVOID Buffer; ULONG Length; NTSTATUS Status = STATUS_UNSUCCESSFUL; FS_INFORMATION_CLASS FsInformationClass; BOOLEAN VcbResourceAcquired = FALSE; __try { ASSERT(IrpContext != NULL); ASSERT((IrpContext->Identifier.Type == EXT2ICX) && (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT))); DeviceObject = IrpContext->DeviceObject; // // This request is not allowed on the main device object // if (IsExt2FsDevice(DeviceObject)) { Status = STATUS_INVALID_DEVICE_REQUEST; __leave; } Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension; ASSERT(Vcb != NULL); ASSERT((Vcb->Identifier.Type == EXT2VCB) && (Vcb->Identifier.Size == sizeof(EXT2_VCB))); if (!IsMounted(Vcb)) { Status = STATUS_VOLUME_DISMOUNTED; __leave; } if (!ExAcquireResourceSharedLite( &Vcb->MainResource, IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) { Status = STATUS_PENDING; __leave; } VcbResourceAcquired = TRUE; Irp = IrpContext->Irp; IoStackLocation = IoGetCurrentIrpStackLocation(Irp); FsInformationClass = IoStackLocation->Parameters.QueryVolume.FsInformationClass; Length = IoStackLocation->Parameters.QueryVolume.Length; Buffer = Irp->AssociatedIrp.SystemBuffer; RtlZeroMemory(Buffer, Length); switch (FsInformationClass) { case FileFsVolumeInformation: { PFILE_FS_VOLUME_INFORMATION FsVolInfo; ULONG VolumeLabelLength; ULONG RequiredLength; if (Length < sizeof(FILE_FS_VOLUME_INFORMATION)) { Status = STATUS_BUFFER_OVERFLOW; __leave; } FsVolInfo = (PFILE_FS_VOLUME_INFORMATION) Buffer; FsVolInfo->VolumeCreationTime.QuadPart = 0; FsVolInfo->VolumeSerialNumber = Vcb->Vpb->SerialNumber; VolumeLabelLength = Vcb->Vpb->VolumeLabelLength; FsVolInfo->VolumeLabelLength = VolumeLabelLength; /* We don't support ObjectId */ FsVolInfo->SupportsObjects = FALSE; RequiredLength = sizeof(FILE_FS_VOLUME_INFORMATION) + VolumeLabelLength - sizeof(WCHAR); if (Length < RequiredLength) { Irp->IoStatus.Information = sizeof(FILE_FS_VOLUME_INFORMATION); Status = STATUS_BUFFER_OVERFLOW; __leave; } RtlCopyMemory(FsVolInfo->VolumeLabel, Vcb->Vpb->VolumeLabel, Vcb->Vpb->VolumeLabelLength); Irp->IoStatus.Information = RequiredLength; Status = STATUS_SUCCESS; } break; case FileFsSizeInformation: { PFILE_FS_SIZE_INFORMATION FsSizeInfo; if (Length < sizeof(FILE_FS_SIZE_INFORMATION)) { Status = STATUS_BUFFER_OVERFLOW; __leave; } FsSizeInfo = (PFILE_FS_SIZE_INFORMATION) Buffer; FsSizeInfo->TotalAllocationUnits.QuadPart = ext3_blocks_count(SUPER_BLOCK); FsSizeInfo->AvailableAllocationUnits.QuadPart = ext3_free_blocks_count(SUPER_BLOCK); FsSizeInfo->SectorsPerAllocationUnit = Vcb->BlockSize / Vcb->DiskGeometry.BytesPerSector; FsSizeInfo->BytesPerSector = Vcb->DiskGeometry.BytesPerSector; Irp->IoStatus.Information = sizeof(FILE_FS_SIZE_INFORMATION); Status = STATUS_SUCCESS; } break; case FileFsDeviceInformation: { PFILE_FS_DEVICE_INFORMATION FsDevInfo; if (Length < sizeof(FILE_FS_DEVICE_INFORMATION)) { Status = STATUS_BUFFER_OVERFLOW; __leave; } FsDevInfo = (PFILE_FS_DEVICE_INFORMATION) Buffer; FsDevInfo->DeviceType = Vcb->TargetDeviceObject->DeviceType; if (FsDevInfo->DeviceType != FILE_DEVICE_DISK) { DbgBreak(); } FsDevInfo->Characteristics = Vcb->TargetDeviceObject->Characteristics; if (IsVcbReadOnly(Vcb)) { SetFlag( FsDevInfo->Characteristics, FILE_READ_ONLY_DEVICE ); } Irp->IoStatus.Information = sizeof(FILE_FS_DEVICE_INFORMATION); Status = STATUS_SUCCESS; } break; case FileFsAttributeInformation: { PFILE_FS_ATTRIBUTE_INFORMATION FsAttrInfo; ULONG RequiredLength; if (Length < sizeof(FILE_FS_ATTRIBUTE_INFORMATION)) { Status = STATUS_BUFFER_OVERFLOW; __leave; } FsAttrInfo = (PFILE_FS_ATTRIBUTE_INFORMATION) Buffer; FsAttrInfo->FileSystemAttributes = FILE_SUPPORTS_HARD_LINKS | FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES | FILE_SUPPORTS_REPARSE_POINTS; if (IsVcbReadOnly(Vcb)) { FsAttrInfo->FileSystemAttributes |= FILE_READ_ONLY_VOLUME; } FsAttrInfo->MaximumComponentNameLength = EXT2_NAME_LEN; FsAttrInfo->FileSystemNameLength = 8; RequiredLength = sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + 8 - sizeof(WCHAR); if (Length < RequiredLength) { Irp->IoStatus.Information = sizeof(FILE_FS_ATTRIBUTE_INFORMATION); Status = STATUS_BUFFER_OVERFLOW; __leave; } if (IsFlagOn(SUPER_BLOCK->s_feature_incompat, EXT4_FEATURE_INCOMPAT_EXTENTS)) { RtlCopyMemory(FsAttrInfo->FileSystemName, L"EXT4\0", 10); } else if (Vcb->IsExt3fs) { RtlCopyMemory(FsAttrInfo->FileSystemName, L"EXT3\0", 10); } else { RtlCopyMemory(FsAttrInfo->FileSystemName, L"EXT2\0", 10); } Irp->IoStatus.Information = RequiredLength; Status = STATUS_SUCCESS; } break; #if (_WIN32_WINNT >= 0x0500) case FileFsFullSizeInformation: { PFILE_FS_FULL_SIZE_INFORMATION PFFFSI; if (Length < sizeof(FILE_FS_FULL_SIZE_INFORMATION)) { Status = STATUS_BUFFER_OVERFLOW; __leave; } PFFFSI = (PFILE_FS_FULL_SIZE_INFORMATION) Buffer; /* typedef struct _FILE_FS_FULL_SIZE_INFORMATION { LARGE_INTEGER TotalAllocationUnits; LARGE_INTEGER CallerAvailableAllocationUnits; LARGE_INTEGER ActualAvailableAllocationUnits; ULONG SectorsPerAllocationUnit; ULONG BytesPerSector; } FILE_FS_FULL_SIZE_INFORMATION, *PFILE_FS_FULL_SIZE_INFORMATION; */ { PFFFSI->TotalAllocationUnits.QuadPart = ext3_blocks_count(SUPER_BLOCK); PFFFSI->CallerAvailableAllocationUnits.QuadPart = ext3_free_blocks_count(SUPER_BLOCK); /* - Vcb->SuperBlock->s_r_blocks_count; */ PFFFSI->ActualAvailableAllocationUnits.QuadPart = ext3_free_blocks_count(SUPER_BLOCK); } PFFFSI->SectorsPerAllocationUnit = Vcb->BlockSize / Vcb->DiskGeometry.BytesPerSector; PFFFSI->BytesPerSector = Vcb->DiskGeometry.BytesPerSector; Irp->IoStatus.Information = sizeof(FILE_FS_FULL_SIZE_INFORMATION); Status = STATUS_SUCCESS; } break; #endif // (_WIN32_WINNT >= 0x0500) default: Status = STATUS_INVALID_INFO_CLASS; break; } } __finally { if (VcbResourceAcquired) { ExReleaseResourceLite(&Vcb->MainResource); } if (!IrpContext->ExceptionInProgress) { if (Status == STATUS_PENDING) { Ext2QueueRequest(IrpContext); } else { Ext2CompleteIrpContext(IrpContext, Status); } } } return Status; }