/* * FFS File System Driver for Windows * * volinfo.c * * 2004.5.6 ~ * * Lee Jae-Hong, http://www.pyrasis.com * * See License.txt * */ #include "ntifs.h" #include "ffsdrv.h" /* Globals */ extern PFFS_GLOBAL FFSGlobal; /* Definitions */ #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, FFSQueryVolumeInformation) #pragma alloc_text(PAGE, FFSSetVolumeInformation) #endif __drv_mustHoldCriticalRegion NTSTATUS FFSQueryVolumeInformation( IN PFFS_IRP_CONTEXT IrpContext) { PDEVICE_OBJECT DeviceObject; NTSTATUS Status = STATUS_UNSUCCESSFUL; PFFS_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 == FFSICX) && (IrpContext->Identifier.Size == sizeof(FFS_IRP_CONTEXT))); DeviceObject = IrpContext->DeviceObject; // // This request is not allowed on the main device object // if (DeviceObject == FFSGlobal->DeviceObject) { Status = STATUS_INVALID_DEVICE_REQUEST; _SEH2_LEAVE; } Vcb = (PFFS_VCB)DeviceObject->DeviceExtension; ASSERT(Vcb != NULL); ASSERT((Vcb->Identifier.Type == FFSVCB) && (Vcb->Identifier.Size == sizeof(FFS_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; { if (FS_VERSION == 1) { FsSizeInfo->TotalAllocationUnits.QuadPart = (Vcb->ffs_super_block->fs_old_size / 8); FsSizeInfo->AvailableAllocationUnits.QuadPart = (Vcb->ffs_super_block->fs_old_cstotal.cs_nbfree / 8); } else { FsSizeInfo->TotalAllocationUnits.QuadPart = (Vcb->ffs_super_block->fs_size / 8); FsSizeInfo->AvailableAllocationUnits.QuadPart = (Vcb->ffs_super_block->fs_cstotal.cs_nbfree / 8); } } 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; 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 = FFS_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"FFS\0", 8); 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; */ { if (FS_VERSION == 1) { PFFFSI->TotalAllocationUnits.QuadPart = (Vcb->ffs_super_block->fs_old_size / 8); PFFFSI->CallerAvailableAllocationUnits.QuadPart = (Vcb->ffs_super_block->fs_old_cstotal.cs_nbfree / 8); PFFFSI->ActualAvailableAllocationUnits.QuadPart = (Vcb->ffs_super_block->fs_old_cstotal.cs_nbfree / 8); } else { PFFFSI->TotalAllocationUnits.QuadPart = (Vcb->ffs_super_block->fs_size / 8); PFFFSI->CallerAvailableAllocationUnits.QuadPart = (Vcb->ffs_super_block->fs_cstotal.cs_nbfree / 8); PFFFSI->ActualAvailableAllocationUnits.QuadPart = (Vcb->ffs_super_block->fs_cstotal.cs_nbfree / 8); } } 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) { FFSQueueRequest(IrpContext); } else { FFSCompleteIrpContext(IrpContext, Status); } } } _SEH2_END; return Status; } #if !FFS_READ_ONLY __drv_mustHoldCriticalRegion NTSTATUS FFSSetVolumeInformation( IN PFFS_IRP_CONTEXT IrpContext) { PDEVICE_OBJECT DeviceObject; NTSTATUS Status = STATUS_UNSUCCESSFUL; PFFS_VCB Vcb; PIRP Irp; PIO_STACK_LOCATION IoStackLocation; FS_INFORMATION_CLASS FsInformationClass; PAGED_CODE(); _SEH2_TRY { ASSERT(IrpContext != NULL); ASSERT((IrpContext->Identifier.Type == FFSICX) && (IrpContext->Identifier.Size == sizeof(FFS_IRP_CONTEXT))); DeviceObject = IrpContext->DeviceObject; // // This request is not allowed on the main device object // if (DeviceObject == FFSGlobal->DeviceObject) { Status = STATUS_INVALID_DEVICE_REQUEST; _SEH2_LEAVE; } Vcb = (PFFS_VCB)DeviceObject->DeviceExtension; ASSERT(Vcb != NULL); ASSERT((Vcb->Identifier.Type == FFSVCB) && (Vcb->Identifier.Size == sizeof(FFS_VCB))); ASSERT(IsMounted(Vcb)); if (IsFlagOn(Vcb->Flags, VCB_READ_ONLY)) { Status = STATUS_MEDIA_WRITE_PROTECTED; _SEH2_LEAVE; } Irp = IrpContext->Irp; IoStackLocation = IoGetCurrentIrpStackLocation(Irp); //Notes: SetVolume is not defined in ntddk.h of win2k ddk, // But it's same to QueryVolume .... FsInformationClass = IoStackLocation->Parameters./*SetVolume*/QueryVolume.FsInformationClass; switch (FsInformationClass) { case FileFsLabelInformation: { PFILE_FS_LABEL_INFORMATION VolLabelInfo = NULL; ULONG VolLabelLen; UNICODE_STRING LabelName ; OEM_STRING OemName; VolLabelInfo = (PFILE_FS_LABEL_INFORMATION)Irp->AssociatedIrp.SystemBuffer; VolLabelLen = VolLabelInfo->VolumeLabelLength; if(VolLabelLen > (16 * sizeof(WCHAR))) { Status = STATUS_INVALID_VOLUME_LABEL; _SEH2_LEAVE; } RtlCopyMemory(Vcb->Vpb->VolumeLabel, VolLabelInfo->VolumeLabel, VolLabelLen); RtlZeroMemory(Vcb->ffs_super_block->fs_volname, 16); LabelName.Buffer = VolLabelInfo->VolumeLabel; LabelName.MaximumLength = (USHORT)16 * sizeof(WCHAR); LabelName.Length = (USHORT)VolLabelLen; OemName.Buffer = SUPER_BLOCK->fs_volname; OemName.Length = 0; OemName.MaximumLength = 16; FFSUnicodeToOEM(&OemName, &LabelName); Vcb->Vpb->VolumeLabelLength = (USHORT)VolLabelLen; if (FFSSaveSuper(IrpContext, Vcb)) { Status = STATUS_SUCCESS; } Irp->IoStatus.Information = 0; } break; default: Status = STATUS_INVALID_INFO_CLASS; } } _SEH2_FINALLY { if (!IrpContext->ExceptionInProgress) { if (Status == STATUS_PENDING) { FFSQueueRequest(IrpContext); } else { FFSCompleteIrpContext(IrpContext, Status); } } } _SEH2_END; return Status; } #endif // !FFS_READ_ONLY