NTSTATUS VfatDirectoryControl (PVFAT_IRP_CONTEXT IrpContext) /* * FUNCTION: directory control : read/write directory informations */ { NTSTATUS RC = STATUS_SUCCESS; IrpContext->Irp->IoStatus.Information = 0; switch (IrpContext->MinorFunction) { case IRP_MN_QUERY_DIRECTORY: RC = DoQuery (IrpContext); break; case IRP_MN_NOTIFY_CHANGE_DIRECTORY: DPRINT (" vfat, dir : change\n"); RC = STATUS_NOT_IMPLEMENTED; break; default: // error DbgPrint ("unexpected minor function %x in VFAT driver\n", IrpContext->MinorFunction); RC = STATUS_INVALID_DEVICE_REQUEST; break; } if (RC == STATUS_PENDING) { RC = VfatQueueRequest(IrpContext); } else { IrpContext->Irp->IoStatus.Status = RC; IoCompleteRequest (IrpContext->Irp, IO_NO_INCREMENT); VfatFreeIrpContext(IrpContext); } return RC; }
/* * FUNCTION: Set the specified volume information */ NTSTATUS VfatSetVolumeInformation( PVFAT_IRP_CONTEXT IrpContext) { FS_INFORMATION_CLASS FsInformationClass; NTSTATUS Status = STATUS_SUCCESS; PVOID SystemBuffer; ULONG BufferLength; PIO_STACK_LOCATION Stack = IrpContext->Stack; /* PRECONDITION */ ASSERT(IrpContext); DPRINT("VfatSetVolumeInformation(IrpContext %p)\n", IrpContext); if (!ExAcquireResourceExclusiveLite(&((PDEVICE_EXTENSION)IrpContext->DeviceObject->DeviceExtension)->DirResource, (BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT))) { return VfatQueueRequest(IrpContext); } FsInformationClass = Stack->Parameters.SetVolume.FsInformationClass; BufferLength = Stack->Parameters.SetVolume.Length; SystemBuffer = IrpContext->Irp->AssociatedIrp.SystemBuffer; DPRINT("FsInformationClass %d\n", FsInformationClass); DPRINT("BufferLength %u\n", BufferLength); DPRINT("SystemBuffer %p\n", SystemBuffer); switch (FsInformationClass) { case FileFsLabelInformation: Status = FsdSetFsLabelInformation(IrpContext->DeviceObject, SystemBuffer); break; default: Status = STATUS_NOT_SUPPORTED; } ExReleaseResourceLite(&((PDEVICE_EXTENSION)IrpContext->DeviceObject->DeviceExtension)->DirResource); IrpContext->Irp->IoStatus.Status = Status; IrpContext->Irp->IoStatus.Information = 0; IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT); VfatFreeIrpContext(IrpContext); return Status; }
NTSTATUS VfatFlush( PVFAT_IRP_CONTEXT IrpContext) { NTSTATUS Status; PVFATFCB Fcb; /* This request is not allowed on the main device object. */ if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject) { Status = STATUS_INVALID_DEVICE_REQUEST; goto ByeBye; } Fcb = (PVFATFCB)IrpContext->FileObject->FsContext; ASSERT(Fcb); if (Fcb->Flags & FCB_IS_VOLUME) { ExAcquireResourceExclusiveLite(&IrpContext->DeviceExt->DirResource, TRUE); Status = VfatFlushVolume(IrpContext->DeviceExt, Fcb); ExReleaseResourceLite(&IrpContext->DeviceExt->DirResource); } else { ExAcquireResourceExclusiveLite(&Fcb->MainResource, TRUE); Status = VfatFlushFile(IrpContext->DeviceExt, Fcb); ExReleaseResourceLite (&Fcb->MainResource); } ByeBye: IrpContext->Irp->IoStatus.Status = Status; IrpContext->Irp->IoStatus.Information = 0; IoCompleteRequest (IrpContext->Irp, IO_NO_INCREMENT); VfatFreeIrpContext(IrpContext); return Status; }
/* * FUNCTION: Closes a file */ NTSTATUS VfatClose( PVFAT_IRP_CONTEXT IrpContext) { NTSTATUS Status; DPRINT("VfatClose(DeviceObject %p, Irp %p)\n", IrpContext->DeviceObject, IrpContext->Irp); if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject) { DPRINT("Closing file system\n"); Status = STATUS_SUCCESS; goto ByeBye; } #if 0 /* There occurs a dead look at the call to CcRosDeleteFileCache/ObDereferenceObject/VfatClose in CmLazyCloseThreadMain if VfatClose is execute asynchronous in a worker thread. */ if (!ExAcquireResourceExclusiveLite(&IrpContext->DeviceExt->DirResource, IrpContext->Flags & IRPCONTEXT_CANWAIT)) #else if (!ExAcquireResourceExclusiveLite(&IrpContext->DeviceExt->DirResource, TRUE)) #endif { return VfatQueueRequest(IrpContext); } Status = VfatCloseFile(IrpContext->DeviceExt, IrpContext->FileObject); ExReleaseResourceLite(&IrpContext->DeviceExt->DirResource); ByeBye: IrpContext->Irp->IoStatus.Status = Status; IrpContext->Irp->IoStatus.Information = 0; IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT); VfatFreeIrpContext(IrpContext); return Status; }
NTSTATUS VfatRead( PVFAT_IRP_CONTEXT IrpContext) { NTSTATUS Status; PVFATFCB Fcb; ULONG Length = 0; ULONG ReturnedLength = 0; PERESOURCE Resource = NULL; LARGE_INTEGER ByteOffset; PVOID Buffer; ULONG BytesPerSector; ASSERT(IrpContext); DPRINT("VfatRead(IrpContext %p)\n", IrpContext); ASSERT(IrpContext->DeviceObject); // This request is not allowed on the main device object if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject) { DPRINT("VfatRead is called with the main device object.\n"); Status = STATUS_INVALID_DEVICE_REQUEST; goto ByeBye; } ASSERT(IrpContext->DeviceExt); ASSERT(IrpContext->FileObject); Fcb = IrpContext->FileObject->FsContext; ASSERT(Fcb); if (Fcb->Flags & FCB_IS_PAGE_FILE) { PFATINFO FatInfo = &IrpContext->DeviceExt->FatInfo; IrpContext->Stack->Parameters.Read.ByteOffset.QuadPart += FatInfo->dataStart * FatInfo->BytesPerSector; IoSkipCurrentIrpStackLocation(IrpContext->Irp); DPRINT("Read from page file, disk offset %I64x\n", IrpContext->Stack->Parameters.Read.ByteOffset.QuadPart); Status = IoCallDriver(IrpContext->DeviceExt->StorageDevice, IrpContext->Irp); VfatFreeIrpContext(IrpContext); return Status; } DPRINT("<%wZ>\n", &Fcb->PathNameU); ByteOffset = IrpContext->Stack->Parameters.Read.ByteOffset; Length = IrpContext->Stack->Parameters.Read.Length; BytesPerSector = IrpContext->DeviceExt->FatInfo.BytesPerSector; /* fail if file is a directory and no paged read */ if (*Fcb->Attributes & FILE_ATTRIBUTE_DIRECTORY && !(IrpContext->Irp->Flags & IRP_PAGING_IO)) { Status = STATUS_INVALID_PARAMETER; goto ByeBye; } DPRINT("'%wZ', Offset: %u, Length %u\n", &Fcb->PathNameU, ByteOffset.u.LowPart, Length); if (ByteOffset.u.HighPart && !(Fcb->Flags & FCB_IS_VOLUME)) { Status = STATUS_INVALID_PARAMETER; goto ByeBye; } if (ByteOffset.QuadPart >= Fcb->RFCB.FileSize.QuadPart) { IrpContext->Irp->IoStatus.Information = 0; Status = STATUS_END_OF_FILE; goto ByeBye; } if (IrpContext->Irp->Flags & (IRP_PAGING_IO | IRP_NOCACHE) || (Fcb->Flags & FCB_IS_VOLUME)) { if (ByteOffset.u.LowPart % BytesPerSector != 0 || Length % BytesPerSector != 0) { DPRINT("%u %u\n", ByteOffset.u.LowPart, Length); // non cached read must be sector aligned Status = STATUS_INVALID_PARAMETER; goto ByeBye; } } if (Length == 0) { IrpContext->Irp->IoStatus.Information = 0; Status = STATUS_SUCCESS; goto ByeBye; } if (Fcb->Flags & FCB_IS_VOLUME) { Resource = &IrpContext->DeviceExt->DirResource; } else if (IrpContext->Irp->Flags & IRP_PAGING_IO) { Resource = &Fcb->PagingIoResource; } else { Resource = &Fcb->MainResource; } if (!ExAcquireResourceSharedLite(Resource, IrpContext->Flags & IRPCONTEXT_CANWAIT ? TRUE : FALSE)) { Resource = NULL; Status = STATUS_PENDING; goto ByeBye; } if (!(IrpContext->Irp->Flags & IRP_PAGING_IO) && FsRtlAreThereCurrentFileLocks(&Fcb->FileLock)) { if (!FsRtlCheckLockForReadAccess(&Fcb->FileLock, IrpContext->Irp)) { Status = STATUS_FILE_LOCK_CONFLICT; goto ByeBye; } } Buffer = VfatGetUserBuffer(IrpContext->Irp); if (!Buffer) { Status = STATUS_INVALID_USER_BUFFER; goto ByeBye; } if (!(IrpContext->Irp->Flags & (IRP_NOCACHE|IRP_PAGING_IO)) && !(Fcb->Flags & (FCB_IS_PAGE_FILE|FCB_IS_VOLUME))) { // cached read Status = STATUS_SUCCESS; if (ByteOffset.u.LowPart + Length > Fcb->RFCB.FileSize.u.LowPart) { Length = Fcb->RFCB.FileSize.u.LowPart - ByteOffset.u.LowPart; Status = /*STATUS_END_OF_FILE*/STATUS_SUCCESS; } _SEH2_TRY { if (IrpContext->FileObject->PrivateCacheMap == NULL) { CcInitializeCacheMap(IrpContext->FileObject, (PCC_FILE_SIZES)(&Fcb->RFCB.AllocationSize), FALSE, &(VfatGlobalData->CacheMgrCallbacks), Fcb); } if (!CcCopyRead(IrpContext->FileObject, &ByteOffset, Length, (IrpContext->Flags & IRPCONTEXT_CANWAIT) != 0, Buffer, &IrpContext->Irp->IoStatus)) { ASSERT((IrpContext->Flags & IRPCONTEXT_CANWAIT) == 0); Status = STATUS_PENDING; goto ByeBye; } } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { Status = _SEH2_GetExceptionCode(); goto ByeBye; } _SEH2_END; if (!NT_SUCCESS(IrpContext->Irp->IoStatus.Status)) { Status = IrpContext->Irp->IoStatus.Status; } }
NTSTATUS VfatFileSystemControl(PVFAT_IRP_CONTEXT IrpContext) /* * FUNCTION: File system control */ { NTSTATUS Status; DPRINT("VfatFileSystemControl(IrpContext %p)\n", IrpContext); ASSERT(IrpContext); ASSERT(IrpContext->Irp); ASSERT(IrpContext->Stack); IrpContext->Irp->IoStatus.Information = 0; switch (IrpContext->MinorFunction) { case IRP_MN_KERNEL_CALL: case IRP_MN_USER_FS_REQUEST: switch(IrpContext->Stack->Parameters.DeviceIoControl.IoControlCode) { case FSCTL_GET_VOLUME_BITMAP: Status = VfatGetVolumeBitmap(IrpContext); break; case FSCTL_GET_RETRIEVAL_POINTERS: Status = VfatGetRetrievalPointers(IrpContext); break; case FSCTL_MOVE_FILE: Status = VfatMoveFile(IrpContext); break; case FSCTL_IS_VOLUME_DIRTY: Status = VfatIsVolumeDirty(IrpContext); break; case FSCTL_MARK_VOLUME_DIRTY: Status = VfatMarkVolumeDirty(IrpContext); break; default: Status = STATUS_INVALID_DEVICE_REQUEST; } break; case IRP_MN_MOUNT_VOLUME: Status = VfatMount(IrpContext); break; case IRP_MN_VERIFY_VOLUME: DPRINT("VFATFS: IRP_MN_VERIFY_VOLUME\n"); Status = VfatVerify(IrpContext); break; default: DPRINT("VFAT FSC: MinorFunction %d\n", IrpContext->MinorFunction); Status = STATUS_INVALID_DEVICE_REQUEST; break; } IrpContext->Irp->IoStatus.Status = Status; IoCompleteRequest (IrpContext->Irp, IO_NO_INCREMENT); VfatFreeIrpContext(IrpContext); return (Status); }
NTSTATUS VfatWrite( PVFAT_IRP_CONTEXT IrpContext) { PVFATFCB Fcb; PERESOURCE Resource = NULL; LARGE_INTEGER ByteOffset; LARGE_INTEGER OldFileSize; NTSTATUS Status = STATUS_SUCCESS; ULONG Length = 0; PVOID Buffer; ULONG BytesPerSector; ASSERT(IrpContext); DPRINT("VfatWrite(IrpContext %p)\n", IrpContext); ASSERT(IrpContext->DeviceObject); // This request is not allowed on the main device object if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject) { DPRINT("VfatWrite is called with the main device object.\n"); Status = STATUS_INVALID_DEVICE_REQUEST; goto ByeBye; } ASSERT(IrpContext->DeviceExt); ASSERT(IrpContext->FileObject); Fcb = IrpContext->FileObject->FsContext; ASSERT(Fcb); if (Fcb->Flags & FCB_IS_PAGE_FILE) { PFATINFO FatInfo = &IrpContext->DeviceExt->FatInfo; IrpContext->Stack->Parameters.Write.ByteOffset.QuadPart += FatInfo->dataStart * FatInfo->BytesPerSector; IoSkipCurrentIrpStackLocation(IrpContext->Irp); DPRINT("Write to page file, disk offset %I64x\n", IrpContext->Stack->Parameters.Write.ByteOffset.QuadPart); Status = IoCallDriver(IrpContext->DeviceExt->StorageDevice, IrpContext->Irp); VfatFreeIrpContext(IrpContext); return Status; } DPRINT("<%wZ>\n", &Fcb->PathNameU); /* fail if file is a directory and no paged read */ if (*Fcb->Attributes & FILE_ATTRIBUTE_DIRECTORY && !(IrpContext->Irp->Flags & IRP_PAGING_IO)) { Status = STATUS_INVALID_PARAMETER; goto ByeBye; } ByteOffset = IrpContext->Stack->Parameters.Write.ByteOffset; if (ByteOffset.u.LowPart == FILE_WRITE_TO_END_OF_FILE && ByteOffset.u.HighPart == -1) { ByteOffset.QuadPart = Fcb->RFCB.FileSize.QuadPart; } Length = IrpContext->Stack->Parameters.Write.Length; BytesPerSector = IrpContext->DeviceExt->FatInfo.BytesPerSector; if (ByteOffset.u.HighPart && !(Fcb->Flags & FCB_IS_VOLUME)) { Status = STATUS_INVALID_PARAMETER; goto ByeBye; } if (Fcb->Flags & (FCB_IS_FAT | FCB_IS_VOLUME) || vfatDirEntryGetFirstCluster(IrpContext->DeviceExt, &Fcb->entry) == 1) { if (ByteOffset.QuadPart + Length > Fcb->RFCB.FileSize.QuadPart) { // we can't extend the FAT, the volume or the root on FAT12/FAT16 Status = STATUS_END_OF_FILE; goto ByeBye; } } if (IrpContext->Irp->Flags & (IRP_PAGING_IO|IRP_NOCACHE) || (Fcb->Flags & FCB_IS_VOLUME)) { if (ByteOffset.u.LowPart % BytesPerSector != 0 || Length % BytesPerSector != 0) { // non cached write must be sector aligned Status = STATUS_INVALID_PARAMETER; goto ByeBye; } } if (Length == 0) { /* FIXME: Update last write time */ IrpContext->Irp->IoStatus.Information = 0; Status = STATUS_SUCCESS; goto ByeBye; } if (IrpContext->Irp->Flags & IRP_PAGING_IO) { if (ByteOffset.u.LowPart + Length > Fcb->RFCB.AllocationSize.u.LowPart) { Status = STATUS_INVALID_PARAMETER; goto ByeBye; } if (ByteOffset.u.LowPart + Length > ROUND_UP(Fcb->RFCB.AllocationSize.u.LowPart, BytesPerSector)) { Length = ROUND_UP(Fcb->RFCB.FileSize.u.LowPart, BytesPerSector) - ByteOffset.u.LowPart; } } if (Fcb->Flags & FCB_IS_VOLUME) { Resource = &IrpContext->DeviceExt->DirResource; } else if (IrpContext->Irp->Flags & IRP_PAGING_IO) { Resource = &Fcb->PagingIoResource; } else { Resource = &Fcb->MainResource; } if (Fcb->Flags & FCB_IS_PAGE_FILE) { if (!ExAcquireResourceSharedLite(Resource, (BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT))) { Resource = NULL; Status = STATUS_PENDING; goto ByeBye; } } else { if (!ExAcquireResourceExclusiveLite(Resource, (BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT))) { Resource = NULL; Status = STATUS_PENDING; goto ByeBye; } } if (!(IrpContext->Irp->Flags & IRP_PAGING_IO) && FsRtlAreThereCurrentFileLocks(&Fcb->FileLock)) { if (!FsRtlCheckLockForWriteAccess(&Fcb->FileLock, IrpContext->Irp)) { Status = STATUS_FILE_LOCK_CONFLICT; goto ByeBye; } } if (!(IrpContext->Flags & IRPCONTEXT_CANWAIT) && !(Fcb->Flags & FCB_IS_VOLUME)) { if (ByteOffset.u.LowPart + Length > Fcb->RFCB.AllocationSize.u.LowPart) { Status = STATUS_PENDING; goto ByeBye; } } OldFileSize = Fcb->RFCB.FileSize; Buffer = VfatGetUserBuffer(IrpContext->Irp); if (!Buffer) { Status = STATUS_INVALID_USER_BUFFER; goto ByeBye; } if (!(Fcb->Flags & (FCB_IS_FAT|FCB_IS_VOLUME)) && !(IrpContext->Irp->Flags & IRP_PAGING_IO) && ByteOffset.u.LowPart + Length > Fcb->RFCB.FileSize.u.LowPart) { LARGE_INTEGER AllocationSize; AllocationSize.QuadPart = ByteOffset.u.LowPart + Length; Status = VfatSetAllocationSizeInformation(IrpContext->FileObject, Fcb, IrpContext->DeviceExt, &AllocationSize); if (!NT_SUCCESS (Status)) { goto ByeBye; } } if (!(IrpContext->Irp->Flags & (IRP_NOCACHE|IRP_PAGING_IO)) && !(Fcb->Flags & (FCB_IS_PAGE_FILE|FCB_IS_VOLUME))) { // cached write if (IrpContext->FileObject->PrivateCacheMap == NULL) { CcInitializeCacheMap(IrpContext->FileObject, (PCC_FILE_SIZES)(&Fcb->RFCB.AllocationSize), FALSE, &VfatGlobalData->CacheMgrCallbacks, Fcb); } if (ByteOffset.QuadPart > OldFileSize.QuadPart) { CcZeroData(IrpContext->FileObject, &OldFileSize, &ByteOffset, TRUE); } if (CcCopyWrite(IrpContext->FileObject, &ByteOffset, Length, 1 /*IrpContext->Flags & IRPCONTEXT_CANWAIT*/, Buffer)) { IrpContext->Irp->IoStatus.Information = Length; Status = STATUS_SUCCESS; } else { Status = STATUS_UNSUCCESSFUL; } } else { // non cached write if (ByteOffset.QuadPart > OldFileSize.QuadPart) { CcZeroData(IrpContext->FileObject, &OldFileSize, &ByteOffset, TRUE); } Status = VfatLockUserBuffer(IrpContext->Irp, Length, IoReadAccess); if (!NT_SUCCESS(Status)) { goto ByeBye; } Status = VfatWriteFileData(IrpContext, Length, ByteOffset); if (NT_SUCCESS(Status)) { IrpContext->Irp->IoStatus.Information = Length; } } if (!(IrpContext->Irp->Flags & IRP_PAGING_IO) && !(Fcb->Flags & (FCB_IS_FAT|FCB_IS_VOLUME))) { if(!(*Fcb->Attributes & FILE_ATTRIBUTE_DIRECTORY)) { LARGE_INTEGER SystemTime; // set dates and times KeQuerySystemTime (&SystemTime); if (Fcb->Flags & FCB_IS_FATX_ENTRY) { FsdSystemTimeToDosDateTime(IrpContext->DeviceExt, &SystemTime, &Fcb->entry.FatX.UpdateDate, &Fcb->entry.FatX.UpdateTime); Fcb->entry.FatX.AccessDate = Fcb->entry.FatX.UpdateDate; Fcb->entry.FatX.AccessTime = Fcb->entry.FatX.UpdateTime; } else { FsdSystemTimeToDosDateTime(IrpContext->DeviceExt, &SystemTime, &Fcb->entry.Fat.UpdateDate, &Fcb->entry.Fat.UpdateTime); Fcb->entry.Fat.AccessDate = Fcb->entry.Fat.UpdateDate; } /* set date and times to dirty */ Fcb->Flags |= FCB_IS_DIRTY; } } ByeBye: if (Resource) { ExReleaseResourceLite(Resource); } if (Status == STATUS_PENDING) { Status = VfatLockUserBuffer(IrpContext->Irp, Length, IoReadAccess); if (NT_SUCCESS(Status)) { Status = VfatQueueRequest(IrpContext); } else { IrpContext->Irp->IoStatus.Status = Status; IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT); VfatFreeIrpContext(IrpContext); } } else { IrpContext->Irp->IoStatus.Status = Status; if (IrpContext->FileObject->Flags & FO_SYNCHRONOUS_IO && !(IrpContext->Irp->Flags & IRP_PAGING_IO) && NT_SUCCESS(Status)) { IrpContext->FileObject->CurrentByteOffset.QuadPart = ByteOffset.QuadPart + IrpContext->Irp->IoStatus.Information; } IoCompleteRequest(IrpContext->Irp, (CCHAR)(NT_SUCCESS(Status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT)); VfatFreeIrpContext(IrpContext); } DPRINT("%x\n", Status); return Status; }
/* * FUNCTION: Retrieve the specified volume information */ NTSTATUS VfatQueryVolumeInformation( PVFAT_IRP_CONTEXT IrpContext) { FS_INFORMATION_CLASS FsInformationClass; NTSTATUS RC = STATUS_SUCCESS; PVOID SystemBuffer; ULONG BufferLength; /* PRECONDITION */ ASSERT(IrpContext); DPRINT("VfatQueryVolumeInformation(IrpContext %p)\n", IrpContext); if (!ExAcquireResourceSharedLite(&((PDEVICE_EXTENSION)IrpContext->DeviceObject->DeviceExtension)->DirResource, (BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT))) { return VfatQueueRequest(IrpContext); } /* INITIALIZATION */ FsInformationClass = IrpContext->Stack->Parameters.QueryVolume.FsInformationClass; BufferLength = IrpContext->Stack->Parameters.QueryVolume.Length; SystemBuffer = IrpContext->Irp->AssociatedIrp.SystemBuffer; DPRINT("FsInformationClass %d\n", FsInformationClass); DPRINT("SystemBuffer %p\n", SystemBuffer); switch (FsInformationClass) { case FileFsVolumeInformation: RC = FsdGetFsVolumeInformation(IrpContext->DeviceObject, SystemBuffer, &BufferLength); break; case FileFsAttributeInformation: RC = FsdGetFsAttributeInformation(IrpContext->DeviceObject->DeviceExtension, SystemBuffer, &BufferLength); break; case FileFsSizeInformation: RC = FsdGetFsSizeInformation(IrpContext->DeviceObject, SystemBuffer, &BufferLength); break; case FileFsDeviceInformation: RC = FsdGetFsDeviceInformation(IrpContext->DeviceObject, SystemBuffer, &BufferLength); break; default: RC = STATUS_NOT_SUPPORTED; } ExReleaseResourceLite(&((PDEVICE_EXTENSION)IrpContext->DeviceObject->DeviceExtension)->DirResource); IrpContext->Irp->IoStatus.Status = RC; if (NT_SUCCESS(RC)) IrpContext->Irp->IoStatus.Information = IrpContext->Stack->Parameters.QueryVolume.Length - BufferLength; else IrpContext->Irp->IoStatus.Information = 0; IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT); VfatFreeIrpContext(IrpContext); return RC; }