X-Git-Url: https://git.reactos.org/?p=reactos.git;a=blobdiff_plain;f=drivers%2Ffilesystems%2Fffs%2Fsrc%2Ffsctl.c;fp=drivers%2Ffilesystems%2Fffs%2Fsrc%2Ffsctl.c;h=251ea88b833d41e08611d33b0a8d58f6dc21bdab;hp=0000000000000000000000000000000000000000;hb=c2c66aff7dacc62d125f2cd61d1167e9a2aa3fd6;hpb=b94e2d8ca0b7bb9c17f624e1b4b7e3e7f5b853ac diff --git a/drivers/filesystems/ffs/src/fsctl.c b/drivers/filesystems/ffs/src/fsctl.c new file mode 100644 index 00000000000..251ea88b833 --- /dev/null +++ b/drivers/filesystems/ffs/src/fsctl.c @@ -0,0 +1,1663 @@ +/* + * FFS File System Driver for Windows + * + * fsctl.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 */ + +BOOLEAN +FFSIsMediaWriteProtected ( + IN PFFS_IRP_CONTEXT IrpContext, + IN PDEVICE_OBJECT TargetDevice); + +#ifdef ALLOC_PRAGMA +//#pragma alloc_text(PAGE, FFSSetVpbFlag) +//#pragma alloc_text(PAGE, FFSClearVpbFlag) +#pragma alloc_text(PAGE, FFSGetPartition) +#pragma alloc_text(PAGE, FFSLoadDiskLabel) +#pragma alloc_text(PAGE, FFSIsHandleCountZero) +#pragma alloc_text(PAGE, FFSLockVcb) +#pragma alloc_text(PAGE, FFSLockVolume) +#pragma alloc_text(PAGE, FFSUnlockVcb) +#pragma alloc_text(PAGE, FFSUnlockVolume) +#pragma alloc_text(PAGE, FFSAllowExtendedDasdIo) +#pragma alloc_text(PAGE, FFSUserFsRequest) +#pragma alloc_text(PAGE, FFSIsMediaWriteProtected) +#pragma alloc_text(PAGE, FFSMountVolume) +#pragma alloc_text(PAGE, FFSCheckDismount) +#pragma alloc_text(PAGE, FFSPurgeVolume) +#pragma alloc_text(PAGE, FFSPurgeFile) +#pragma alloc_text(PAGE, FFSDismountVolume) +#pragma alloc_text(PAGE, FFSIsVolumeMounted) +#pragma alloc_text(PAGE, FFSVerifyVolume) +#pragma alloc_text(PAGE, FFSFileSystemControl) +#endif + + +VOID +FFSSetVpbFlag( + IN PVPB Vpb, + IN USHORT Flag) +{ + KIRQL OldIrql; + + IoAcquireVpbSpinLock(&OldIrql); + + Vpb->Flags |= Flag; + + IoReleaseVpbSpinLock(OldIrql); +} + + +VOID +FFSClearVpbFlag( + IN PVPB Vpb, + IN USHORT Flag) +{ + KIRQL OldIrql; + + IoAcquireVpbSpinLock(&OldIrql); + + Vpb->Flags &= ~Flag; + + IoReleaseVpbSpinLock(OldIrql); +} + + +NTSTATUS +FFSGetPartition( + IN PDEVICE_OBJECT DeviceObject, + OUT ULONGLONG *StartOffset) +{ + CHAR Buffer[2048]; + PIRP Irp; + IO_STATUS_BLOCK IoStatus; + KEVENT Event; + NTSTATUS Status; + PARTITION_INFORMATION *PartInfo; + + PAGED_CODE(); + + if (IsFlagOn(DeviceObject->Characteristics, FILE_FLOPPY_DISKETTE)) + { + *StartOffset = 0; + return STATUS_SUCCESS; + } + + KeInitializeEvent(&Event, NotificationEvent, FALSE); + + Irp = IoBuildDeviceIoControlRequest( + IOCTL_DISK_GET_PARTITION_INFO, + DeviceObject, + NULL, + 0, + Buffer, + 2048, + FALSE, + &Event, + &IoStatus); + + if (!Irp) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + + Status = IoCallDriver(DeviceObject, Irp); + if (!NT_SUCCESS(Status)) + { + return Status; + } + + Status = KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); + if (!NT_SUCCESS(Status)) + { + return Status; + } + + PartInfo = (PARTITION_INFORMATION *)Buffer; + *StartOffset = PartInfo->StartingOffset.QuadPart; + + return Status; +} + + +NTSTATUS +FFSLoadDiskLabel( + PDEVICE_OBJECT DeviceObject, + IN PFFS_VCB Vcb) +{ + NTSTATUS Status; + PFFS_SUPER_BLOCK FFSSb; + PDISKLABEL Disklabel; + int i; + int RootFS_VERSION; + ULONGLONG StartOffset = 0; + ULONGLONG FSOffset = 0; + ULONGLONG FSRootOffset = 0; + + PAGED_CODE(); + + Disklabel = (PDISKLABEL)ExAllocatePoolWithTag(PagedPool, sizeof(DISKLABEL), FFS_POOL_TAG); + + FFSReadDisk(Vcb, (LABELSECTOR * SECTOR_SIZE + LABELOFFSET), sizeof(DISKLABEL), (PVOID)Disklabel, FALSE); + + if (Disklabel->d_magic == DISKMAGIC) + { + KdPrint(("FFSLoadDiskLabel() Disklabel magic ok\n")); + + Status = STATUS_SUCCESS; + } + else + { + KdPrint(("FFSLoadDiskLabel() No BSD disklabel found, trying to find BSD file system on \"normal\" partition.\n")); + + if ((FFSSb = FFSLoadSuper(Vcb, FALSE, FSOffset + SBLOCK_UFS1)) && + (FFSSb->fs_magic == FS_UFS1_MAGIC)) + { + FFSPrint((DBG_VITAL, "FFSLoadDiskLabel() \"normal\" partition of FFSv1 file system is found.\n")); +/* + if ((FFSSb->fs_fsmnt[0] == '/') && (FFSSb->fs_fsmnt[1] == '\0')) + { + FFSGlobal->RootPartition = i; + FSRootOffset = FSOffset; + RootFS_VERSION = 1; + } +*/ + FS_VERSION = 1; + Vcb->FSOffset[0] = 0; + Vcb->PartitionNumber = 0; + Vcb->ffs_super_block = FFSSb; + Status = STATUS_SUCCESS; + return Status; + } + else if ((FFSSb = FFSLoadSuper(Vcb, FALSE, FSOffset + SBLOCK_UFS2)) && + (FFSSb->fs_magic == FS_UFS2_MAGIC)) + { + FFSPrint((DBG_VITAL, "FFSLoadDiskLabel() \"normal\" partition of FFSv2 file system is found.\n")); +/* + if ((FFSSb->fs_fsmnt[0] == '/') && (FFSSb->fs_fsmnt[1] == '\0')) + { + FFSGlobal->RootPartition = i; + FSRootOffset = FSOffset; + RootFS_VERSION = 2; + } +*/ + FS_VERSION = 2; + Vcb->FSOffset[0] = 0; + Vcb->PartitionNumber = 0; + Vcb->ffs_super_block = FFSSb; + Status = STATUS_SUCCESS; + return Status; + } + else + { + KdPrint(("FFSLoadDiskLabel() No BSD file system was found on the \"normal\" partition.\n")); + Status = STATUS_UNRECOGNIZED_VOLUME; + return Status; + } + } + + Status = FFSGetPartition(DeviceObject, &StartOffset); + if (!NT_SUCCESS(Status)) + { + KdPrint(("FFSLoadDiskLabel() Slice info failed, Status %u\n", Status)); + return Status; + } + + Vcb->PartitionNumber = FFSGlobal->PartitionNumber; + + KdPrint(("FFSLoadDiskLabel() Selected BSD Label : %d, StartOffset : %x\n", Vcb->PartitionNumber, StartOffset)); + + for (i = 0; i < MAXPARTITIONS; i++) + { + if (Disklabel->d_partitions[i].p_fstype == FS_BSDFFS) + { + /* Important */ + FSOffset = Disklabel->d_partitions[i].p_offset; + FSOffset = FSOffset * SECTOR_SIZE; + //FSOffset = FSOffset - StartOffset; + Vcb->FSOffset[i] = FSOffset; + /* Important */ + + KdPrint(("FFSLoadDiskLabel() Label %d, FS_BSDFFS, %x\n", i, Vcb->FSOffset[i])); + + if ((FFSSb = FFSLoadSuper(Vcb, FALSE, FSOffset + SBLOCK_UFS1)) && + (FFSSb->fs_magic == FS_UFS1_MAGIC)) + { + FFSPrint((DBG_VITAL, "FFSLoadDiskLabel() Label %d of FFSv1 file system is found.\n", i)); + + if ((FFSSb->fs_fsmnt[0] == '/') && (FFSSb->fs_fsmnt[1] == '\0')) + { + Vcb->RootPartition = i; + FSRootOffset = FSOffset; + RootFS_VERSION = 1; + } + + FS_VERSION = 1; + + if (i == (int)Vcb->PartitionNumber) + { + Vcb->ffs_super_block = FFSSb; + } + + Status = STATUS_SUCCESS; + } + else if ((FFSSb = FFSLoadSuper(Vcb, FALSE, FSOffset + SBLOCK_UFS2)) && + (FFSSb->fs_magic == FS_UFS2_MAGIC)) + { + FFSPrint((DBG_VITAL, "FFSLoadDiskLabel() Label %d of FFSv2 file system is found.\n", i)); + + if ((FFSSb->fs_fsmnt[0] == '/') && (FFSSb->fs_fsmnt[1] == '\0')) + { + Vcb->RootPartition = i; + FSRootOffset = FSOffset; + RootFS_VERSION = 2; + } + + FS_VERSION = 2; + + if (i == (int)Vcb->PartitionNumber) + { + Vcb->ffs_super_block = FFSSb; + } + + Status = STATUS_SUCCESS; + } + } +#if 0 + else if (i == (int)FFSGlobal->PartitionNumber) + { + /* ¼±ÅÃµÈ BSD ÆÄƼ¼ÇÀÌ µð½ºÅ©¿¡ ¾øÀ» °æ¿ì Root ÆÄƼ¼ÇÀ¸·Î ´ëü */ + if (RootFS_VERSION == 1) + { + FFSSb = FFSLoadSuper(Vcb, FALSE, FSRootOffset + SBLOCK_UFS1); + Vcb->ffs_super_block = FFSSb; + FFSGlobal->PartitionNumber = FFSGlobal->RootPartition; + } + else + { + FFSSb = FFSLoadSuper(Vcb, FALSE, FSRootOffset + SBLOCK_UFS2); + Vcb->ffs_super_block = FFSSb; + FFSGlobal->PartitionNumber = FFSGlobal->RootPartition; + } + } +#endif + } + + if (Vcb->ffs_super_block == NULL) + Status = STATUS_UNRECOGNIZED_VOLUME; + + return Status; +} + + +BOOLEAN +FFSIsHandleCountZero( + IN PFFS_VCB Vcb) +{ + PFFS_FCB Fcb; + PLIST_ENTRY List; + + PAGED_CODE(); + + for(List = Vcb->FcbList.Flink; + List != &Vcb->FcbList; + List = List->Flink) + { + Fcb = CONTAINING_RECORD(List, FFS_FCB, Next); + + ASSERT((Fcb->Identifier.Type == FFSFCB) && + (Fcb->Identifier.Size == sizeof(FFS_FCB))); + + FFSPrint((DBG_INFO, "FFSIsHandleCountZero: Inode:%xh File:%S OpenHandleCount=%xh\n", + Fcb->FFSMcb->Inode, Fcb->FFSMcb->ShortName.Buffer, Fcb->OpenHandleCount)); + + if (Fcb->OpenHandleCount) + { + return FALSE; + } + } + + return TRUE; +} + + +NTSTATUS +FFSLockVcb( + IN PFFS_VCB Vcb, + IN PFILE_OBJECT FileObject) +{ + NTSTATUS Status; + + PAGED_CODE(); + + _SEH2_TRY + { + if (FlagOn(Vcb->Flags, VCB_VOLUME_LOCKED)) + { + FFSPrint((DBG_INFO, "FFSLockVolume: Volume is already locked.\n")); + + Status = STATUS_ACCESS_DENIED; + + _SEH2_LEAVE; + } + + if (Vcb->OpenFileHandleCount > (ULONG)(FileObject ? 1 : 0)) + { + FFSPrint((DBG_INFO, "FFSLockVcb: There are still opened files.\n")); + + Status = STATUS_ACCESS_DENIED; + + _SEH2_LEAVE; + } + + if (!FFSIsHandleCountZero(Vcb)) + { + FFSPrint((DBG_INFO, "FFSLockVcb: Thare are still opened files.\n")); + + Status = STATUS_ACCESS_DENIED; + + _SEH2_LEAVE; + } + + SetFlag(Vcb->Flags, VCB_VOLUME_LOCKED); + + FFSSetVpbFlag(Vcb->Vpb, VPB_LOCKED); + + Vcb->LockFile = FileObject; + + FFSPrint((DBG_INFO, "FFSLockVcb: Volume locked.\n")); + + Status = STATUS_SUCCESS; + } + + _SEH2_FINALLY + { + // Nothing + } _SEH2_END; + + return Status; +} + + +__drv_mustHoldCriticalRegion +NTSTATUS +FFSLockVolume( + IN PFFS_IRP_CONTEXT IrpContext) +{ + PIO_STACK_LOCATION IrpSp; + PDEVICE_OBJECT DeviceObject; + PFFS_VCB Vcb = 0; + NTSTATUS Status; + 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; + + Status = STATUS_UNSUCCESSFUL; + + // + // This request is not allowed on the main device object + // + if (DeviceObject == FFSGlobal->DeviceObject) + { + Status = STATUS_INVALID_PARAMETER; + _SEH2_LEAVE; + } + + Vcb = (PFFS_VCB)DeviceObject->DeviceExtension; + + ASSERT(Vcb != NULL); + + ASSERT((Vcb->Identifier.Type == FFSVCB) && + (Vcb->Identifier.Size == sizeof(FFS_VCB))); + + ASSERT(IsMounted(Vcb)); + + IrpSp = IoGetCurrentIrpStackLocation(IrpContext->Irp); + +#if (_WIN32_WINNT >= 0x0500) + CcWaitForCurrentLazyWriterActivity(); +#endif + ExAcquireResourceExclusiveLite( + &Vcb->MainResource, + TRUE); + + VcbResourceAcquired = TRUE; + + Status = FFSLockVcb(Vcb, IrpSp->FileObject); + } + + _SEH2_FINALLY + { + if (VcbResourceAcquired) + { + ExReleaseResourceForThreadLite( + &Vcb->MainResource, + ExGetCurrentResourceThread()); + } + + if (!IrpContext->ExceptionInProgress) + { + FFSCompleteIrpContext(IrpContext, Status); + } + } _SEH2_END; + + return Status; +} + + +NTSTATUS +FFSUnlockVcb( + IN PFFS_VCB Vcb, + IN PFILE_OBJECT FileObject) +{ + NTSTATUS Status; + + PAGED_CODE(); + + _SEH2_TRY + { + if (FileObject && FileObject->FsContext != Vcb) + { + Status = STATUS_NOT_LOCKED; + _SEH2_LEAVE; + } + + if (!FlagOn(Vcb->Flags, VCB_VOLUME_LOCKED)) + { + FFSPrint((DBG_ERROR, ": FFSUnlockVcb: Volume is not locked.\n")); + Status = STATUS_NOT_LOCKED; + _SEH2_LEAVE; + } + + if (Vcb->LockFile == FileObject) + { + ClearFlag(Vcb->Flags, VCB_VOLUME_LOCKED); + + FFSClearVpbFlag(Vcb->Vpb, VPB_LOCKED); + + FFSPrint((DBG_INFO, "FFSUnlockVcb: Volume unlocked.\n")); + + Status = STATUS_SUCCESS; + } + else + { + Status = STATUS_NOT_LOCKED; + } + } + + _SEH2_FINALLY + { + // Nothing + } _SEH2_END; + + return Status; +} + + +__drv_mustHoldCriticalRegion +NTSTATUS +FFSUnlockVolume( + IN PFFS_IRP_CONTEXT IrpContext) +{ + PIO_STACK_LOCATION IrpSp; + PDEVICE_OBJECT DeviceObject; + NTSTATUS Status; + PFFS_VCB Vcb = 0; + 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_PARAMETER; + _SEH2_LEAVE; + } + + Vcb = (PFFS_VCB)DeviceObject->DeviceExtension; + + ASSERT(Vcb != NULL); + + ASSERT((Vcb->Identifier.Type == FFSVCB) && + (Vcb->Identifier.Size == sizeof(FFS_VCB))); + + ASSERT(IsMounted(Vcb)); + + IrpSp = IoGetCurrentIrpStackLocation(IrpContext->Irp); + + ExAcquireResourceExclusiveLite( + &Vcb->MainResource, + TRUE); + + VcbResourceAcquired = TRUE; + + Status = FFSUnlockVcb(Vcb, IrpSp->FileObject); + } + _SEH2_FINALLY + { + if (VcbResourceAcquired) + { + ExReleaseResourceForThreadLite( + &Vcb->MainResource, + ExGetCurrentResourceThread()); + } + + if (!IrpContext->ExceptionInProgress) + { + FFSCompleteIrpContext(IrpContext, Status); + } + } _SEH2_END; + + return Status; +} + + +__drv_mustHoldCriticalRegion +NTSTATUS +FFSInvalidateVolumes( + IN PFFS_IRP_CONTEXT IrpContext) +{ + NTSTATUS Status; + PIRP Irp; + PIO_STACK_LOCATION IrpSp; + + HANDLE Handle; + + PLIST_ENTRY ListEntry; + + PFILE_OBJECT FileObject; + PDEVICE_OBJECT DeviceObject; + BOOLEAN GlobalResourceAcquired = FALSE; + + LUID Privilege = {SE_TCB_PRIVILEGE, 0}; + + _SEH2_TRY + { + Irp = IrpContext->Irp; + IrpSp = IoGetCurrentIrpStackLocation(Irp); + + if (!SeSinglePrivilegeCheck(Privilege, Irp->RequestorMode)) + { + Status = STATUS_PRIVILEGE_NOT_HELD; + _SEH2_LEAVE; + } + + if ( +#if !defined(_GNU_NTIFS_) || defined(__REACTOS__) + IrpSp->Parameters.FileSystemControl.InputBufferLength +#else + ((PEXTENDED_IO_STACK_LOCATION)(IrpSp))-> + Parameters.FileSystemControl.InputBufferLength +#endif + != sizeof(HANDLE)) + { + Status = STATUS_INVALID_PARAMETER; + + _SEH2_LEAVE; + } + + Handle = *(PHANDLE)Irp->AssociatedIrp.SystemBuffer; + + Status = ObReferenceObjectByHandle(Handle, + 0, + *IoFileObjectType, + KernelMode, + (void **)&FileObject, + NULL); + + if (!NT_SUCCESS(Status)) + { + _SEH2_LEAVE; + } + else + { + ObDereferenceObject(FileObject); + DeviceObject = FileObject->DeviceObject; + } + + FFSPrint((DBG_INFO, "FFSInvalidateVolumes: FileObject=%xh ...\n", FileObject)); + + ExAcquireResourceExclusiveLite( + &FFSGlobal->Resource, + TRUE); + + GlobalResourceAcquired = TRUE; + + ListEntry = FFSGlobal->VcbList.Flink; + + while (ListEntry != &FFSGlobal->VcbList) + { + PFFS_VCB Vcb; + + Vcb = CONTAINING_RECORD(ListEntry, FFS_VCB, Next); + + ListEntry = ListEntry->Flink; + + FFSPrint((DBG_INFO, "FFSInvalidateVolumes: Vcb=%xh Vcb->Vpb=%xh...\n", Vcb, Vcb->Vpb)); + if (Vcb->Vpb && (Vcb->Vpb->RealDevice == DeviceObject)) + { + ExAcquireResourceExclusiveLite(&Vcb->MainResource, TRUE); + FFSPrint((DBG_INFO, "FFSInvalidateVolumes: FFSPurgeVolume...\n")); + FFSPurgeVolume(Vcb, FALSE); + ClearFlag(Vcb->Flags, VCB_MOUNTED); + ExReleaseResourceLite(&Vcb->MainResource); + + // + // Vcb is still attached on the list ...... + // + + if (ListEntry->Blink == &Vcb->Next) + { + FFSPrint((DBG_INFO, "FFSInvalidateVolumes: FFSCheckDismount...\n")); + FFSCheckDismount(IrpContext, Vcb, FALSE); + } + } + } + } + + _SEH2_FINALLY + { + if (GlobalResourceAcquired) + { + ExReleaseResourceForThreadLite( + &FFSGlobal->Resource, + ExGetCurrentResourceThread()); + } + + FFSCompleteIrpContext(IrpContext, Status); + } _SEH2_END; + + return Status; +} + + +__drv_mustHoldCriticalRegion +NTSTATUS +FFSAllowExtendedDasdIo( + IN PFFS_IRP_CONTEXT IrpContext) +{ + PIO_STACK_LOCATION IrpSp; + PFFS_VCB Vcb; + PFFS_CCB Ccb; + + PAGED_CODE(); + + IrpSp = IoGetCurrentIrpStackLocation(IrpContext->Irp); + + Vcb = (PFFS_VCB)IrpSp->FileObject->FsContext; + Ccb = (PFFS_CCB)IrpSp->FileObject->FsContext2; + + ASSERT(Vcb != NULL); + + ASSERT((Vcb->Identifier.Type == FFSVCB) && + (Vcb->Identifier.Size == sizeof(FFS_VCB))); + + ASSERT(IsMounted(Vcb)); + + if (Ccb) + { + SetFlag(Ccb->Flags, CCB_ALLOW_EXTENDED_DASD_IO); + + FFSCompleteIrpContext(IrpContext, STATUS_SUCCESS); + + return STATUS_SUCCESS; + } + else + { + return STATUS_INVALID_PARAMETER; + } +} + + +__drv_mustHoldCriticalRegion +NTSTATUS +FFSUserFsRequest( + IN PFFS_IRP_CONTEXT IrpContext) +{ + PIRP Irp; + PIO_STACK_LOCATION IoStackLocation; + ULONG FsControlCode; + NTSTATUS Status; + + PAGED_CODE(); + + ASSERT(IrpContext); + + ASSERT((IrpContext->Identifier.Type == FFSICX) && + (IrpContext->Identifier.Size == sizeof(FFS_IRP_CONTEXT))); + + Irp = IrpContext->Irp; + + IoStackLocation = IoGetCurrentIrpStackLocation(Irp); + +#if !defined(_GNU_NTIFS_) || defined(__REACTOS__) + FsControlCode = + IoStackLocation->Parameters.FileSystemControl.FsControlCode; +#else + FsControlCode = ((PEXTENDED_IO_STACK_LOCATION) + IoStackLocation)->Parameters.FileSystemControl.FsControlCode; +#endif + + switch (FsControlCode) + { + case FSCTL_LOCK_VOLUME: + Status = FFSLockVolume(IrpContext); + break; + + case FSCTL_UNLOCK_VOLUME: + Status = FFSUnlockVolume(IrpContext); + break; + + case FSCTL_DISMOUNT_VOLUME: + Status = FFSDismountVolume(IrpContext); + break; + + case FSCTL_IS_VOLUME_MOUNTED: + Status = FFSIsVolumeMounted(IrpContext); + break; + + case FSCTL_INVALIDATE_VOLUMES: + Status = FFSInvalidateVolumes(IrpContext); + break; + +#if (_WIN32_WINNT >= 0x0500) + case FSCTL_ALLOW_EXTENDED_DASD_IO: + Status = FFSAllowExtendedDasdIo(IrpContext); + break; +#endif //(_WIN32_WINNT >= 0x0500) + + default: + + FFSPrint((DBG_ERROR, "FFSUserFsRequest: Invalid User Request: %xh.\n", FsControlCode)); + Status = STATUS_INVALID_DEVICE_REQUEST; + + FFSCompleteIrpContext(IrpContext, Status); + } + + return Status; +} + + +BOOLEAN +FFSIsMediaWriteProtected( + IN PFFS_IRP_CONTEXT IrpContext, + IN PDEVICE_OBJECT TargetDevice) +{ + PIRP Irp; + KEVENT Event; + NTSTATUS Status; + IO_STATUS_BLOCK IoStatus; + + PAGED_CODE(); + + KeInitializeEvent(&Event, NotificationEvent, FALSE); + + Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_IS_WRITABLE, + TargetDevice, + NULL, + 0, + NULL, + 0, + FALSE, + &Event, + &IoStatus); + + if (Irp == NULL) + { + return FALSE; + } + + SetFlag(IoGetNextIrpStackLocation(Irp)->Flags, SL_OVERRIDE_VERIFY_VOLUME); + + Status = IoCallDriver(TargetDevice, Irp); + + if (Status == STATUS_PENDING) + { + + (VOID) KeWaitForSingleObject(&Event, + Executive, + KernelMode, + FALSE, + (PLARGE_INTEGER)NULL); + + Status = IoStatus.Status; + } + + return (BOOLEAN)(Status == STATUS_MEDIA_WRITE_PROTECTED); +} + + +__drv_mustHoldCriticalRegion +NTSTATUS +FFSMountVolume( + IN PFFS_IRP_CONTEXT IrpContext) +{ + PDEVICE_OBJECT MainDeviceObject; + BOOLEAN GlobalDataResourceAcquired = FALSE; + PIRP Irp; + PIO_STACK_LOCATION IoStackLocation; + PDEVICE_OBJECT TargetDeviceObject; + NTSTATUS Status = STATUS_UNRECOGNIZED_VOLUME; + PDEVICE_OBJECT VolumeDeviceObject = NULL; + PFFS_VCB Vcb; + PFFS_SUPER_BLOCK FFSSb = NULL; + ULONG dwBytes; + DISK_GEOMETRY DiskGeometry; + + PAGED_CODE(); + + _SEH2_TRY + { + ASSERT(IrpContext != NULL); + + ASSERT((IrpContext->Identifier.Type == FFSICX) && + (IrpContext->Identifier.Size == sizeof(FFS_IRP_CONTEXT))); + + MainDeviceObject = IrpContext->DeviceObject; + + // + // Make sure we can wait. + // + + SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT); + + // + // This request is only allowed on the main device object + // + if (MainDeviceObject != FFSGlobal->DeviceObject) + { + Status = STATUS_INVALID_DEVICE_REQUEST; + _SEH2_LEAVE; + } + + ExAcquireResourceExclusiveLite( + &(FFSGlobal->Resource), + TRUE); + + GlobalDataResourceAcquired = TRUE; + + if (FlagOn(FFSGlobal->Flags, FFS_UNLOAD_PENDING)) + { + Status = STATUS_UNRECOGNIZED_VOLUME; + _SEH2_LEAVE; + } + + Irp = IrpContext->Irp; + + IoStackLocation = IoGetCurrentIrpStackLocation(Irp); + + TargetDeviceObject = + IoStackLocation->Parameters.MountVolume.DeviceObject; + + dwBytes = sizeof(DISK_GEOMETRY); + Status = FFSDiskIoControl( + TargetDeviceObject, + IOCTL_DISK_GET_DRIVE_GEOMETRY, + NULL, + 0, + &DiskGeometry, + &dwBytes); + + if (!NT_SUCCESS(Status)) + { + _SEH2_LEAVE; + } + + Status = IoCreateDevice( + MainDeviceObject->DriverObject, + sizeof(FFS_VCB), + NULL, + FILE_DEVICE_DISK_FILE_SYSTEM, + 0, + FALSE, + &VolumeDeviceObject); + + if (!NT_SUCCESS(Status)) + { + _SEH2_LEAVE; + } + + VolumeDeviceObject->StackSize = (CCHAR)(TargetDeviceObject->StackSize + 1); + + if (TargetDeviceObject->AlignmentRequirement > + VolumeDeviceObject->AlignmentRequirement) + { + + VolumeDeviceObject->AlignmentRequirement = + TargetDeviceObject->AlignmentRequirement; + } + + (IoStackLocation->Parameters.MountVolume.Vpb)->DeviceObject = + VolumeDeviceObject; + + Vcb = (PFFS_VCB)VolumeDeviceObject->DeviceExtension; + + RtlZeroMemory(Vcb, sizeof(FFS_VCB)); + + Vcb->Identifier.Type = FFSVCB; + Vcb->Identifier.Size = sizeof(FFS_VCB); + + Vcb->TargetDeviceObject = TargetDeviceObject; + Vcb->DiskGeometry = DiskGeometry; + + Status = FFSLoadDiskLabel(TargetDeviceObject, Vcb); + + if (!NT_SUCCESS(Status)) + { + _SEH2_LEAVE; + } + + + FFSSb = Vcb->ffs_super_block; + + Vcb->BlockSize = FFSSb->fs_bsize; + Vcb->SectorBits = FFSLog2(SECTOR_SIZE); + + Status = FFSInitializeVcb(IrpContext, Vcb, FFSSb, TargetDeviceObject, + VolumeDeviceObject, IoStackLocation->Parameters.MountVolume.Vpb); + + if (NT_SUCCESS(Status)) + { + if (FFSIsMediaWriteProtected(IrpContext, TargetDeviceObject)) + { + SetFlag(Vcb->Flags, VCB_WRITE_PROTECTED); + } + else + { + ClearFlag(Vcb->Flags, VCB_WRITE_PROTECTED); + } + + SetFlag(Vcb->Flags, VCB_MOUNTED); + + FFSInsertVcb(Vcb); + + ClearFlag(VolumeDeviceObject->Flags, DO_DEVICE_INITIALIZING); + } + } + + _SEH2_FINALLY + { + if (GlobalDataResourceAcquired) + { + ExReleaseResourceForThreadLite( + &FFSGlobal->Resource, + ExGetCurrentResourceThread()); + } + + if (!NT_SUCCESS(Status)) + { + if (FFSSb) + { + ExFreePool(FFSSb); + } + + if (VolumeDeviceObject) + { + IoDeleteDevice(VolumeDeviceObject); + } + } + + if (!IrpContext->ExceptionInProgress) + { + if (NT_SUCCESS(Status)) + { + ClearFlag(VolumeDeviceObject->Flags, DO_DEVICE_INITIALIZING); + } + + FFSCompleteIrpContext(IrpContext, Status); + } + } _SEH2_END; + + return Status; +} + + +__drv_mustHoldCriticalRegion +NTSTATUS +FFSVerifyVolume( + IN PFFS_IRP_CONTEXT IrpContext) +{ + PDEVICE_OBJECT DeviceObject; + NTSTATUS Status = STATUS_UNSUCCESSFUL; + PFFS_SUPER_BLOCK FFSSb = NULL; + PFFS_VCB Vcb = 0; + BOOLEAN VcbResourceAcquired = FALSE; + BOOLEAN GlobalResourceAcquired = FALSE; + PIRP Irp; + PIO_STACK_LOCATION IoStackLocation; + ULONG ChangeCount; + ULONG dwReturn; + + 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; + } + + ExAcquireResourceExclusiveLite( + &FFSGlobal->Resource, + TRUE); + + GlobalResourceAcquired = TRUE; + + Vcb = (PFFS_VCB)DeviceObject->DeviceExtension; + + ASSERT(Vcb != NULL); + + ASSERT((Vcb->Identifier.Type == FFSVCB) && + (Vcb->Identifier.Size == sizeof(FFS_VCB))); + + ExAcquireResourceExclusiveLite( + &Vcb->MainResource, + TRUE); + + VcbResourceAcquired = TRUE; + + if (!FlagOn(Vcb->TargetDeviceObject->Flags, DO_VERIFY_VOLUME)) + { + Status = STATUS_SUCCESS; + _SEH2_LEAVE; + } + + if (!IsMounted(Vcb)) + { + Status = STATUS_WRONG_VOLUME; + _SEH2_LEAVE; + } + + dwReturn = sizeof(ULONG); + Status = FFSDiskIoControl( + Vcb->TargetDeviceObject, + IOCTL_DISK_CHECK_VERIFY, + NULL, + 0, + &ChangeCount, + &dwReturn); + + if (ChangeCount != Vcb->ChangeCount) + { + Status = STATUS_WRONG_VOLUME; + _SEH2_LEAVE; + } + + Irp = IrpContext->Irp; + + IoStackLocation = IoGetCurrentIrpStackLocation(Irp); + + if (((((FFSSb = FFSLoadSuper(Vcb, TRUE, SBLOCK_UFS1)) != NULL) && (FFSSb->fs_magic == FS_UFS1_MAGIC)) || + (((FFSSb = FFSLoadSuper(Vcb, TRUE, SBLOCK_UFS2)) != NULL) && (FFSSb->fs_magic == FS_UFS2_MAGIC))) && + (memcmp(FFSSb->fs_id, SUPER_BLOCK->fs_id, 8) == 0) && + (memcmp(FFSSb->fs_volname, SUPER_BLOCK->fs_volname, 16) == 0)) + { + ClearFlag(Vcb->TargetDeviceObject->Flags, DO_VERIFY_VOLUME); + + if (FFSIsMediaWriteProtected(IrpContext, Vcb->TargetDeviceObject)) + { + SetFlag(Vcb->Flags, VCB_WRITE_PROTECTED); + } + else + { + ClearFlag(Vcb->Flags, VCB_WRITE_PROTECTED); + } + + FFSPrint((DBG_INFO, "FFSVerifyVolume: Volume verify succeeded.\n")); + + Status = STATUS_SUCCESS; + } + else + { + Status = STATUS_WRONG_VOLUME; + + FFSPurgeVolume(Vcb, FALSE); + + SetFlag(Vcb->Flags, VCB_DISMOUNT_PENDING); + + ClearFlag(Vcb->TargetDeviceObject->Flags, DO_VERIFY_VOLUME); + + FFSPrint((DBG_INFO, "FFSVerifyVolume: Volume verify failed.\n")); + } + } + + _SEH2_FINALLY + { + if (FFSSb) + ExFreePool(FFSSb); + + if (VcbResourceAcquired) + { + ExReleaseResourceForThreadLite( + &Vcb->MainResource, + ExGetCurrentResourceThread()); + } + + if (GlobalResourceAcquired) + { + ExReleaseResourceForThreadLite( + &FFSGlobal->Resource, + ExGetCurrentResourceThread()); + } + + if (!IrpContext->ExceptionInProgress) + { + FFSCompleteIrpContext(IrpContext, Status); + } + } _SEH2_END; + + return Status; +} + + +__drv_mustHoldCriticalRegion +NTSTATUS +FFSIsVolumeMounted( + IN PFFS_IRP_CONTEXT IrpContext) +{ + PAGED_CODE(); + + ASSERT(IrpContext); + + ASSERT((IrpContext->Identifier.Type == FFSICX) && + (IrpContext->Identifier.Size == sizeof(FFS_IRP_CONTEXT))); + + return FFSVerifyVolume(IrpContext); +} + + +__drv_mustHoldCriticalRegion +NTSTATUS +FFSDismountVolume( + IN PFFS_IRP_CONTEXT IrpContext) +{ + PDEVICE_OBJECT DeviceObject; + NTSTATUS Status = STATUS_UNSUCCESSFUL; + PFFS_VCB Vcb = 0; + 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)); + + ExAcquireResourceExclusiveLite( + &Vcb->MainResource, + TRUE); + + VcbResourceAcquired = TRUE; + + if (IsFlagOn(Vcb->Flags, VCB_DISMOUNT_PENDING)) + { + Status = STATUS_VOLUME_DISMOUNTED; + _SEH2_LEAVE; + } + + /* + if (!FlagOn(Vcb->Flags, VCB_VOLUME_LOCKED)) + { + FFSPrint((DBG_ERROR, "FFSDismount: Volume is not locked.\n")); + + Status = STATUS_ACCESS_DENIED; + _SEH2_LEAVE; + } + */ + + FFSFlushFiles(Vcb, FALSE); + + FFSFlushVolume(Vcb, FALSE); + + FFSPurgeVolume(Vcb, TRUE); + + ExReleaseResourceForThreadLite( + &Vcb->MainResource, + ExGetCurrentResourceThread()); + + VcbResourceAcquired = FALSE; + + FFSCheckDismount(IrpContext, Vcb, TRUE); + + FFSPrint((DBG_INFO, "FFSDismount: Volume dismount pending.\n")); + + Status = STATUS_SUCCESS; + } + _SEH2_FINALLY + { + if (VcbResourceAcquired) + { + ExReleaseResourceForThreadLite( + &Vcb->MainResource, + ExGetCurrentResourceThread()); + } + + if (!IrpContext->ExceptionInProgress) + { + FFSCompleteIrpContext(IrpContext, Status); + } + } _SEH2_END; + + return Status; +} + + +__drv_mustHoldCriticalRegion +BOOLEAN +FFSCheckDismount( + IN PFFS_IRP_CONTEXT IrpContext, + IN PFFS_VCB Vcb, + IN BOOLEAN bForce) +{ + KIRQL Irql; + PVPB Vpb = Vcb->Vpb; + BOOLEAN bDeleted = FALSE; + ULONG UnCleanCount = 0; + + PAGED_CODE(); + + ExAcquireResourceExclusiveLite( + &FFSGlobal->Resource, TRUE); + + ExAcquireResourceExclusiveLite( + &Vcb->MainResource, TRUE); + + if ((IrpContext->MajorFunction == IRP_MJ_CREATE) && + (IrpContext->RealDevice == Vcb->RealDevice)) + { + UnCleanCount = 3; + } + else + { + UnCleanCount = 2; + } + + IoAcquireVpbSpinLock(&Irql); + + if ((Vpb->ReferenceCount == UnCleanCount) || bForce) + { + + if ((Vpb->ReferenceCount != UnCleanCount) && bForce) + { + FFSBreakPoint(); + } + + ClearFlag(Vpb->Flags, VPB_MOUNTED); + ClearFlag(Vpb->Flags, VPB_LOCKED); + + if ((Vcb->RealDevice != Vpb->RealDevice) && +#ifdef _MSC_VER +#pragma prefast( suppress: 28175, "allowed in file system drivers" ) +#endif + (Vcb->RealDevice->Vpb == Vpb)) + { + SetFlag(Vcb->RealDevice->Flags, DO_DEVICE_INITIALIZING); + SetFlag(Vpb->Flags, VPB_PERSISTENT); + } + + FFSRemoveVcb(Vcb); + + ClearFlag(Vpb->Flags, VPB_MOUNTED); + SetFlag(Vcb->Flags, VCB_DISMOUNT_PENDING); + + Vpb->DeviceObject = NULL; + + bDeleted = TRUE; + } + +#if 0 + + else if ((Vpb->RealDevice->Vpb == Vpb) && bForce) + { + PVPB NewVpb; + +#define TAG_VPB ' bpV' + + NewVpb = ExAllocatePoolWithTag(NonPagedPoolMustSucceed, + sizeof(VPB), TAG_VPB); + + NewVpb->Type = IO_TYPE_VPB; + NewVpb->Size = sizeof(VPB); + NewVpb->RealDevice = Vcb->Vpb->RealDevice; + + NewVpb->RealDevice->Vpb = NewVpb; + + NewVpb->Flags = FlagOn(Vcb->Vpb->Flags, VPB_REMOVE_PENDING); + + NewVpb = NULL; + + ClearFlag(Vcb->Flags, VCB_MOUNTED); + ClearFlag(Vcb->Flags, VCB_DISMOUNT_PENDING); + } + +#endif + + IoReleaseVpbSpinLock(Irql); + + ExReleaseResourceForThreadLite( + &Vcb->MainResource, + ExGetCurrentResourceThread()); + + ExReleaseResourceForThreadLite( + &FFSGlobal->Resource, + ExGetCurrentResourceThread()); + + if (bDeleted) + { +#if 0 + FFSBreakPoint(); /* XP¿¡¼­ ºê·¹ÀÌÅ© Æ÷ÀÎÆ® ¹ß»ý */ +#endif + + FFSFreeVcb(Vcb); + } + + return bDeleted; +} + + +__drv_mustHoldCriticalRegion +NTSTATUS +FFSPurgeVolume( + IN PFFS_VCB Vcb, + IN BOOLEAN FlushBeforePurge) +{ + PFFS_FCB Fcb; + LIST_ENTRY FcbList; + PLIST_ENTRY ListEntry; + PFCB_LIST_ENTRY FcbListEntry; + + PAGED_CODE(); + + _SEH2_TRY + { + ASSERT(Vcb != NULL); + + ASSERT((Vcb->Identifier.Type == FFSVCB) && + (Vcb->Identifier.Size == sizeof(FFS_VCB))); + + if (IsFlagOn(Vcb->Flags, VCB_READ_ONLY) || + IsFlagOn(Vcb->Flags, VCB_WRITE_PROTECTED)) + { + FlushBeforePurge = FALSE; + } + + FcbListEntry= NULL; + InitializeListHead(&FcbList); + + for (ListEntry = Vcb->FcbList.Flink; + ListEntry != &Vcb->FcbList; + ListEntry = ListEntry->Flink) + { + Fcb = CONTAINING_RECORD(ListEntry, FFS_FCB, Next); + + Fcb->ReferenceCount++; + + FFSPrint((DBG_INFO, "FFSPurgeVolume: %s refercount=%xh\n", Fcb->AnsiFileName.Buffer, Fcb->ReferenceCount)); + + FcbListEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FCB_LIST_ENTRY), FFS_POOL_TAG); + + if (FcbListEntry) + { + FcbListEntry->Fcb = Fcb; + + InsertTailList(&FcbList, &FcbListEntry->Next); + } + else + { + FFSPrint((DBG_ERROR, "FFSPurgeVolume: Error allocating FcbListEntry ...\n")); + } + } + + while (!IsListEmpty(&FcbList)) + { + ListEntry = RemoveHeadList(&FcbList); + + FcbListEntry = CONTAINING_RECORD(ListEntry, FCB_LIST_ENTRY, Next); + + Fcb = FcbListEntry->Fcb; + + if (ExAcquireResourceExclusiveLite( + &Fcb->MainResource, + TRUE)) + { + FFSPurgeFile(Fcb, FlushBeforePurge); + + if (!Fcb->OpenHandleCount && Fcb->ReferenceCount == 1) + { + RemoveEntryList(&Fcb->Next); + FFSFreeFcb(Fcb); + } + else + { + ExReleaseResourceForThreadLite( + &Fcb->MainResource, + ExGetCurrentResourceThread()); + } + } + + ExFreePool(FcbListEntry); + } + + if (FlushBeforePurge) + { + ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE); + ExReleaseResourceLite(&Vcb->PagingIoResource); + + CcFlushCache(&Vcb->SectionObject, NULL, 0, NULL); + } + + if (Vcb->SectionObject.ImageSectionObject) + { + MmFlushImageSection(&Vcb->SectionObject, MmFlushForWrite); + } + + if (Vcb->SectionObject.DataSectionObject) + { + CcPurgeCacheSection(&Vcb->SectionObject, NULL, 0, FALSE); + } + + FFSPrint((DBG_INFO, "FFSPurgeVolume: Volume flushed and purged.\n")); + } + _SEH2_FINALLY + { + // Nothing + } _SEH2_END; + + return STATUS_SUCCESS; +} + + +__drv_mustHoldCriticalRegion +NTSTATUS +FFSPurgeFile( + IN PFFS_FCB Fcb, + IN BOOLEAN FlushBeforePurge) +{ + IO_STATUS_BLOCK IoStatus; + + PAGED_CODE(); + + ASSERT(Fcb != NULL); + + ASSERT((Fcb->Identifier.Type == FFSFCB) && + (Fcb->Identifier.Size == sizeof(FFS_FCB))); + + + if(!IsFlagOn(Fcb->Vcb->Flags, VCB_READ_ONLY) && FlushBeforePurge && + !IsFlagOn(Fcb->Vcb->Flags, VCB_WRITE_PROTECTED)) + { + + FFSPrint((DBG_INFO, "FFSPurgeFile: CcFlushCache on %s.\n", + Fcb->AnsiFileName.Buffer)); + + ExAcquireSharedStarveExclusive(&Fcb->PagingIoResource, TRUE); + ExReleaseResourceLite(&Fcb->PagingIoResource); + + CcFlushCache(&Fcb->SectionObject, NULL, 0, &IoStatus); + + ClearFlag(Fcb->Flags, FCB_FILE_MODIFIED); + } + + if (Fcb->SectionObject.ImageSectionObject) + { + + FFSPrint((DBG_INFO, "FFSPurgeFile: MmFlushImageSection on %s.\n", + Fcb->AnsiFileName.Buffer)); + + MmFlushImageSection(&Fcb->SectionObject, MmFlushForWrite); + } + + if (Fcb->SectionObject.DataSectionObject) + { + + FFSPrint((DBG_INFO, "FFSPurgeFile: CcPurgeCacheSection on %s.\n", + Fcb->AnsiFileName.Buffer)); + + CcPurgeCacheSection(&Fcb->SectionObject, NULL, 0, FALSE); + } + + return STATUS_SUCCESS; +} + + +__drv_mustHoldCriticalRegion +NTSTATUS +FFSSelectBSDPartition( + IN PFFS_IRP_CONTEXT IrpContext) +{ + PIRP Irp; + NTSTATUS Status; + PFFS_BSD_PARTITION BSDPartition; + + _SEH2_TRY + { + ASSERT(IrpContext != NULL); + + ASSERT((IrpContext->Identifier.Type == FFSICX) && + (IrpContext->Identifier.Size == sizeof(FFS_IRP_CONTEXT))); + + Irp = IrpContext->Irp; + + BSDPartition = (PFFS_BSD_PARTITION)Irp->AssociatedIrp.SystemBuffer; + FFSGlobal->PartitionNumber = BSDPartition->Number; + + Status = STATUS_SUCCESS; + } + _SEH2_FINALLY + { + if (!IrpContext->ExceptionInProgress) + { + FFSCompleteIrpContext(IrpContext, Status); + } + } _SEH2_END; + + return Status; +} + + +__drv_mustHoldCriticalRegion +NTSTATUS +FFSFileSystemControl( + IN PFFS_IRP_CONTEXT IrpContext) +{ + NTSTATUS Status; + + PAGED_CODE(); + + ASSERT(IrpContext); + + ASSERT((IrpContext->Identifier.Type == FFSICX) && + (IrpContext->Identifier.Size == sizeof(FFS_IRP_CONTEXT))); + + switch (IrpContext->MinorFunction) + { + case IRP_MN_USER_FS_REQUEST: + Status = FFSUserFsRequest(IrpContext); + break; + + case IRP_MN_MOUNT_VOLUME: + Status = FFSMountVolume(IrpContext); + break; + + case IRP_MN_VERIFY_VOLUME: + Status = FFSVerifyVolume(IrpContext); + break; + + default: + + FFSPrint((DBG_ERROR, "FFSFilsSystemControl: Invalid Device Request.\n")); + Status = STATUS_INVALID_DEVICE_REQUEST; + FFSCompleteIrpContext(IrpContext, Status); + } + + return Status; +}