[FASTFAT] Don't leak statistics on dismount
[reactos.git] / drivers / filesystems / fastfat / fsctl.c
index 0c1d0bc..b70a84c 100644 (file)
 
 /* INCLUDES *****************************************************************/
 
-#define NDEBUG
 #include "vfat.h"
 
+#define NDEBUG
+#include <debug.h>
+
+extern VFAT_DISPATCH FatXDispatch;
+extern VFAT_DISPATCH FatDispatch;
+
 /* FUNCTIONS ****************************************************************/
 
 #define  CACHEPAGESIZE(pDeviceExt) ((pDeviceExt)->FatInfo.BytesPerCluster > PAGE_SIZE ? \
                                     (pDeviceExt)->FatInfo.BytesPerCluster : PAGE_SIZE)
 
-static NTSTATUS
-VfatHasFileSystem(PDEVICE_OBJECT DeviceToMount,
-                  PBOOLEAN RecognizedFS,
-                  PFATINFO pFatInfo)
+static
+NTSTATUS
+VfatHasFileSystem(
+    PDEVICE_OBJECT DeviceToMount,
+    PBOOLEAN RecognizedFS,
+    PFATINFO pFatInfo,
+    BOOLEAN Override)
 {
-   NTSTATUS Status;
-   PARTITION_INFORMATION PartitionInfo;
-   DISK_GEOMETRY DiskGeometry;
-   FATINFO FatInfo;
-   ULONG Size;
-   ULONG Sectors;
-   LARGE_INTEGER Offset;
-   struct _BootSector* Boot;
-   struct _BootSectorFatX* BootFatX;
-   BOOLEAN PartitionInfoIsValid = FALSE;
-
-   DPRINT("VfatHasFileSystem\n");
-
-   *RecognizedFS = FALSE;
-
-   Size = sizeof(DISK_GEOMETRY);
-   Status = VfatBlockDeviceIoControl(DeviceToMount,
-                                     IOCTL_DISK_GET_DRIVE_GEOMETRY,
-                                     NULL,
-                                     0,
-                                     &DiskGeometry,
-                                     &Size,
-                                     FALSE);
-   if (!NT_SUCCESS(Status))
-   {
-      DPRINT("VfatBlockDeviceIoControl faild (%x)\n", Status);
-      return Status;
-   }
-   FatInfo.FixedMedia = DiskGeometry.MediaType == FixedMedia ? TRUE : FALSE;
-   if (DiskGeometry.MediaType == FixedMedia || DiskGeometry.MediaType == RemovableMedia)
-   {
-      // We have found a hard disk
-      Size = sizeof(PARTITION_INFORMATION);
-      Status = VfatBlockDeviceIoControl(DeviceToMount,
-                                        IOCTL_DISK_GET_PARTITION_INFO,
-                                        NULL,
-                                        0,
-                                        &PartitionInfo,
-                                        &Size,
-                                        FALSE);
-      if (!NT_SUCCESS(Status))
-      {
-         DPRINT("VfatBlockDeviceIoControl faild (%x)\n", Status);
-         return Status;
-      }
-      PartitionInfoIsValid = TRUE;
-      DPRINT("Partition Information:\n");
-      DPRINT("StartingOffset      %I64u\n", PartitionInfo.StartingOffset.QuadPart  / 512);
-      DPRINT("PartitionLength     %I64u\n", PartitionInfo.PartitionLength.QuadPart / 512);
-      DPRINT("HiddenSectors       %u\n", PartitionInfo.HiddenSectors);
-      DPRINT("PartitionNumber     %u\n", PartitionInfo.PartitionNumber);
-      DPRINT("PartitionType       %u\n", PartitionInfo.PartitionType);
-      DPRINT("BootIndicator       %u\n", PartitionInfo.BootIndicator);
-      DPRINT("RecognizedPartition %u\n", PartitionInfo.RecognizedPartition);
-      DPRINT("RewritePartition    %u\n", PartitionInfo.RewritePartition);
-      if (PartitionInfo.PartitionType)
-      {
-         if (PartitionInfo.PartitionType == PARTITION_FAT_12       ||
-             PartitionInfo.PartitionType == PARTITION_FAT_16       ||
-             PartitionInfo.PartitionType == PARTITION_HUGE         ||
-             PartitionInfo.PartitionType == PARTITION_FAT32        ||
-             PartitionInfo.PartitionType == PARTITION_FAT32_XINT13 ||
-             PartitionInfo.PartitionType == PARTITION_XINT13)
-         {
+    NTSTATUS Status;
+    PARTITION_INFORMATION PartitionInfo;
+    DISK_GEOMETRY DiskGeometry;
+    FATINFO FatInfo;
+    ULONG Size;
+    ULONG Sectors;
+    LARGE_INTEGER Offset;
+    struct _BootSector* Boot;
+    struct _BootSectorFatX* BootFatX;
+    BOOLEAN PartitionInfoIsValid = FALSE;
+
+    DPRINT("VfatHasFileSystem\n");
+
+    *RecognizedFS = FALSE;
+
+    Size = sizeof(DISK_GEOMETRY);
+    Status = VfatBlockDeviceIoControl(DeviceToMount,
+                                      IOCTL_DISK_GET_DRIVE_GEOMETRY,
+                                      NULL,
+                                      0,
+                                      &DiskGeometry,
+                                      &Size,
+                                      Override);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT("VfatBlockDeviceIoControl failed (%x)\n", Status);
+        return Status;
+    }
+
+    FatInfo.FixedMedia = DiskGeometry.MediaType == FixedMedia ? TRUE : FALSE;
+    if (DiskGeometry.MediaType == FixedMedia || DiskGeometry.MediaType == RemovableMedia)
+    {
+        // We have found a hard disk
+        Size = sizeof(PARTITION_INFORMATION);
+        Status = VfatBlockDeviceIoControl(DeviceToMount,
+                                          IOCTL_DISK_GET_PARTITION_INFO,
+                                          NULL,
+                                          0,
+                                          &PartitionInfo,
+                                          &Size,
+                                          Override);
+        if (!NT_SUCCESS(Status))
+        {
+            DPRINT("VfatBlockDeviceIoControl failed (%x)\n", Status);
+            return Status;
+        }
+
+        DPRINT("Partition Information:\n");
+        DPRINT("StartingOffset      %I64x\n", PartitionInfo.StartingOffset.QuadPart  / 512);
+        DPRINT("PartitionLength     %I64x\n", PartitionInfo.PartitionLength.QuadPart / 512);
+        DPRINT("HiddenSectors       %u\n", PartitionInfo.HiddenSectors);
+        DPRINT("PartitionNumber     %u\n", PartitionInfo.PartitionNumber);
+        DPRINT("PartitionType       %u\n", PartitionInfo.PartitionType);
+        DPRINT("BootIndicator       %u\n", PartitionInfo.BootIndicator);
+        DPRINT("RecognizedPartition %u\n", PartitionInfo.RecognizedPartition);
+        DPRINT("RewritePartition    %u\n", PartitionInfo.RewritePartition);
+        if (PartitionInfo.PartitionType)
+        {
+            if (PartitionInfo.PartitionType == PARTITION_FAT_12       ||
+                PartitionInfo.PartitionType == PARTITION_FAT_16       ||
+                PartitionInfo.PartitionType == PARTITION_HUGE         ||
+                PartitionInfo.PartitionType == PARTITION_FAT32        ||
+                PartitionInfo.PartitionType == PARTITION_FAT32_XINT13 ||
+                PartitionInfo.PartitionType == PARTITION_XINT13)
+            {
+                 PartitionInfoIsValid = TRUE;
+                *RecognizedFS = TRUE;
+            }
+        }
+        else if (DiskGeometry.MediaType == RemovableMedia &&
+                 PartitionInfo.PartitionNumber > 0 &&
+                 PartitionInfo.StartingOffset.QuadPart == 0 &&
+                 PartitionInfo.PartitionLength.QuadPart > 0)
+        {
+            /* This is possible a removable media formated as super floppy */
+            PartitionInfoIsValid = TRUE;
             *RecognizedFS = TRUE;
-         }
-      }
-      else if (DiskGeometry.MediaType == RemovableMedia &&
-               PartitionInfo.PartitionNumber > 0 &&
-               PartitionInfo.StartingOffset.QuadPart == 0 &&
-               PartitionInfo.PartitionLength.QuadPart > 0)
-      {
-         /* This is possible a removable media formated as super floppy */
-         *RecognizedFS = TRUE;
-      }
-   }
-   else if (DiskGeometry.MediaType == Unknown)
-   {
-      /*
-       * Floppy disk driver can return Unknown as media type if it
-       * doesn't know yet what floppy in the drive really is. This is
-       * perfectly correct to do under Windows.
-       */
-      *RecognizedFS = TRUE;
-      DiskGeometry.BytesPerSector = 512;
-   }
-   else
-   {
-      *RecognizedFS = TRUE;
-   }
-   if (*RecognizedFS)
-   {
-
-      Boot = ExAllocatePoolWithTag(NonPagedPool, DiskGeometry.BytesPerSector, TAG_VFAT);
-      if (Boot == NULL)
-      {
-         return STATUS_INSUFFICIENT_RESOURCES;
-      }
-
-      Offset.QuadPart = 0;
-
-      /* Try to recognize FAT12/FAT16/FAT32 partitions */
-      Status = VfatReadDisk(DeviceToMount, &Offset, DiskGeometry.BytesPerSector, (PUCHAR) Boot, FALSE);
-      if (NT_SUCCESS(Status))
-      {
-         if (Boot->Signatur1 != 0xaa55)
-         {
-            *RecognizedFS = FALSE;
-         }
-         if (*RecognizedFS &&
-         Boot->BytesPerSector != 512 &&
-         Boot->BytesPerSector != 1024 &&
-             Boot->BytesPerSector != 2048 &&
-         Boot->BytesPerSector != 4096)
-         {
-            DPRINT1("BytesPerSector %d\n", Boot->BytesPerSector);
-            *RecognizedFS = FALSE;
-         }
-
-         if (*RecognizedFS &&
-             Boot->FATCount != 1 &&
-             Boot->FATCount != 2)
-         {
-            DPRINT1("FATCount %d\n", Boot->FATCount);
-            *RecognizedFS = FALSE;
-         }
-
-         if (*RecognizedFS &&
-             Boot->Media != 0xf0 &&
-             Boot->Media != 0xf8 &&
-             Boot->Media != 0xf9 &&
-             Boot->Media != 0xfa &&
-             Boot->Media != 0xfb &&
-             Boot->Media != 0xfc &&
-             Boot->Media != 0xfd &&
-             Boot->Media != 0xfe &&
-             Boot->Media != 0xff)
-         {
-            DPRINT1("Media             %02x\n", Boot->Media);
-            *RecognizedFS = FALSE;
-         }
-
-         if (*RecognizedFS &&
-             Boot->SectorsPerCluster != 1 &&
-             Boot->SectorsPerCluster != 2 &&
-             Boot->SectorsPerCluster != 4 &&
-             Boot->SectorsPerCluster != 8 &&
-             Boot->SectorsPerCluster != 16 &&
-             Boot->SectorsPerCluster != 32 &&
-             Boot->SectorsPerCluster != 64 &&
-             Boot->SectorsPerCluster != 128)
-         {
-            DPRINT1("SectorsPerCluster %02x\n", Boot->SectorsPerCluster);
-            *RecognizedFS = FALSE;
-         }
-
-         if (*RecognizedFS &&
-             Boot->BytesPerSector * Boot->SectorsPerCluster > 32 * 1024)
-         {
-            DPRINT1("ClusterSize %dx\n", Boot->BytesPerSector * Boot->SectorsPerCluster);
-            *RecognizedFS = FALSE;
-         }
-
-         if (*RecognizedFS)
-         {
-            FatInfo.VolumeID = Boot->VolumeID;
-            FatInfo.FATStart = Boot->ReservedSectors;
-            FatInfo.FATCount = Boot->FATCount;
-            FatInfo.FATSectors = Boot->FATSectors ? Boot->FATSectors : ((struct _BootSector32*) Boot)->FATSectors32;
-            FatInfo.BytesPerSector = Boot->BytesPerSector;
-            FatInfo.SectorsPerCluster = Boot->SectorsPerCluster;
-            FatInfo.BytesPerCluster = FatInfo.BytesPerSector * FatInfo.SectorsPerCluster;
-            FatInfo.rootDirectorySectors = ((Boot->RootEntries * 32) + Boot->BytesPerSector - 1) / Boot->BytesPerSector;
-            FatInfo.rootStart = FatInfo.FATStart + FatInfo.FATCount * FatInfo.FATSectors;
-            FatInfo.dataStart = FatInfo.rootStart + FatInfo.rootDirectorySectors;
-            FatInfo.Sectors = Sectors = Boot->Sectors ? Boot->Sectors : Boot->SectorsHuge;
-            Sectors -= Boot->ReservedSectors + FatInfo.FATCount * FatInfo.FATSectors + FatInfo.rootDirectorySectors;
-            FatInfo.NumberOfClusters = Sectors / Boot->SectorsPerCluster;
-            if (FatInfo.NumberOfClusters < 4085)
+        }
+    }
+    else
+    {
+        *RecognizedFS = TRUE;
+    }
+
+    if (*RecognizedFS)
+    {
+        Boot = ExAllocatePoolWithTag(NonPagedPool, DiskGeometry.BytesPerSector, TAG_VFAT);
+        if (Boot == NULL)
+        {
+           return STATUS_INSUFFICIENT_RESOURCES;
+        }
+
+        Offset.QuadPart = 0;
+
+        /* Try to recognize FAT12/FAT16/FAT32 partitions */
+        Status = VfatReadDisk(DeviceToMount, &Offset, DiskGeometry.BytesPerSector, (PUCHAR) Boot, Override);
+        if (NT_SUCCESS(Status))
+        {
+            if (Boot->Signatur1 != 0xaa55)
             {
-               DPRINT("FAT12\n");
-               FatInfo.FatType = FAT12;
-               FatInfo.RootCluster = (FatInfo.rootStart - 1) / FatInfo.SectorsPerCluster;
+                *RecognizedFS = FALSE;
             }
-            else if (FatInfo.NumberOfClusters >= 65525)
+
+            if (*RecognizedFS &&
+                Boot->BytesPerSector != 512 &&
+                Boot->BytesPerSector != 1024 &&
+                Boot->BytesPerSector != 2048 &&
+                Boot->BytesPerSector != 4096)
             {
-               DPRINT("FAT32\n");
-               FatInfo.FatType = FAT32;
-               FatInfo.RootCluster = ((struct _BootSector32*) Boot)->RootCluster;
-               FatInfo.rootStart = FatInfo.dataStart + ((FatInfo.RootCluster - 2) * FatInfo.SectorsPerCluster);
-               FatInfo.VolumeID = ((struct _BootSector32*) Boot)->VolumeID;
+                DPRINT1("BytesPerSector %u\n", Boot->BytesPerSector);
+                *RecognizedFS = FALSE;
             }
-            else
+
+            if (*RecognizedFS &&
+                Boot->FATCount != 1 &&
+                Boot->FATCount != 2)
             {
-               DPRINT("FAT16\n");
-               FatInfo.FatType = FAT16;
-               FatInfo.RootCluster = FatInfo.rootStart / FatInfo.SectorsPerCluster;
+                DPRINT1("FATCount %u\n", Boot->FATCount);
+                *RecognizedFS = FALSE;
             }
-            if (PartitionInfoIsValid &&
-                FatInfo.Sectors > PartitionInfo.PartitionLength.QuadPart / FatInfo.BytesPerSector)
+
+            if (*RecognizedFS &&
+                Boot->Media != 0xf0 &&
+                Boot->Media != 0xf8 &&
+                Boot->Media != 0xf9 &&
+                Boot->Media != 0xfa &&
+                Boot->Media != 0xfb &&
+                Boot->Media != 0xfc &&
+                Boot->Media != 0xfd &&
+                Boot->Media != 0xfe &&
+                Boot->Media != 0xff)
             {
-               *RecognizedFS = FALSE;
+                DPRINT1("Media             %02x\n", Boot->Media);
+                *RecognizedFS = FALSE;
             }
 
-            if (pFatInfo && *RecognizedFS)
+            if (*RecognizedFS &&
+                Boot->SectorsPerCluster != 1 &&
+                Boot->SectorsPerCluster != 2 &&
+                Boot->SectorsPerCluster != 4 &&
+                Boot->SectorsPerCluster != 8 &&
+                Boot->SectorsPerCluster != 16 &&
+                Boot->SectorsPerCluster != 32 &&
+                Boot->SectorsPerCluster != 64 &&
+                Boot->SectorsPerCluster != 128)
             {
-               *pFatInfo = FatInfo;
+                DPRINT1("SectorsPerCluster %02x\n", Boot->SectorsPerCluster);
+                *RecognizedFS = FALSE;
             }
-         }
-      }
-
-      ExFreePool(Boot);
-   }
-
-   if (!*RecognizedFS && PartitionInfoIsValid)
-   {
-      BootFatX = ExAllocatePoolWithTag(NonPagedPool, sizeof(struct _BootSectorFatX), TAG_VFAT);
-      if (BootFatX == NULL)
-      {
-         *RecognizedFS=FALSE;
-         return STATUS_INSUFFICIENT_RESOURCES;
-      }
-
-      Offset.QuadPart = 0;
-
-      /* Try to recognize FATX16/FATX32 partitions (Xbox) */
-      Status = VfatReadDisk(DeviceToMount, &Offset, sizeof(struct _BootSectorFatX), (PUCHAR) BootFatX, FALSE);
-      if (NT_SUCCESS(Status))
-      {
-         *RecognizedFS = TRUE;
-         if (BootFatX->SysType[0] != 'F' ||
-             BootFatX->SysType[1] != 'A' ||
-             BootFatX->SysType[2] != 'T' ||
-             BootFatX->SysType[3] != 'X')
-         {
-            DPRINT1("SysType %c%c%c%c\n", BootFatX->SysType[0], BootFatX->SysType[1], BootFatX->SysType[2], BootFatX->SysType[3]);
-            *RecognizedFS=FALSE;
-         }
-
-         if (*RecognizedFS &&
-            BootFatX->SectorsPerCluster != 1 &&
-            BootFatX->SectorsPerCluster != 2 &&
-            BootFatX->SectorsPerCluster != 4 &&
-            BootFatX->SectorsPerCluster != 8 &&
-            BootFatX->SectorsPerCluster != 16 &&
-            BootFatX->SectorsPerCluster != 32 &&
-            BootFatX->SectorsPerCluster != 64 &&
-            BootFatX->SectorsPerCluster != 128)
-         {
-            DPRINT1("SectorsPerCluster %lu\n", BootFatX->SectorsPerCluster);
+
+            if (*RecognizedFS &&
+                Boot->BytesPerSector * Boot->SectorsPerCluster > 32 * 1024)
+            {
+                DPRINT1("ClusterSize %dx\n", Boot->BytesPerSector * Boot->SectorsPerCluster);
+                *RecognizedFS = FALSE;
+            }
+
+            if (*RecognizedFS)
+            {
+                FatInfo.VolumeID = Boot->VolumeID;
+                FatInfo.FATStart = Boot->ReservedSectors;
+                FatInfo.FATCount = Boot->FATCount;
+                FatInfo.FATSectors = Boot->FATSectors ? Boot->FATSectors : ((struct _BootSector32*) Boot)->FATSectors32;
+                FatInfo.BytesPerSector = Boot->BytesPerSector;
+                FatInfo.SectorsPerCluster = Boot->SectorsPerCluster;
+                FatInfo.BytesPerCluster = FatInfo.BytesPerSector * FatInfo.SectorsPerCluster;
+                FatInfo.rootDirectorySectors = ((Boot->RootEntries * 32) + Boot->BytesPerSector - 1) / Boot->BytesPerSector;
+                FatInfo.rootStart = FatInfo.FATStart + FatInfo.FATCount * FatInfo.FATSectors;
+                FatInfo.dataStart = FatInfo.rootStart + FatInfo.rootDirectorySectors;
+                FatInfo.Sectors = Sectors = Boot->Sectors ? Boot->Sectors : Boot->SectorsHuge;
+                Sectors -= Boot->ReservedSectors + FatInfo.FATCount * FatInfo.FATSectors + FatInfo.rootDirectorySectors;
+                FatInfo.NumberOfClusters = Sectors / Boot->SectorsPerCluster;
+                if (FatInfo.NumberOfClusters < 4085)
+                {
+                    DPRINT("FAT12\n");
+                    FatInfo.FatType = FAT12;
+                    FatInfo.RootCluster = (FatInfo.rootStart - 1) / FatInfo.SectorsPerCluster;
+                    RtlCopyMemory(&FatInfo.VolumeLabel, &Boot->VolumeLabel, sizeof(FatInfo.VolumeLabel));
+                }
+                else if (FatInfo.NumberOfClusters >= 65525)
+                {
+                    DPRINT("FAT32\n");
+                    FatInfo.FatType = FAT32;
+                    FatInfo.RootCluster = ((struct _BootSector32*) Boot)->RootCluster;
+                    FatInfo.rootStart = FatInfo.dataStart + ((FatInfo.RootCluster - 2) * FatInfo.SectorsPerCluster);
+                    FatInfo.VolumeID = ((struct _BootSector32*) Boot)->VolumeID;
+                    FatInfo.FSInfoSector = ((struct _BootSector32*) Boot)->FSInfoSector;
+                    RtlCopyMemory(&FatInfo.VolumeLabel, &((struct _BootSector32*)Boot)->VolumeLabel, sizeof(FatInfo.VolumeLabel));
+                }
+                else
+                {
+                    DPRINT("FAT16\n");
+                    FatInfo.FatType = FAT16;
+                    FatInfo.RootCluster = FatInfo.rootStart / FatInfo.SectorsPerCluster;
+                    RtlCopyMemory(&FatInfo.VolumeLabel, &Boot->VolumeLabel, sizeof(FatInfo.VolumeLabel));
+                }
+
+                if (PartitionInfoIsValid &&
+                    FatInfo.Sectors > PartitionInfo.PartitionLength.QuadPart / FatInfo.BytesPerSector)
+                {
+                    *RecognizedFS = FALSE;
+                }
+
+                if (pFatInfo && *RecognizedFS)
+                {
+                    *pFatInfo = FatInfo;
+                }
+            }
+        }
+
+        ExFreePool(Boot);
+    }
+
+    if (!*RecognizedFS && PartitionInfoIsValid)
+    {
+        BootFatX = ExAllocatePoolWithTag(NonPagedPool, sizeof(struct _BootSectorFatX), TAG_VFAT);
+        if (BootFatX == NULL)
+        {
             *RecognizedFS=FALSE;
-         }
-
-         if (*RecognizedFS)
-         {
-            FatInfo.BytesPerSector = DiskGeometry.BytesPerSector;
-            FatInfo.SectorsPerCluster = BootFatX->SectorsPerCluster;
-            FatInfo.rootDirectorySectors = BootFatX->SectorsPerCluster;
-            FatInfo.BytesPerCluster = BootFatX->SectorsPerCluster * DiskGeometry.BytesPerSector;
-            FatInfo.Sectors = (ULONG)(PartitionInfo.PartitionLength.QuadPart / DiskGeometry.BytesPerSector);
-            if (FatInfo.Sectors / FatInfo.SectorsPerCluster < 65525)
+            return STATUS_INSUFFICIENT_RESOURCES;
+        }
+
+        Offset.QuadPart = 0;
+
+        /* Try to recognize FATX16/FATX32 partitions (Xbox) */
+        Status = VfatReadDisk(DeviceToMount, &Offset, sizeof(struct _BootSectorFatX), (PUCHAR) BootFatX, Override);
+        if (NT_SUCCESS(Status))
+        {
+            *RecognizedFS = TRUE;
+            if (BootFatX->SysType[0] != 'F' ||
+                BootFatX->SysType[1] != 'A' ||
+                BootFatX->SysType[2] != 'T' ||
+                BootFatX->SysType[3] != 'X')
             {
-               DPRINT("FATX16\n");
-               FatInfo.FatType = FATX16;
+                DPRINT1("SysType %c%c%c%c\n", BootFatX->SysType[0], BootFatX->SysType[1], BootFatX->SysType[2], BootFatX->SysType[3]);
+                *RecognizedFS=FALSE;
             }
-            else
+
+            if (*RecognizedFS &&
+                BootFatX->SectorsPerCluster != 1 &&
+                BootFatX->SectorsPerCluster != 2 &&
+                BootFatX->SectorsPerCluster != 4 &&
+                BootFatX->SectorsPerCluster != 8 &&
+                BootFatX->SectorsPerCluster != 16 &&
+                BootFatX->SectorsPerCluster != 32 &&
+                BootFatX->SectorsPerCluster != 64 &&
+                BootFatX->SectorsPerCluster != 128)
             {
-               DPRINT("FATX32\n");
-               FatInfo.FatType = FATX32;
+                DPRINT1("SectorsPerCluster %lu\n", BootFatX->SectorsPerCluster);
+                *RecognizedFS=FALSE;
             }
-            FatInfo.VolumeID = BootFatX->VolumeID;
-            FatInfo.FATStart = sizeof(struct _BootSectorFatX) / DiskGeometry.BytesPerSector;
-            FatInfo.FATCount = BootFatX->FATCount;
-            FatInfo.FATSectors =
-                  ROUND_UP(FatInfo.Sectors / FatInfo.SectorsPerCluster * (FatInfo.FatType == FATX16 ? 2 : 4), 4096) /
-                  FatInfo.BytesPerSector;
-            FatInfo.rootStart = FatInfo.FATStart + FatInfo.FATCount * FatInfo.FATSectors;
-            FatInfo.RootCluster = (FatInfo.rootStart - 1) / FatInfo.SectorsPerCluster;
-            FatInfo.dataStart = FatInfo.rootStart + FatInfo.rootDirectorySectors;
-            FatInfo.NumberOfClusters = (FatInfo.Sectors - FatInfo.dataStart) / FatInfo.SectorsPerCluster;
-
-            if (pFatInfo && *RecognizedFS)
+
+            if (*RecognizedFS)
             {
-               *pFatInfo = FatInfo;
+                FatInfo.BytesPerSector = DiskGeometry.BytesPerSector;
+                FatInfo.SectorsPerCluster = BootFatX->SectorsPerCluster;
+                FatInfo.rootDirectorySectors = BootFatX->SectorsPerCluster;
+                FatInfo.BytesPerCluster = BootFatX->SectorsPerCluster * DiskGeometry.BytesPerSector;
+                FatInfo.Sectors = (ULONG)(PartitionInfo.PartitionLength.QuadPart / DiskGeometry.BytesPerSector);
+                if (FatInfo.Sectors / FatInfo.SectorsPerCluster < 65525)
+                {
+                    DPRINT("FATX16\n");
+                    FatInfo.FatType = FATX16;
+                }
+                else
+                {
+                    DPRINT("FATX32\n");
+                    FatInfo.FatType = FATX32;
+                }
+                FatInfo.VolumeID = BootFatX->VolumeID;
+                FatInfo.FATStart = sizeof(struct _BootSectorFatX) / DiskGeometry.BytesPerSector;
+                FatInfo.FATCount = BootFatX->FATCount;
+                FatInfo.FATSectors =
+                    ROUND_UP(FatInfo.Sectors / FatInfo.SectorsPerCluster * (FatInfo.FatType == FATX16 ? 2 : 4), 4096) /
+                    FatInfo.BytesPerSector;
+                FatInfo.rootStart = FatInfo.FATStart + FatInfo.FATCount * FatInfo.FATSectors;
+                FatInfo.RootCluster = (FatInfo.rootStart - 1) / FatInfo.SectorsPerCluster;
+                FatInfo.dataStart = FatInfo.rootStart + FatInfo.rootDirectorySectors;
+                FatInfo.NumberOfClusters = (FatInfo.Sectors - FatInfo.dataStart) / FatInfo.SectorsPerCluster;
+
+                if (pFatInfo && *RecognizedFS)
+                {
+                    *pFatInfo = FatInfo;
+                }
             }
-         }
-      }
-      ExFreePool(BootFatX);
-   }
+        }
+        ExFreePool(BootFatX);
+    }
 
-   DPRINT("VfatHasFileSystem done\n");
-   return Status;
+    DPRINT("VfatHasFileSystem done\n");
+    return Status;
 }
 
-static NTSTATUS
-VfatMountDevice(PDEVICE_EXTENSION DeviceExt,
-                PDEVICE_OBJECT DeviceToMount)
 /*
- * FUNCTION: Mounts the device
+ * FUNCTION: Read the volume label
+ * WARNING: Read this comment carefully before using it (and using it wrong)
+ * Device parameter is expected to be the lower DO is start isn't 0
+ *                  otherwise, it is expected to be the VCB is start is 0
+ * Start parameter is expected to be, in bytes, the beginning of the root start.
+ *                 Set it to 0 if you wish to use the associated FCB with caching.
+ *                 In that specific case, Device parameter is expected to be the VCB!
+ * VolumeLabel parameter is expected to be a preallocated UNICODE_STRING (ie, with buffer)
+ *                       Its buffer has to be able to contain MAXIMUM_VOLUME_LABEL_LENGTH bytes 
  */
+static
+NTSTATUS
+ReadVolumeLabel(
+    PVOID Device,
+    ULONG Start,
+    BOOLEAN IsFatX,
+    PUNICODE_STRING VolumeLabel)
 {
-   NTSTATUS Status;
-   BOOLEAN RecognizedFS;
+    PDEVICE_EXTENSION DeviceExt;
+    PDEVICE_OBJECT DeviceObject;
+    PVOID Context = NULL;
+    ULONG DirIndex = 0;
+    PDIR_ENTRY Entry;
+    PVFATFCB pFcb;
+    LARGE_INTEGER FileOffset;
+    ULONG SizeDirEntry;
+    ULONG EntriesPerPage;
+    OEM_STRING StringO;
+    BOOLEAN NoCache = (Start != 0);
+    PVOID Buffer;
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    if (IsFatX)
+    {
+        SizeDirEntry = sizeof(FATX_DIR_ENTRY);
+        EntriesPerPage = FATX_ENTRIES_PER_PAGE;
+    }
+    else
+    {
+        SizeDirEntry = sizeof(FAT_DIR_ENTRY);
+        EntriesPerPage = FAT_ENTRIES_PER_PAGE;
+    }
 
-   DPRINT("Mounting VFAT device...\n");
+    FileOffset.QuadPart = Start;
+    if (!NoCache)
+    {
+        DeviceExt = Device;
+
+        /* FIXME: Check we really have a VCB
+        ASSERT();
+        */
+
+        ExAcquireResourceExclusiveLite(&DeviceExt->DirResource, TRUE);
+        pFcb = vfatOpenRootFCB(DeviceExt);
+        ExReleaseResourceLite(&DeviceExt->DirResource);
 
-   Status = VfatHasFileSystem(DeviceToMount, &RecognizedFS, &DeviceExt->FatInfo);
-   if (!NT_SUCCESS(Status))
-   {
-      return(Status);
-   }
-   DPRINT("MountVfatdev %d, PAGE_SIZE = %d\n", DeviceExt->FatInfo.BytesPerCluster, PAGE_SIZE);
+        _SEH2_TRY
+        {
+            CcMapData(pFcb->FileObject, &FileOffset, SizeDirEntry, MAP_WAIT, &Context, (PVOID*)&Entry);
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            Status = _SEH2_GetExceptionCode();
+        }
+        _SEH2_END;
+    }
+    else
+    {
+        DeviceObject = Device;
+
+        ASSERT(DeviceObject->Type == 3);
+
+        Buffer = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, TAG_VFAT);
+        if (Buffer != NULL)
+        {
+            Status = VfatReadDisk(DeviceObject, &FileOffset, PAGE_SIZE, (PUCHAR)Buffer, TRUE);
+            if (!NT_SUCCESS(Status))
+            {
+                ExFreePoolWithTag(Buffer, TAG_VFAT);
+            }
+            else
+            {
+                Entry = Buffer;
+            }
+        }
+        else
+        {
+            Status = STATUS_INSUFFICIENT_RESOURCES;
+        }
+    }
+
+    if (NT_SUCCESS(Status))
+    {
+        while (TRUE)
+        {
+            if (ENTRY_VOLUME(IsFatX, Entry))
+            {
+                /* copy volume label */
+                if (IsFatX)
+                {
+                    StringO.Buffer = (PCHAR)Entry->FatX.Filename;
+                    StringO.MaximumLength = StringO.Length = Entry->FatX.FilenameLength;
+                    RtlOemStringToUnicodeString(VolumeLabel, &StringO, FALSE);
+                }
+                else
+                {
+                    vfat8Dot3ToString(&Entry->Fat, VolumeLabel);
+                }
+                break;
+            }
+            if (ENTRY_END(IsFatX, Entry))
+            {
+                break;
+            }
+            DirIndex++;
+            Entry = (PDIR_ENTRY)((ULONG_PTR)Entry + SizeDirEntry);
+            if ((DirIndex % EntriesPerPage) == 0)
+            {
+                FileOffset.u.LowPart += PAGE_SIZE;
+
+                if (!NoCache)
+                {
+                    CcUnpinData(Context);
+
+                    _SEH2_TRY
+                    {
+                        CcMapData(pFcb->FileObject, &FileOffset, SizeDirEntry, MAP_WAIT, &Context, (PVOID*)&Entry);
+                    }
+                    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+                    {
+                        Status = _SEH2_GetExceptionCode();
+                    }
+                    _SEH2_END;
+                    if (!NT_SUCCESS(Status))
+                    {
+                        Context = NULL;
+                        break;
+                    }
+                }
+                else
+                {
+                    Status = VfatReadDisk(DeviceObject, &FileOffset, PAGE_SIZE, (PUCHAR)Buffer, TRUE);
+                    if (!NT_SUCCESS(Status))
+                    {
+                        break;
+                    }
+                    Entry = Buffer;
+                }
+            }
+        }
+        if (Context)
+        {
+            CcUnpinData(Context);
+        }
+        else if (NoCache)
+        {
+            ExFreePoolWithTag(Buffer, TAG_VFAT);
+        }
+    }
 
+    if (!NoCache)
+    {
+        ExAcquireResourceExclusiveLite(&DeviceExt->DirResource, TRUE);
+        vfatReleaseFCB(DeviceExt, pFcb);
+        ExReleaseResourceLite(&DeviceExt->DirResource);
+    }
 
-   return(STATUS_SUCCESS);
+    return STATUS_SUCCESS;
 }
 
 
-static NTSTATUS
-VfatMount (PVFAT_IRP_CONTEXT IrpContext)
 /*
  * FUNCTION: Mount the filesystem
  */
+static
+NTSTATUS
+VfatMount(
+    PVFAT_IRP_CONTEXT IrpContext)
 {
-   PDEVICE_OBJECT DeviceObject = NULL;
-   PDEVICE_EXTENSION DeviceExt = NULL;
-   BOOLEAN RecognizedFS;
-   NTSTATUS Status;
-   PVFATFCB Fcb = NULL;
-   PVFATFCB VolumeFcb = NULL;
-   PVFATCCB Ccb = NULL;
-   PDEVICE_OBJECT DeviceToMount;
-   PVPB Vpb;
-   UNICODE_STRING NameU = RTL_CONSTANT_STRING(L"\\$$Fat$$");
-   UNICODE_STRING VolumeNameU = RTL_CONSTANT_STRING(L"\\$$Volume$$");
-   ULONG HashTableSize;
-   ULONG eocMark;
-   FATINFO FatInfo;
-
-   DPRINT("VfatMount(IrpContext %p)\n", IrpContext);
-
-   ASSERT(IrpContext);
-
-   if (IrpContext->DeviceObject != VfatGlobalData->DeviceObject)
-   {
-      Status = STATUS_INVALID_DEVICE_REQUEST;
-      goto ByeBye;
-   }
-
-   DeviceToMount = IrpContext->Stack->Parameters.MountVolume.DeviceObject;
-   Vpb = IrpContext->Stack->Parameters.MountVolume.Vpb;
-
-   Status = VfatHasFileSystem (DeviceToMount, &RecognizedFS, &FatInfo);
-   if (!NT_SUCCESS(Status))
-   {
-      goto ByeBye;
-   }
-
-   if (RecognizedFS == FALSE)
-   {
-      DPRINT("VFAT: Unrecognized Volume\n");
-      Status = STATUS_UNRECOGNIZED_VOLUME;
-      goto ByeBye;
-   }
-
-   /* Use prime numbers for the table size */
-   if (FatInfo.FatType == FAT12)
-   {
-      HashTableSize = 4099; // 4096 = 4 * 1024
-   }
-   else if (FatInfo.FatType == FAT16 ||
-            FatInfo.FatType == FATX16)
-   {
-      HashTableSize = 16411; // 16384 = 16 * 1024
-   }
-   else
-   {
-      HashTableSize = 65537; // 65536 = 64 * 1024;
-   }
-   HashTableSize = FCB_HASH_TABLE_SIZE;
-   DPRINT("VFAT: Recognized volume\n");
-   Status = IoCreateDevice(VfatGlobalData->DriverObject,
-                           ROUND_UP(sizeof (DEVICE_EXTENSION), sizeof(ULONG)) + sizeof(HASHENTRY*) * HashTableSize,
-                           NULL,
-                           FILE_DEVICE_DISK_FILE_SYSTEM,
-                           DeviceToMount->Characteristics,
-                           FALSE,
-                           &DeviceObject);
-   if (!NT_SUCCESS(Status))
-   {
-      goto ByeBye;
-   }
-
-   DeviceObject->Flags = DeviceObject->Flags | DO_DIRECT_IO;
-   DeviceExt = (PVOID) DeviceObject->DeviceExtension;
-   RtlZeroMemory(DeviceExt, ROUND_UP(sizeof(DEVICE_EXTENSION), sizeof(ULONG)) + sizeof(HASHENTRY*) * HashTableSize);
-   DeviceExt->FcbHashTable = (HASHENTRY**)((ULONG_PTR)DeviceExt + ROUND_UP(sizeof(DEVICE_EXTENSION), sizeof(ULONG)));
-   DeviceExt->HashTableSize = HashTableSize;
-
-   /* use same vpb as device disk */
-   DeviceObject->Vpb = Vpb;
-   DeviceToMount->Vpb = Vpb;
-
-   Status = VfatMountDevice(DeviceExt, DeviceToMount);
-   if (!NT_SUCCESS(Status))
-   {
-      /* FIXME: delete device object */
-      goto ByeBye;
-   }
-
-   DPRINT("BytesPerSector:     %d\n", DeviceExt->FatInfo.BytesPerSector);
-   DPRINT("SectorsPerCluster:  %d\n", DeviceExt->FatInfo.SectorsPerCluster);
-   DPRINT("FATCount:           %d\n", DeviceExt->FatInfo.FATCount);
-   DPRINT("FATSectors:         %d\n", DeviceExt->FatInfo.FATSectors);
-   DPRINT("RootStart:          %d\n", DeviceExt->FatInfo.rootStart);
-   DPRINT("DataStart:          %d\n", DeviceExt->FatInfo.dataStart);
-   if (DeviceExt->FatInfo.FatType == FAT32)
-   {
-      DPRINT("RootCluster:        %d\n", DeviceExt->FatInfo.RootCluster);
-   }
-
-   switch (DeviceExt->FatInfo.FatType)
-   {
-      case FAT12:
-         DeviceExt->GetNextCluster = FAT12GetNextCluster;
-         DeviceExt->FindAndMarkAvailableCluster = FAT12FindAndMarkAvailableCluster;
-         DeviceExt->WriteCluster = FAT12WriteCluster;
-         DeviceExt->CleanShutBitMask = 0;
-         break;
-
-      case FAT16:
-      case FATX16:
-         DeviceExt->GetNextCluster = FAT16GetNextCluster;
-         DeviceExt->FindAndMarkAvailableCluster = FAT16FindAndMarkAvailableCluster;
-         DeviceExt->WriteCluster = FAT16WriteCluster;
-         DeviceExt->CleanShutBitMask = 0x8000;
-         break;
-
-      case FAT32:
-      case FATX32:
-         DeviceExt->GetNextCluster = FAT32GetNextCluster;
-         DeviceExt->FindAndMarkAvailableCluster = FAT32FindAndMarkAvailableCluster;
-         DeviceExt->WriteCluster = FAT32WriteCluster;
-         DeviceExt->CleanShutBitMask = 0x80000000;
-         break;
-   }
-
-   if (DeviceExt->FatInfo.FatType == FATX16
-      || DeviceExt->FatInfo.FatType == FATX32)
-   {
-      DeviceExt->Flags |= VCB_IS_FATX;
-      DeviceExt->GetNextDirEntry = FATXGetNextDirEntry;
-      DeviceExt->BaseDateYear = 2000;
-   }
-   else
-   {
-      DeviceExt->GetNextDirEntry = FATGetNextDirEntry;
-      DeviceExt->BaseDateYear = 1980;
-   }
-
-   DeviceExt->StorageDevice = DeviceToMount;
-   DeviceExt->StorageDevice->Vpb->DeviceObject = DeviceObject;
-   DeviceExt->StorageDevice->Vpb->RealDevice = DeviceExt->StorageDevice;
-   DeviceExt->StorageDevice->Vpb->Flags |= VPB_MOUNTED;
-   DeviceObject->StackSize = DeviceExt->StorageDevice->StackSize + 1;
-   DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
-
-   DPRINT("FsDeviceObject %p\n", DeviceObject);
-
-   /* Initialize this resource early ... it's used in VfatCleanup */
-   ExInitializeResourceLite(&DeviceExt->DirResource);
-
-   DeviceExt->FATFileObject = IoCreateStreamFileObject(NULL, DeviceExt->StorageDevice);
-   Fcb = vfatNewFCB(DeviceExt, &NameU);
-   if (Fcb == NULL)
-   {
-      Status = STATUS_INSUFFICIENT_RESOURCES;
-      goto ByeBye;
-   }
-   Ccb = ExAllocateFromNPagedLookasideList(&VfatGlobalData->CcbLookasideList);
-   if (Ccb == NULL)
-   {
-      Status =  STATUS_INSUFFICIENT_RESOURCES;
-      goto ByeBye;
-   }
-
-   RtlZeroMemory(Ccb, sizeof (VFATCCB));
-   DeviceExt->FATFileObject->FsContext = Fcb;
-   DeviceExt->FATFileObject->FsContext2 = Ccb;
-   DeviceExt->FATFileObject->SectionObjectPointer = &Fcb->SectionObjectPointers;
-   DeviceExt->FATFileObject->PrivateCacheMap = NULL;
-   DeviceExt->FATFileObject->Vpb = DeviceObject->Vpb;
-   Fcb->FileObject = DeviceExt->FATFileObject;
-
-   Fcb->Flags |= FCB_IS_FAT;
-
-   Fcb->RFCB.FileSize.QuadPart = DeviceExt->FatInfo.FATSectors * DeviceExt->FatInfo.BytesPerSector;
-   Fcb->RFCB.ValidDataLength = Fcb->RFCB.FileSize;
-   Fcb->RFCB.AllocationSize = Fcb->RFCB.FileSize;
-
-   CcInitializeCacheMap(DeviceExt->FATFileObject,
-                        (PCC_FILE_SIZES)(&Fcb->RFCB.AllocationSize),
-                        TRUE,
-                        &VfatGlobalData->CacheMgrCallbacks,
-                        Fcb);
-
-   DeviceExt->LastAvailableCluster = 2;
-   ExInitializeResourceLite(&DeviceExt->FatResource);
-
-   InitializeListHead(&DeviceExt->FcbListHead);
-
-   VolumeFcb = vfatNewFCB(DeviceExt, &VolumeNameU);
-   if (VolumeFcb == NULL)
-   {
-      Status = STATUS_INSUFFICIENT_RESOURCES;
-      goto ByeBye;
-   }
-   VolumeFcb->Flags = FCB_IS_VOLUME;
-   VolumeFcb->RFCB.FileSize.QuadPart = DeviceExt->FatInfo.Sectors * DeviceExt->FatInfo.BytesPerSector;
-   VolumeFcb->RFCB.ValidDataLength = VolumeFcb->RFCB.FileSize;
-   VolumeFcb->RFCB.AllocationSize = VolumeFcb->RFCB.FileSize;
-   DeviceExt->VolumeFcb = VolumeFcb;
-
-   ExAcquireResourceExclusiveLite(&VfatGlobalData->VolumeListLock, TRUE);
-   InsertHeadList(&VfatGlobalData->VolumeListHead, &DeviceExt->VolumeListEntry);
-   ExReleaseResourceLite(&VfatGlobalData->VolumeListLock);
-
-   /* read serial number */
-   DeviceObject->Vpb->SerialNumber = DeviceExt->FatInfo.VolumeID;
-
-   /* read volume label */
-   ReadVolumeLabel(DeviceExt,  DeviceObject->Vpb);
-
-   /* read clean shutdown bit status */
-   Status = GetNextCluster(DeviceExt, 1, &eocMark);
-   if (NT_SUCCESS(Status))
-   {
-      if (eocMark & DeviceExt->CleanShutBitMask)
-      {
-         /* unset clean shutdown bit */
-         eocMark &= ~DeviceExt->CleanShutBitMask;
-         WriteCluster(DeviceExt, 1, eocMark);
-         VolumeFcb->Flags |= VCB_CLEAR_DIRTY;
-      }
-   }
-   VolumeFcb->Flags |= VCB_IS_DIRTY;
-
-   FsRtlNotifyVolumeEvent(DeviceExt->FATFileObject, FSRTL_VOLUME_MOUNT);
-
-   Status = STATUS_SUCCESS;
+    PDEVICE_OBJECT DeviceObject = NULL;
+    PDEVICE_EXTENSION DeviceExt = NULL;
+    BOOLEAN RecognizedFS;
+    NTSTATUS Status;
+    PVFATFCB Fcb = NULL;
+    PVFATFCB VolumeFcb = NULL;
+    PVFATCCB Ccb = NULL;
+    PDEVICE_OBJECT DeviceToMount;
+    PVPB Vpb;
+    UNICODE_STRING NameU = RTL_CONSTANT_STRING(L"\\$$Fat$$");
+    UNICODE_STRING VolumeNameU = RTL_CONSTANT_STRING(L"\\$$Volume$$");
+    UNICODE_STRING VolumeLabelU;
+    ULONG HashTableSize;
+    ULONG i;
+    FATINFO FatInfo;
+    BOOLEAN Dirty;
+
+    DPRINT("VfatMount(IrpContext %p)\n", IrpContext);
+
+    ASSERT(IrpContext);
+
+    if (IrpContext->DeviceObject != VfatGlobalData->DeviceObject)
+    {
+        Status = STATUS_INVALID_DEVICE_REQUEST;
+        goto ByeBye;
+    }
+
+    DeviceToMount = IrpContext->Stack->Parameters.MountVolume.DeviceObject;
+    Vpb = IrpContext->Stack->Parameters.MountVolume.Vpb;
+
+    Status = VfatHasFileSystem(DeviceToMount, &RecognizedFS, &FatInfo, FALSE);
+    if (!NT_SUCCESS(Status))
+    {
+        goto ByeBye;
+    }
+
+    if (RecognizedFS == FALSE)
+    {
+        DPRINT("VFAT: Unrecognized Volume\n");
+        Status = STATUS_UNRECOGNIZED_VOLUME;
+        goto ByeBye;
+    }
+
+    /* Use prime numbers for the table size */
+    if (FatInfo.FatType == FAT12)
+    {
+        HashTableSize = 4099; // 4096 = 4 * 1024
+    }
+    else if (FatInfo.FatType == FAT16 ||
+             FatInfo.FatType == FATX16)
+    {
+        HashTableSize = 16411; // 16384 = 16 * 1024
+    }
+    else
+    {
+        HashTableSize = 65537; // 65536 = 64 * 1024;
+    }
+    DPRINT("VFAT: Recognized volume\n");
+    Status = IoCreateDevice(VfatGlobalData->DriverObject,
+                            ROUND_UP(sizeof (DEVICE_EXTENSION), sizeof(ULONG)) + sizeof(HASHENTRY*) * HashTableSize,
+                            NULL,
+                            FILE_DEVICE_DISK_FILE_SYSTEM,
+                            DeviceToMount->Characteristics,
+                            FALSE,
+                            &DeviceObject);
+    if (!NT_SUCCESS(Status))
+    {
+        goto ByeBye;
+    }
+
+    DeviceExt = DeviceObject->DeviceExtension;
+    RtlZeroMemory(DeviceExt, ROUND_UP(sizeof(DEVICE_EXTENSION), sizeof(ULONG)) + sizeof(HASHENTRY*) * HashTableSize);
+    DeviceExt->FcbHashTable = (HASHENTRY**)((ULONG_PTR)DeviceExt + ROUND_UP(sizeof(DEVICE_EXTENSION), sizeof(ULONG)));
+    DeviceExt->HashTableSize = HashTableSize;
+    DeviceExt->VolumeDevice = DeviceObject;
+
+    /* use same vpb as device disk */
+    DeviceObject->Vpb = Vpb;
+    DeviceToMount->Vpb = Vpb;
+
+    RtlCopyMemory(&DeviceExt->FatInfo, &FatInfo, sizeof(FATINFO));
+
+    DPRINT("BytesPerSector:     %u\n", DeviceExt->FatInfo.BytesPerSector);
+    DPRINT("SectorsPerCluster:  %u\n", DeviceExt->FatInfo.SectorsPerCluster);
+    DPRINT("FATCount:           %u\n", DeviceExt->FatInfo.FATCount);
+    DPRINT("FATSectors:         %u\n", DeviceExt->FatInfo.FATSectors);
+    DPRINT("RootStart:          %u\n", DeviceExt->FatInfo.rootStart);
+    DPRINT("DataStart:          %u\n", DeviceExt->FatInfo.dataStart);
+    if (DeviceExt->FatInfo.FatType == FAT32)
+    {
+        DPRINT("RootCluster:        %u\n", DeviceExt->FatInfo.RootCluster);
+    }
+
+    switch (DeviceExt->FatInfo.FatType)
+    {
+        case FAT12:
+            DeviceExt->GetNextCluster = FAT12GetNextCluster;
+            DeviceExt->FindAndMarkAvailableCluster = FAT12FindAndMarkAvailableCluster;
+            DeviceExt->WriteCluster = FAT12WriteCluster;
+            /* We don't define dirty bit functions here
+             * FAT12 doesn't have such bit and they won't get called
+             */
+            break;
+
+        case FAT16:
+        case FATX16:
+            DeviceExt->GetNextCluster = FAT16GetNextCluster;
+            DeviceExt->FindAndMarkAvailableCluster = FAT16FindAndMarkAvailableCluster;
+            DeviceExt->WriteCluster = FAT16WriteCluster;
+            DeviceExt->GetDirtyStatus = FAT16GetDirtyStatus;
+            DeviceExt->SetDirtyStatus = FAT16SetDirtyStatus;
+            break;
+
+        case FAT32:
+        case FATX32:
+            DeviceExt->GetNextCluster = FAT32GetNextCluster;
+            DeviceExt->FindAndMarkAvailableCluster = FAT32FindAndMarkAvailableCluster;
+            DeviceExt->WriteCluster = FAT32WriteCluster;
+            DeviceExt->GetDirtyStatus = FAT32GetDirtyStatus;
+            DeviceExt->SetDirtyStatus = FAT32SetDirtyStatus;
+            break;
+    }
+
+    if (DeviceExt->FatInfo.FatType == FATX16 ||
+        DeviceExt->FatInfo.FatType == FATX32)
+    {
+        DeviceExt->Flags |= VCB_IS_FATX;
+        DeviceExt->BaseDateYear = 2000;
+        RtlCopyMemory(&DeviceExt->Dispatch, &FatXDispatch, sizeof(VFAT_DISPATCH));
+    }
+    else
+    {
+        DeviceExt->BaseDateYear = 1980;
+        RtlCopyMemory(&DeviceExt->Dispatch, &FatDispatch, sizeof(VFAT_DISPATCH));
+    }
+
+    DeviceExt->StorageDevice = DeviceToMount;
+    DeviceExt->StorageDevice->Vpb->DeviceObject = DeviceObject;
+    DeviceExt->StorageDevice->Vpb->RealDevice = DeviceExt->StorageDevice;
+    DeviceExt->StorageDevice->Vpb->Flags |= VPB_MOUNTED;
+    DeviceObject->StackSize = DeviceExt->StorageDevice->StackSize + 1;
+    DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
+
+    DPRINT("FsDeviceObject %p\n", DeviceObject);
+
+    /* Initialize this resource early ... it's used in VfatCleanup */
+    ExInitializeResourceLite(&DeviceExt->DirResource);
+
+    DeviceExt->IoVPB = DeviceObject->Vpb;
+    DeviceExt->SpareVPB = ExAllocatePoolWithTag(NonPagedPool, sizeof(VPB), TAG_VFAT);
+    if (DeviceExt->SpareVPB == NULL)
+    {
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto ByeBye;
+    }
+
+    DeviceExt->Statistics = ExAllocatePoolWithTag(NonPagedPool,
+                                                  sizeof(STATISTICS) * VfatGlobalData->NumberProcessors,
+                                                  TAG_STATS);
+    if (DeviceExt->Statistics == NULL)
+    {
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto ByeBye;
+    }
+
+    RtlZeroMemory(DeviceExt->Statistics, sizeof(STATISTICS) * VfatGlobalData->NumberProcessors);
+    for (i = 0; i < VfatGlobalData->NumberProcessors; ++i)
+    {
+        DeviceExt->Statistics[i].Base.FileSystemType = FILESYSTEM_STATISTICS_TYPE_FAT;
+        DeviceExt->Statistics[i].Base.Version = 1;
+        DeviceExt->Statistics[i].Base.SizeOfCompleteStructure = sizeof(STATISTICS);
+    }
+
+    DeviceExt->FATFileObject = IoCreateStreamFileObject(NULL, DeviceExt->StorageDevice);
+    Fcb = vfatNewFCB(DeviceExt, &NameU);
+    if (Fcb == NULL)
+    {
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto ByeBye;
+    }
+
+    Ccb = ExAllocateFromNPagedLookasideList(&VfatGlobalData->CcbLookasideList);
+    if (Ccb == NULL)
+    {
+        Status =  STATUS_INSUFFICIENT_RESOURCES;
+        goto ByeBye;
+    }
+
+    RtlZeroMemory(Ccb, sizeof (VFATCCB));
+    DeviceExt->FATFileObject->FsContext = Fcb;
+    DeviceExt->FATFileObject->FsContext2 = Ccb;
+    DeviceExt->FATFileObject->SectionObjectPointer = &Fcb->SectionObjectPointers;
+    DeviceExt->FATFileObject->PrivateCacheMap = NULL;
+    DeviceExt->FATFileObject->Vpb = DeviceObject->Vpb;
+    Fcb->FileObject = DeviceExt->FATFileObject;
+
+    Fcb->Flags |= FCB_IS_FAT;
+
+    Fcb->RFCB.FileSize.QuadPart = DeviceExt->FatInfo.FATSectors * DeviceExt->FatInfo.BytesPerSector;
+    Fcb->RFCB.ValidDataLength = Fcb->RFCB.FileSize;
+    Fcb->RFCB.AllocationSize = Fcb->RFCB.FileSize;
+
+    _SEH2_TRY
+    {
+        CcInitializeCacheMap(DeviceExt->FATFileObject,
+                             (PCC_FILE_SIZES)(&Fcb->RFCB.AllocationSize),
+                             TRUE,
+                             &VfatGlobalData->CacheMgrCallbacks,
+                             Fcb);
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        Status = _SEH2_GetExceptionCode();
+        goto ByeBye;
+    }
+    _SEH2_END;
+
+    DeviceExt->LastAvailableCluster = 2;
+    CountAvailableClusters(DeviceExt, NULL);
+    ExInitializeResourceLite(&DeviceExt->FatResource);
+
+    InitializeListHead(&DeviceExt->FcbListHead);
+
+    VolumeFcb = vfatNewFCB(DeviceExt, &VolumeNameU);
+    if (VolumeFcb == NULL)
+    {
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto ByeBye;
+    }
+
+    VolumeFcb->Flags = FCB_IS_VOLUME;
+    VolumeFcb->RFCB.FileSize.QuadPart = (LONGLONG) DeviceExt->FatInfo.Sectors * DeviceExt->FatInfo.BytesPerSector;
+    VolumeFcb->RFCB.ValidDataLength = VolumeFcb->RFCB.FileSize;
+    VolumeFcb->RFCB.AllocationSize = VolumeFcb->RFCB.FileSize;
+    DeviceExt->VolumeFcb = VolumeFcb;
+
+    ExAcquireResourceExclusiveLite(&VfatGlobalData->VolumeListLock, TRUE);
+    InsertHeadList(&VfatGlobalData->VolumeListHead, &DeviceExt->VolumeListEntry);
+    ExReleaseResourceLite(&VfatGlobalData->VolumeListLock);
+
+    /* read serial number */
+    DeviceObject->Vpb->SerialNumber = DeviceExt->FatInfo.VolumeID;
+
+    /* read volume label */
+    VolumeLabelU.Buffer = DeviceObject->Vpb->VolumeLabel;
+    VolumeLabelU.Length = 0;
+    VolumeLabelU.MaximumLength = sizeof(DeviceObject->Vpb->VolumeLabel);
+    ReadVolumeLabel(DeviceExt, 0, vfatVolumeIsFatX(DeviceExt), &VolumeLabelU);
+    Vpb->VolumeLabelLength = VolumeLabelU.Length;
+
+    /* read dirty bit status */
+    Status = GetDirtyStatus(DeviceExt, &Dirty);
+    if (NT_SUCCESS(Status))
+    {
+        /* The volume wasn't dirty, it was properly dismounted */
+        if (!Dirty)
+        {
+            /* Mark it dirty now! */
+            SetDirtyStatus(DeviceExt, TRUE);
+            VolumeFcb->Flags |= VCB_CLEAR_DIRTY;
+        }
+        else
+        {
+            DPRINT1("Mounting a dirty volume\n");
+        }
+    }
+
+    VolumeFcb->Flags |= VCB_IS_DIRTY;
+    if (BooleanFlagOn(Vpb->RealDevice->Flags, DO_SYSTEM_BOOT_PARTITION))
+    {
+        SetFlag(DeviceExt->Flags, VCB_IS_SYS_OR_HAS_PAGE);
+    }
+
+    FsRtlNotifyVolumeEvent(DeviceExt->FATFileObject, FSRTL_VOLUME_MOUNT);
+    FsRtlNotifyInitializeSync(&DeviceExt->NotifySync);
+    InitializeListHead(&DeviceExt->NotifyList);
+
+    DPRINT("Mount success\n");
+
+    Status = STATUS_SUCCESS;
+
 ByeBye:
+    if (!NT_SUCCESS(Status))
+    {
+        /* Cleanup */
+        if (DeviceExt && DeviceExt->FATFileObject)
+            ObDereferenceObject (DeviceExt->FATFileObject);
+        if (DeviceExt && DeviceExt->SpareVPB)
+            ExFreePoolWithTag(DeviceExt->SpareVPB, TAG_VFAT);
+        if (DeviceExt && DeviceExt->Statistics)
+            ExFreePoolWithTag(DeviceExt->Statistics, TAG_STATS);
+        if (Fcb)
+            vfatDestroyFCB(Fcb);
+        if (Ccb)
+            vfatDestroyCCB(Ccb);
+        if (DeviceObject)
+            IoDeleteDevice(DeviceObject);
+    }
 
-  if (!NT_SUCCESS(Status))
-  {
-     // cleanup
-     if (DeviceExt && DeviceExt->FATFileObject)
-        ObDereferenceObject (DeviceExt->FATFileObject);
-     if (Fcb)
-        vfatDestroyFCB(Fcb);
-     if (Ccb)
-        vfatDestroyCCB(Ccb);
-     if (DeviceObject)
-       IoDeleteDevice(DeviceObject);
-     if (VolumeFcb)
-        vfatDestroyFCB(VolumeFcb);
-  }
-  return Status;
+    return Status;
 }
 
 
-static NTSTATUS
-VfatVerify (PVFAT_IRP_CONTEXT IrpContext)
 /*
  * FUNCTION: Verify the filesystem
  */
+static
+NTSTATUS
+VfatVerify(
+    PVFAT_IRP_CONTEXT IrpContext)
 {
-  PDEVICE_OBJECT DeviceToVerify;
-  NTSTATUS Status = STATUS_SUCCESS;
-  FATINFO FatInfo;
-  BOOLEAN RecognizedFS;
-  PDEVICE_EXTENSION DeviceExt = IrpContext->DeviceExt;
-
-  DPRINT("VfatVerify(IrpContext %p)\n", IrpContext);
-
-  DeviceToVerify = IrpContext->Stack->Parameters.VerifyVolume.DeviceObject;
-  Status = VfatBlockDeviceIoControl(DeviceToVerify,
-                                    IOCTL_DISK_CHECK_VERIFY,
-                                    NULL,
-                                    0,
-                                    NULL,
-                                    0,
-                                    TRUE);
-  DeviceToVerify->Flags &= ~DO_VERIFY_VOLUME;
-  if (!NT_SUCCESS(Status) && Status != STATUS_VERIFY_REQUIRED)
-    {
-      DPRINT("VfatBlockDeviceIoControl() failed (Status %lx)\n", Status);
-      Status = STATUS_WRONG_VOLUME;
-    }
-  else
-    {
-      Status = VfatHasFileSystem(DeviceToVerify, &RecognizedFS, &FatInfo);
-      if (!NT_SUCCESS(Status) || RecognizedFS == FALSE)
+    PDEVICE_OBJECT DeviceToVerify;
+    NTSTATUS Status;
+    FATINFO FatInfo;
+    BOOLEAN RecognizedFS;
+    PDEVICE_EXTENSION DeviceExt;
+    BOOLEAN AllowRaw;
+    PVPB Vpb;
+    ULONG ChangeCount, BufSize = sizeof(ChangeCount);
+
+    DPRINT("VfatVerify(IrpContext %p)\n", IrpContext);
+
+    DeviceToVerify = IrpContext->Stack->Parameters.VerifyVolume.DeviceObject;
+    DeviceExt = DeviceToVerify->DeviceExtension;
+    Vpb = IrpContext->Stack->Parameters.VerifyVolume.Vpb;
+    AllowRaw = BooleanFlagOn(IrpContext->Stack->Flags, SL_ALLOW_RAW_MOUNT);
+
+    if (!BooleanFlagOn(Vpb->RealDevice->Flags, DO_VERIFY_VOLUME))
+    {
+        DPRINT("Already verified\n");
+        return STATUS_SUCCESS;
+    }
+
+    Status = VfatBlockDeviceIoControl(DeviceExt->StorageDevice,
+                                      IOCTL_DISK_CHECK_VERIFY,
+                                      NULL,
+                                      0,
+                                      &ChangeCount,
+                                      &BufSize,
+                                      TRUE);
+    if (!NT_SUCCESS(Status) && Status != STATUS_VERIFY_REQUIRED)
+    {
+        DPRINT("VfatBlockDeviceIoControl() failed (Status %lx)\n", Status);
+        Status = (AllowRaw ? STATUS_WRONG_VOLUME : Status);
+    }
+    else
+    {
+        Status = VfatHasFileSystem(DeviceExt->StorageDevice, &RecognizedFS, &FatInfo, TRUE);
+        if (!NT_SUCCESS(Status) || RecognizedFS == FALSE)
         {
-          Status = STATUS_WRONG_VOLUME;
+            if (NT_SUCCESS(Status) || AllowRaw)
+            {
+                Status = STATUS_WRONG_VOLUME;
+            }
         }
-      else if (sizeof(FATINFO) == RtlCompareMemory(&FatInfo, &DeviceExt->FatInfo, sizeof(FATINFO)))
+        else if (sizeof(FATINFO) == RtlCompareMemory(&FatInfo, &DeviceExt->FatInfo, sizeof(FATINFO)))
         {
-          /*
-           * FIXME:
-           *   Preformated floppy disks have very often a serial number of 0000:0000.
-           *   We should calculate a crc sum over the sectors from the root directory as secondary volume number.
-           *   Each write to the root directory must update this crc sum.
-           */
-
+            WCHAR BufferU[MAXIMUM_VOLUME_LABEL_LENGTH / sizeof(WCHAR)];
+            UNICODE_STRING VolumeLabelU;
+            UNICODE_STRING VpbLabelU;
+
+            VolumeLabelU.Buffer = BufferU;
+            VolumeLabelU.Length = 0;
+            VolumeLabelU.MaximumLength = sizeof(BufferU);
+            Status = ReadVolumeLabel(DeviceExt->StorageDevice, FatInfo.rootStart * FatInfo.BytesPerSector, (FatInfo.FatType >= FATX16), &VolumeLabelU);
+            if (!NT_SUCCESS(Status))
+            {
+                if (AllowRaw)
+                {
+                    Status = STATUS_WRONG_VOLUME;
+                }
+            }
+            else
+            {
+                VpbLabelU.Buffer = Vpb->VolumeLabel;
+                VpbLabelU.Length = Vpb->VolumeLabelLength;
+                VpbLabelU.MaximumLength = sizeof(Vpb->VolumeLabel);
+
+                if (RtlCompareUnicodeString(&VpbLabelU, &VolumeLabelU, FALSE) != 0)
+                {
+                    Status = STATUS_WRONG_VOLUME;
+                }
+                else
+                {
+                    DPRINT1("Same volume\n");
+                }
+            }
         }
-      else
+        else
         {
-          Status = STATUS_WRONG_VOLUME;
+            Status = STATUS_WRONG_VOLUME;
         }
-     }
+    }
+
+    Vpb->RealDevice->Flags &= ~DO_VERIFY_VOLUME;
 
-  return Status;
+    return Status;
 }
 
 
-static NTSTATUS
-VfatGetVolumeBitmap(PVFAT_IRP_CONTEXT IrpContext)
+static
+NTSTATUS
+VfatGetVolumeBitmap(
+    PVFAT_IRP_CONTEXT IrpContext)
 {
-   DPRINT("VfatGetVolumeBitmap (IrpContext %p)\n", IrpContext);
-
-   return STATUS_INVALID_DEVICE_REQUEST;
+    DPRINT("VfatGetVolumeBitmap (IrpContext %p)\n", IrpContext);
+    return STATUS_INVALID_DEVICE_REQUEST;
 }
 
 
-static NTSTATUS
-VfatGetRetrievalPointers(PVFAT_IRP_CONTEXT IrpContext)
+static
+NTSTATUS
+VfatGetRetrievalPointers(
+    PVFAT_IRP_CONTEXT IrpContext)
 {
-   PIO_STACK_LOCATION Stack;
-   LARGE_INTEGER Vcn;
-   PRETRIEVAL_POINTERS_BUFFER RetrievalPointers;
-   PFILE_OBJECT FileObject;
-   ULONG MaxExtentCount;
-   PVFATFCB Fcb;
-   PDEVICE_EXTENSION DeviceExt;
-   ULONG FirstCluster;
-   ULONG CurrentCluster;
-   ULONG LastCluster;
-   NTSTATUS Status;
-
-   DPRINT("VfatGetRetrievalPointers(IrpContext %p)\n", IrpContext);
-
-   DeviceExt = IrpContext->DeviceExt;
-   FileObject = IrpContext->FileObject;
-   Stack = IrpContext->Stack;
-   if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(STARTING_VCN_INPUT_BUFFER) ||
-       Stack->Parameters.DeviceIoControl.Type3InputBuffer == NULL)
-   {
-      return STATUS_INVALID_PARAMETER;
-   }
-   if (IrpContext->Irp->UserBuffer == NULL ||
-       Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(RETRIEVAL_POINTERS_BUFFER))
-   {
-      return STATUS_BUFFER_TOO_SMALL;
-   }
-
-   Fcb = FileObject->FsContext;
-
-   ExAcquireResourceSharedLite(&Fcb->MainResource, TRUE);
-
-   Vcn = ((PSTARTING_VCN_INPUT_BUFFER)Stack->Parameters.DeviceIoControl.Type3InputBuffer)->StartingVcn;
-   RetrievalPointers = IrpContext->Irp->UserBuffer;
-
-   MaxExtentCount = ((Stack->Parameters.DeviceIoControl.OutputBufferLength - sizeof(RetrievalPointers->ExtentCount) - sizeof(RetrievalPointers->StartingVcn)) / sizeof(RetrievalPointers->Extents[0]));
-
-
-   if (Vcn.QuadPart >= Fcb->RFCB.AllocationSize.QuadPart / DeviceExt->FatInfo.BytesPerCluster)
-   {
-      Status = STATUS_INVALID_PARAMETER;
-      goto ByeBye;
-   }
-
-   CurrentCluster = FirstCluster = vfatDirEntryGetFirstCluster(DeviceExt, &Fcb->entry);
-   Status = OffsetToCluster(DeviceExt, FirstCluster,
-                            Vcn.u.LowPart * DeviceExt->FatInfo.BytesPerCluster,
-                            &CurrentCluster, FALSE);
-   if (!NT_SUCCESS(Status))
-   {
-      goto ByeBye;
-   }
-
-   RetrievalPointers->StartingVcn = Vcn;
-   RetrievalPointers->ExtentCount = 0;
-   RetrievalPointers->Extents[0].Lcn.u.HighPart = 0;
-   RetrievalPointers->Extents[0].Lcn.u.LowPart = CurrentCluster - 2;
-   LastCluster = 0;
-   while (CurrentCluster != 0xffffffff && RetrievalPointers->ExtentCount < MaxExtentCount)
-   {
-
-      LastCluster = CurrentCluster;
-      Status = NextCluster(DeviceExt, CurrentCluster, &CurrentCluster, FALSE);
-      Vcn.QuadPart++;
-      if (!NT_SUCCESS(Status))
-      {
-         goto ByeBye;
-      }
-
-      if (LastCluster + 1 != CurrentCluster)
-      {
-         RetrievalPointers->Extents[RetrievalPointers->ExtentCount].NextVcn = Vcn;
-         RetrievalPointers->ExtentCount++;
-         if (RetrievalPointers->ExtentCount < MaxExtentCount)
-         {
-            RetrievalPointers->Extents[RetrievalPointers->ExtentCount].Lcn.u.HighPart = 0;
-            RetrievalPointers->Extents[RetrievalPointers->ExtentCount].Lcn.u.LowPart = CurrentCluster - 2;
-         }
-      }
-   }
-
-   IrpContext->Irp->IoStatus.Information = sizeof(RETRIEVAL_POINTERS_BUFFER) + (sizeof(RetrievalPointers->Extents[0]) * (RetrievalPointers->ExtentCount - 1));
-   Status = STATUS_SUCCESS;
+    PIO_STACK_LOCATION Stack;
+    LARGE_INTEGER Vcn;
+    PRETRIEVAL_POINTERS_BUFFER RetrievalPointers;
+    PFILE_OBJECT FileObject;
+    ULONG MaxExtentCount;
+    PVFATFCB Fcb;
+    PDEVICE_EXTENSION DeviceExt;
+    ULONG FirstCluster;
+    ULONG CurrentCluster;
+    ULONG LastCluster;
+    NTSTATUS Status;
+
+    DPRINT("VfatGetRetrievalPointers(IrpContext %p)\n", IrpContext);
+
+    DeviceExt = IrpContext->DeviceExt;
+    FileObject = IrpContext->FileObject;
+    Stack = IrpContext->Stack;
+    if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(STARTING_VCN_INPUT_BUFFER) ||
+        Stack->Parameters.DeviceIoControl.Type3InputBuffer == NULL)
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    if (IrpContext->Irp->UserBuffer == NULL ||
+        Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(RETRIEVAL_POINTERS_BUFFER))
+    {
+        return STATUS_BUFFER_TOO_SMALL;
+    }
+
+    Fcb = FileObject->FsContext;
+
+    ExAcquireResourceSharedLite(&Fcb->MainResource, TRUE);
+
+    Vcn = ((PSTARTING_VCN_INPUT_BUFFER)Stack->Parameters.DeviceIoControl.Type3InputBuffer)->StartingVcn;
+    RetrievalPointers = IrpContext->Irp->UserBuffer;
+
+    MaxExtentCount = ((Stack->Parameters.DeviceIoControl.OutputBufferLength - sizeof(RetrievalPointers->ExtentCount) - sizeof(RetrievalPointers->StartingVcn)) / sizeof(RetrievalPointers->Extents[0]));
+
+    if (Vcn.QuadPart >= Fcb->RFCB.AllocationSize.QuadPart / DeviceExt->FatInfo.BytesPerCluster)
+    {
+        Status = STATUS_INVALID_PARAMETER;
+        goto ByeBye;
+    }
+
+    CurrentCluster = FirstCluster = vfatDirEntryGetFirstCluster(DeviceExt, &Fcb->entry);
+    Status = OffsetToCluster(DeviceExt, FirstCluster,
+                             Vcn.u.LowPart * DeviceExt->FatInfo.BytesPerCluster,
+                             &CurrentCluster, FALSE);
+    if (!NT_SUCCESS(Status))
+    {
+        goto ByeBye;
+    }
+
+    RetrievalPointers->StartingVcn = Vcn;
+    RetrievalPointers->ExtentCount = 0;
+    RetrievalPointers->Extents[0].Lcn.u.HighPart = 0;
+    RetrievalPointers->Extents[0].Lcn.u.LowPart = CurrentCluster - 2;
+    LastCluster = 0;
+    while (CurrentCluster != 0xffffffff && RetrievalPointers->ExtentCount < MaxExtentCount)
+    {
+        LastCluster = CurrentCluster;
+        Status = NextCluster(DeviceExt, CurrentCluster, &CurrentCluster, FALSE);
+        Vcn.QuadPart++;
+        if (!NT_SUCCESS(Status))
+        {
+            goto ByeBye;
+        }
+
+        if (LastCluster + 1 != CurrentCluster)
+        {
+            RetrievalPointers->Extents[RetrievalPointers->ExtentCount].NextVcn = Vcn;
+            RetrievalPointers->ExtentCount++;
+            if (RetrievalPointers->ExtentCount < MaxExtentCount)
+            {
+                RetrievalPointers->Extents[RetrievalPointers->ExtentCount].Lcn.u.HighPart = 0;
+                RetrievalPointers->Extents[RetrievalPointers->ExtentCount].Lcn.u.LowPart = CurrentCluster - 2;
+            }
+        }
+    }
+
+    IrpContext->Irp->IoStatus.Information = sizeof(RETRIEVAL_POINTERS_BUFFER) + (sizeof(RetrievalPointers->Extents[0]) * (RetrievalPointers->ExtentCount - 1));
+    Status = STATUS_SUCCESS;
 
 ByeBye:
-   ExReleaseResourceLite(&Fcb->MainResource);
+    ExReleaseResourceLite(&Fcb->MainResource);
 
-   return Status;
+    return Status;
+}
+
+static
+NTSTATUS
+VfatMoveFile(
+    PVFAT_IRP_CONTEXT IrpContext)
+{
+    DPRINT("VfatMoveFile(IrpContext %p)\n", IrpContext);
+    return STATUS_INVALID_DEVICE_REQUEST;
 }
 
-static NTSTATUS
-VfatMoveFile(PVFAT_IRP_CONTEXT IrpContext)
+static
+NTSTATUS
+VfatIsVolumeDirty(
+    PVFAT_IRP_CONTEXT IrpContext)
 {
-   DPRINT("VfatMoveFile(IrpContext %p)\n", IrpContext);
+    PULONG Flags;
+
+    DPRINT("VfatIsVolumeDirty(IrpContext %p)\n", IrpContext);
+
+    if (IrpContext->Stack->Parameters.FileSystemControl.OutputBufferLength != sizeof(ULONG))
+        return STATUS_INVALID_BUFFER_SIZE;
+    else if (!IrpContext->Irp->AssociatedIrp.SystemBuffer)
+        return STATUS_INVALID_USER_BUFFER;
+
+    Flags = (PULONG)IrpContext->Irp->AssociatedIrp.SystemBuffer;
+    *Flags = 0;
+
+    if (BooleanFlagOn(IrpContext->DeviceExt->VolumeFcb->Flags, VCB_IS_DIRTY) &&
+        !BooleanFlagOn(IrpContext->DeviceExt->VolumeFcb->Flags, VCB_CLEAR_DIRTY))
+    {
+        *Flags |= VOLUME_IS_DIRTY;
+    }
+
+    IrpContext->Irp->IoStatus.Information = sizeof(ULONG);
+
+    return STATUS_SUCCESS;
+}
+
+static
+NTSTATUS
+VfatMarkVolumeDirty(
+    PVFAT_IRP_CONTEXT IrpContext)
+{
+    PDEVICE_EXTENSION DeviceExt;
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    DPRINT("VfatMarkVolumeDirty(IrpContext %p)\n", IrpContext);
+    DeviceExt = IrpContext->DeviceExt;
+
+    if (!BooleanFlagOn(DeviceExt->VolumeFcb->Flags, VCB_IS_DIRTY))
+    {
+        Status = SetDirtyStatus(DeviceExt, TRUE);
+    }
+
+    DeviceExt->VolumeFcb->Flags &= ~VCB_CLEAR_DIRTY;
+
+    return Status;
+}
+
+static
+NTSTATUS
+VfatLockOrUnlockVolume(
+    PVFAT_IRP_CONTEXT IrpContext,
+    BOOLEAN Lock)
+{
+    PFILE_OBJECT FileObject;
+    PDEVICE_EXTENSION DeviceExt;
+    PVFATFCB Fcb;
+    PVPB Vpb;
+
+    DPRINT("VfatLockOrUnlockVolume(%p, %d)\n", IrpContext, Lock);
+
+    DeviceExt = IrpContext->DeviceExt;
+    FileObject = IrpContext->FileObject;
+    Fcb = FileObject->FsContext;
+    Vpb = DeviceExt->FATFileObject->Vpb;
+
+    /* Only allow locking with the volume open */
+    if (!BooleanFlagOn(Fcb->Flags, FCB_IS_VOLUME))
+    {
+        return STATUS_ACCESS_DENIED;
+    }
+
+    /* Bail out if it's already in the demanded state */
+    if ((BooleanFlagOn(DeviceExt->Flags, VCB_VOLUME_LOCKED) && Lock) ||
+        (!BooleanFlagOn(DeviceExt->Flags, VCB_VOLUME_LOCKED) && !Lock))
+    {
+        return STATUS_ACCESS_DENIED;
+    }
+
+    /* Bail out if it's already in the demanded state */
+    if ((BooleanFlagOn(Vpb->Flags, VPB_LOCKED) && Lock) ||
+        (!BooleanFlagOn(Vpb->Flags, VPB_LOCKED) && !Lock))
+    {
+        return STATUS_ACCESS_DENIED;
+    }
+
+    /* Deny locking if we're not alone */
+    if (Lock && DeviceExt->OpenHandleCount != 1)
+    {
+        PLIST_ENTRY ListEntry;
+
+#if 1
+        /* FIXME: Hack that allows locking the system volume on
+         * boot so that autochk can run properly
+         * That hack is, on purpose, really restrictive
+         * it will only allow locking with two directories
+         * open: current directory of smss and autochk.
+         */
+        BOOLEAN ForceLock = TRUE;
+        ULONG HandleCount = 0;
+
+        /* Only allow boot volume */
+        if (BooleanFlagOn(DeviceExt->Flags, VCB_IS_SYS_OR_HAS_PAGE))
+        {
+            /* We'll browse all the FCB */
+            ListEntry = DeviceExt->FcbListHead.Flink;
+            while (ListEntry != &DeviceExt->FcbListHead)
+            {
+                Fcb = CONTAINING_RECORD(ListEntry, VFATFCB, FcbListEntry);
+                ListEntry = ListEntry->Flink;
+
+                /* If no handle: that FCB is no problem for locking
+                 * so ignore it
+                 */
+                if (Fcb->OpenHandleCount == 0)
+                {
+                    continue;
+                }
+
+                /* Not a dir? We're no longer at boot */
+                if (!vfatFCBIsDirectory(Fcb))
+                {
+                    ForceLock = FALSE;
+                    break;
+                }
+
+                /* If we have cached initialized and several handles, we're
+                   not in the boot case
+                 */
+                if (Fcb->FileObject != NULL && Fcb->OpenHandleCount > 1)
+                {
+                    ForceLock = FALSE;
+                    break;
+                }
+
+                /* Count the handles */
+                HandleCount += Fcb->OpenHandleCount;
+                /* More than two handles? Then, we're not booting anymore */
+                if (HandleCount > 2)
+                {
+                    ForceLock = FALSE;
+                    break;
+                }
+            }
+        }
+        else
+        {
+            ForceLock = FALSE;
+        }
+
+        /* Here comes the hack, ignore the failure! */
+        if (!ForceLock)
+        {
+#endif
+
+        DPRINT1("Can't lock: %u opened\n", DeviceExt->OpenHandleCount);
+
+        ListEntry = DeviceExt->FcbListHead.Flink;
+        while (ListEntry != &DeviceExt->FcbListHead)
+        {
+            Fcb = CONTAINING_RECORD(ListEntry, VFATFCB, FcbListEntry);
+            ListEntry = ListEntry->Flink;
+
+            if (Fcb->OpenHandleCount  > 0)
+            {
+                DPRINT1("Opened (%u - %u): %wZ\n", Fcb->OpenHandleCount, Fcb->RefCount, &Fcb->PathNameU);
+            }
+        }
+
+        return STATUS_ACCESS_DENIED;
+
+#if 1
+        /* End of the hack: be verbose about its usage,
+         * just in case we would mess up everything!
+         */
+        }
+        else
+        {
+            DPRINT1("HACK: Using lock-hack!\n");
+        }
+#endif
+    }
 
-   return STATUS_INVALID_DEVICE_REQUEST;
+    /* Finally, proceed */
+    if (Lock)
+    {
+        DeviceExt->Flags |= VCB_VOLUME_LOCKED;
+        Vpb->Flags |= VPB_LOCKED;
+    }
+    else
+    {
+        DeviceExt->Flags &= ~VCB_VOLUME_LOCKED;
+        Vpb->Flags &= ~VPB_LOCKED;
+    }
+
+    return STATUS_SUCCESS;
 }
 
-static NTSTATUS
-VfatIsVolumeDirty(PVFAT_IRP_CONTEXT IrpContext)
+static
+NTSTATUS
+VfatDismountVolume(
+    PVFAT_IRP_CONTEXT IrpContext)
 {
-   PULONG Flags;
+    PDEVICE_EXTENSION DeviceExt;
+    PLIST_ENTRY NextEntry;
+    PVFATFCB Fcb;
+    PFILE_OBJECT FileObject;
+
+    DPRINT("VfatDismountVolume(%p)\n", IrpContext);
 
-   DPRINT("VfatIsVolumeDirty(IrpContext %p)\n", IrpContext);
+    DeviceExt = IrpContext->DeviceExt;
+    FileObject = IrpContext->FileObject;
 
-   if (IrpContext->Stack->Parameters.FileSystemControl.OutputBufferLength != sizeof(ULONG))
-      return STATUS_INVALID_BUFFER_SIZE;
-   else if (!IrpContext->Irp->AssociatedIrp.SystemBuffer)
-      return STATUS_INVALID_USER_BUFFER;
+    /* We HAVE to be locked. Windows also allows dismount with no lock
+     * but we're here mainly for 1st stage, so KISS
+     */
+    if (!BooleanFlagOn(DeviceExt->Flags, VCB_VOLUME_LOCKED))
+    {
+        return STATUS_ACCESS_DENIED;
+    }
 
-   Flags = (PULONG)IrpContext->Irp->AssociatedIrp.SystemBuffer;
-   *Flags = 0;
+    /* Deny dismount of boot volume */
+    if (BooleanFlagOn(DeviceExt->Flags, VCB_IS_SYS_OR_HAS_PAGE))
+    {
+        return STATUS_ACCESS_DENIED;
+    }
+
+    /* Race condition? */
+    if (BooleanFlagOn(DeviceExt->Flags, VCB_DISMOUNT_PENDING))
+    {
+        return STATUS_VOLUME_DISMOUNTED;
+    }
+
+    /* Notify we'll dismount. Pass that point there's no reason we fail */
+    FsRtlNotifyVolumeEvent(IrpContext->Stack->FileObject, FSRTL_VOLUME_DISMOUNT);
+
+    ExAcquireResourceExclusiveLite(&DeviceExt->FatResource, TRUE);
+
+    /* We're performing a clean shutdown */
+    if (BooleanFlagOn(DeviceExt->VolumeFcb->Flags, VCB_CLEAR_DIRTY))
+    {
+        /* Drop the dirty bit */
+        if (NT_SUCCESS(SetDirtyStatus(DeviceExt, FALSE)))
+            DeviceExt->VolumeFcb->Flags &= ~VCB_IS_DIRTY;
+    }
 
-   if (IrpContext->DeviceExt->VolumeFcb->Flags & VCB_IS_DIRTY
-      && !(IrpContext->DeviceExt->VolumeFcb->Flags & VCB_CLEAR_DIRTY))
-   {
-      *Flags |= VOLUME_IS_DIRTY;
-   }
+    /* Flush volume & files */
+    VfatFlushVolume(DeviceExt, (PVFATFCB)FileObject->FsContext);
 
-   return STATUS_SUCCESS;
+    /* Rebrowse the FCB in order to free them now */
+    while (!IsListEmpty(&DeviceExt->FcbListHead))
+    {
+        NextEntry = RemoveTailList(&DeviceExt->FcbListHead);
+        Fcb = CONTAINING_RECORD(NextEntry, VFATFCB, FcbListEntry);
+        vfatDestroyFCB(Fcb);
+    }
+
+    /* Mark we're being dismounted */
+    DeviceExt->Flags |= VCB_DISMOUNT_PENDING;
+#ifndef ENABLE_SWAPOUT
+    IrpContext->DeviceObject->Vpb->Flags &= ~VPB_MOUNTED;
+#endif
+
+    ExReleaseResourceLite(&DeviceExt->FatResource);
+
+    /* Release a few resources and quit, we're done */
+    ExFreePoolWithTag(DeviceExt->Statistics, TAG_STATS);
+    ExDeleteResourceLite(&DeviceExt->DirResource);
+    ExDeleteResourceLite(&DeviceExt->FatResource);
+    ObDereferenceObject(DeviceExt->FATFileObject);
+
+    return STATUS_SUCCESS;
 }
 
-static NTSTATUS
-VfatMarkVolumeDirty(PVFAT_IRP_CONTEXT IrpContext)
+static
+NTSTATUS
+VfatGetStatistics(
+    PVFAT_IRP_CONTEXT IrpContext)
 {
-   ULONG eocMark;
-   PDEVICE_EXTENSION DeviceExt;
-   NTSTATUS Status = STATUS_SUCCESS;
-
-   DPRINT("VfatMarkVolumeDirty(IrpContext %p)\n", IrpContext);
-   DeviceExt = IrpContext->DeviceExt;
-
-   if (!(DeviceExt->VolumeFcb->Flags & VCB_IS_DIRTY))
-   {
-      Status = GetNextCluster(DeviceExt, 1, &eocMark);
-      if (NT_SUCCESS(Status))
-      {
-         /* unset clean shutdown bit */
-         eocMark &= ~DeviceExt->CleanShutBitMask;
-         Status = WriteCluster(DeviceExt, 1, eocMark);
-      }
-   }
-
-   DeviceExt->VolumeFcb->Flags &= ~VCB_CLEAR_DIRTY;
-
-   return Status;
+    PVOID Buffer;
+    ULONG Length;
+    NTSTATUS Status;
+    PDEVICE_EXTENSION DeviceExt;
+
+    DeviceExt = IrpContext->DeviceExt;
+    Length = IrpContext->Stack->Parameters.FileSystemControl.OutputBufferLength;
+    Buffer = IrpContext->Irp->AssociatedIrp.SystemBuffer;
+
+    if (Length < sizeof(FILESYSTEM_STATISTICS))
+    {
+        return STATUS_BUFFER_TOO_SMALL;
+    }
+
+    if (Buffer == NULL)
+    {
+        return STATUS_INVALID_USER_BUFFER;
+    }
+
+    if (Length >= sizeof(STATISTICS) * VfatGlobalData->NumberProcessors)
+    {
+        Length = sizeof(STATISTICS) * VfatGlobalData->NumberProcessors;
+        Status = STATUS_SUCCESS;
+    }
+    else
+    {
+        Status = STATUS_BUFFER_OVERFLOW;
+    }
+
+    RtlCopyMemory(Buffer, DeviceExt->Statistics, Length);
+    IrpContext->Irp->IoStatus.Information = Length;
+
+    return Status;
 }
 
-NTSTATUS VfatFileSystemControl(PVFAT_IRP_CONTEXT IrpContext)
 /*
  * FUNCTION: File system control
  */
+NTSTATUS
+VfatFileSystemControl(
+    PVFAT_IRP_CONTEXT IrpContext)
 {
+    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;
+
+                case FSCTL_LOCK_VOLUME:
+                    Status = VfatLockOrUnlockVolume(IrpContext, TRUE);
+                    break;
+
+                case FSCTL_UNLOCK_VOLUME:
+                    Status = VfatLockOrUnlockVolume(IrpContext, FALSE);
+                    break;
+
+                case FSCTL_DISMOUNT_VOLUME:
+                    Status = VfatDismountVolume(IrpContext);
+                    break;
+
+                case FSCTL_FILESYSTEM_GET_STATISTICS:
+                    Status = VfatGetStatistics(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 %u\n", IrpContext->MinorFunction);
+            Status = STATUS_INVALID_DEVICE_REQUEST;
+            break;
+    }
 
-   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);
+    return Status;
 }