Git conversion: Make reactos the root directory, move rosapps, rostests, wallpapers...
[reactos.git] / drivers / filesystems / ffs / src / fsctl.c
diff --git a/drivers/filesystems/ffs/src/fsctl.c b/drivers/filesystems/ffs/src/fsctl.c
new file mode 100644 (file)
index 0000000..251ea88
--- /dev/null
@@ -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;
+}