[FASTFAT] Reduce the usage of the generic allocation tag
[reactos.git] / drivers / filesystems / fastfat / fat.c
index 0ad97fc..8d4ecd9 100644 (file)
 /*
  * COPYRIGHT:        See COPYING in the top level directory
  * PROJECT:          ReactOS kernel
- * FILE:             drivers/fs/vfat/fat.c
- * PURPOSE:          VFAT Filesystem
+ * FILE:             drivers/filesystems/fastfat/fat.c
+ * PURPOSE:          FastFAT Filesystem
  * PROGRAMMER:       Jason Filby (jasonfilby@yahoo.com)
+ *                   Pierre Schweitzer (pierre@reactos.org)
  *
  */
 
 /* INCLUDES *****************************************************************/
 
-#define NDEBUG
 #include "vfat.h"
 
+#define NDEBUG
+#include <debug.h>
+
 /* GLOBALS ******************************************************************/
 
 #define  CACHEPAGESIZE(pDeviceExt) ((pDeviceExt)->FatInfo.BytesPerCluster > PAGE_SIZE ? \
                   (pDeviceExt)->FatInfo.BytesPerCluster : PAGE_SIZE)
 
+/* FIXME: because volume is not cached, we have to perform direct IOs
+ * The day this is fixed, just comment out that line, and check
+ * it still works (and delete old code ;-))
+ */
+#define VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
+
 /* FUNCTIONS ****************************************************************/
 
-NTSTATUS
-FAT32GetNextCluster(PDEVICE_EXTENSION DeviceExt,
-                   ULONG CurrentCluster,
-                   PULONG NextCluster)
 /*
  * FUNCTION: Retrieve the next FAT32 cluster from the FAT table via a physical
  *           disk read
  */
+NTSTATUS
+FAT32GetNextCluster(
+    PDEVICE_EXTENSION DeviceExt,
+    ULONG CurrentCluster,
+    PULONG NextCluster)
 {
-  PVOID BaseAddress;
-  ULONG FATOffset;
-  ULONG ChunkSize;
-  PVOID Context;
-  LARGE_INTEGER Offset;
-
-  ChunkSize = CACHEPAGESIZE(DeviceExt);
-  FATOffset = CurrentCluster * sizeof(ULONG);
-  Offset.QuadPart = ROUND_DOWN(FATOffset, ChunkSize);
-  if(!CcMapData(DeviceExt->FATFileObject, &Offset, ChunkSize, 1, &Context, &BaseAddress))
-  {
-    return STATUS_UNSUCCESSFUL;
-  }
-  CurrentCluster = (*(PULONG)((char*)BaseAddress + (FATOffset % ChunkSize))) & 0x0fffffff;
-  if (CurrentCluster >= 0xffffff8 && CurrentCluster <= 0xfffffff)
-    CurrentCluster = 0xffffffff;
-  CcUnpinData(Context);
-  *NextCluster = CurrentCluster;
-  return (STATUS_SUCCESS);
+    NTSTATUS Status = STATUS_SUCCESS;
+    PVOID BaseAddress;
+    ULONG FATOffset;
+    ULONG ChunkSize;
+    PVOID Context;
+    LARGE_INTEGER Offset;
+
+    ChunkSize = CACHEPAGESIZE(DeviceExt);
+    FATOffset = CurrentCluster * sizeof(ULONG);
+    Offset.QuadPart = ROUND_DOWN(FATOffset, ChunkSize);
+    _SEH2_TRY
+    {
+        CcMapData(DeviceExt->FATFileObject, &Offset, ChunkSize, MAP_WAIT, &Context, &BaseAddress);
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        _SEH2_YIELD(return _SEH2_GetExceptionCode());
+    }
+    _SEH2_END;
+
+    CurrentCluster = (*(PULONG)((char*)BaseAddress + (FATOffset % ChunkSize))) & 0x0fffffff;
+    if (CurrentCluster >= 0xffffff8 && CurrentCluster <= 0xfffffff)
+        CurrentCluster = 0xffffffff;
+
+    if (CurrentCluster == 0)
+    {
+        DPRINT1("WARNING: File system corruption detected. You may need to run a disk repair utility.\n");
+        Status = STATUS_FILE_CORRUPT_ERROR;
+        if (VfatGlobalData->Flags & VFAT_BREAK_ON_CORRUPTION)
+            ASSERT(CurrentCluster != 0);
+    }
+    CcUnpinData(Context);
+    *NextCluster = CurrentCluster;
+    return Status;
 }
 
-NTSTATUS
-FAT16GetNextCluster(PDEVICE_EXTENSION DeviceExt,
-                   ULONG CurrentCluster,
-                   PULONG NextCluster)
 /*
  * FUNCTION: Retrieve the next FAT16 cluster from the FAT table
  */
+NTSTATUS
+FAT16GetNextCluster(
+    PDEVICE_EXTENSION DeviceExt,
+    ULONG CurrentCluster,
+    PULONG NextCluster)
 {
-  PVOID BaseAddress;
-  ULONG FATOffset;
-  ULONG ChunkSize;
-  PVOID Context;
-  LARGE_INTEGER Offset;
-
-  ChunkSize = CACHEPAGESIZE(DeviceExt);
-  FATOffset = CurrentCluster * 2;
-  Offset.QuadPart = ROUND_DOWN(FATOffset, ChunkSize);
-  if(!CcMapData(DeviceExt->FATFileObject, &Offset, ChunkSize, MAP_WAIT, &Context, &BaseAddress))
-  {
-    return STATUS_UNSUCCESSFUL;
-  }
-  CurrentCluster = *((PUSHORT)((char*)BaseAddress + (FATOffset % ChunkSize)));
-  if (CurrentCluster >= 0xfff8 && CurrentCluster <= 0xffff)
-    CurrentCluster = 0xffffffff;
-  CcUnpinData(Context);
-  *NextCluster = CurrentCluster;
-  return (STATUS_SUCCESS);
+    NTSTATUS Status = STATUS_SUCCESS;
+    PVOID BaseAddress;
+    ULONG FATOffset;
+    ULONG ChunkSize;
+    PVOID Context;
+    LARGE_INTEGER Offset;
+
+    ChunkSize = CACHEPAGESIZE(DeviceExt);
+    FATOffset = CurrentCluster * 2;
+    Offset.QuadPart = ROUND_DOWN(FATOffset, ChunkSize);
+    _SEH2_TRY
+    {
+        CcMapData(DeviceExt->FATFileObject, &Offset, ChunkSize, MAP_WAIT, &Context, &BaseAddress);
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        _SEH2_YIELD(return _SEH2_GetExceptionCode());
+    }
+    _SEH2_END;
+
+    CurrentCluster = *((PUSHORT)((char*)BaseAddress + (FATOffset % ChunkSize)));
+    if (CurrentCluster >= 0xfff8 && CurrentCluster <= 0xffff)
+        CurrentCluster = 0xffffffff;
+
+    if (CurrentCluster == 0)
+    {
+        DPRINT1("WARNING: File system corruption detected. You may need to run a disk repair utility.\n");
+        Status = STATUS_FILE_CORRUPT_ERROR;
+        if (VfatGlobalData->Flags & VFAT_BREAK_ON_CORRUPTION)
+            ASSERT(CurrentCluster != 0);
+    }
+
+    CcUnpinData(Context);
+    *NextCluster = CurrentCluster;
+    return Status;
 }
 
-NTSTATUS
-FAT12GetNextCluster(PDEVICE_EXTENSION DeviceExt,
-                   ULONG CurrentCluster,
-                   PULONG NextCluster)
 /*
  * FUNCTION: Retrieve the next FAT12 cluster from the FAT table
  */
+NTSTATUS
+FAT12GetNextCluster(
+    PDEVICE_EXTENSION DeviceExt,
+    ULONG CurrentCluster,
+    PULONG NextCluster)
 {
-  PUSHORT CBlock;
-  ULONG Entry;
-  PVOID BaseAddress;
-  PVOID Context;
-  LARGE_INTEGER Offset;
+    PUSHORT CBlock;
+    ULONG Entry;
+    PVOID BaseAddress;
+    PVOID Context;
+    LARGE_INTEGER Offset;
 
+    *NextCluster = 0;
 
-  *NextCluster = 0;
+    Offset.QuadPart = 0;
+    _SEH2_TRY
+    {
+        CcMapData(DeviceExt->FATFileObject, &Offset, DeviceExt->FatInfo.FATSectors * DeviceExt->FatInfo.BytesPerSector, MAP_WAIT, &Context, &BaseAddress);
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        _SEH2_YIELD(return _SEH2_GetExceptionCode());
+    }
+    _SEH2_END;
 
-  Offset.QuadPart = 0;
-  if(!CcMapData(DeviceExt->FATFileObject, &Offset, DeviceExt->FatInfo.FATSectors * DeviceExt->FatInfo.BytesPerSector, 1, &Context, &BaseAddress))
-  {
-    return STATUS_UNSUCCESSFUL;
-  }
-  CBlock = (PUSHORT)((char*)BaseAddress + (CurrentCluster * 12) / 8);
-  if ((CurrentCluster % 2) == 0)
+    CBlock = (PUSHORT)((char*)BaseAddress + (CurrentCluster * 12) / 8);
+    if ((CurrentCluster % 2) == 0)
     {
-      Entry = *CBlock & 0x0fff;
+         Entry = *CBlock & 0x0fff;
     }
-  else
+    else
     {
-      Entry = *CBlock >> 4;
+        Entry = *CBlock >> 4;
     }
-//  DPRINT("Entry %x\n",Entry);
-  if (Entry >= 0xff8 && Entry <= 0xfff)
-    Entry = 0xffffffff;
-//  DPRINT("Returning %x\n",Entry);
-  *NextCluster = Entry;
-  CcUnpinData(Context);
-//  return Entry == 0xffffffff ? STATUS_END_OF_FILE : STATUS_SUCCESS;
-  return STATUS_SUCCESS;
+
+//    DPRINT("Entry %x\n",Entry);
+    if (Entry >= 0xff8 && Entry <= 0xfff)
+        Entry = 0xffffffff;
+
+//    DPRINT("Returning %x\n",Entry);
+    ASSERT(Entry != 0);
+    *NextCluster = Entry;
+    CcUnpinData(Context);
+//    return Entry == 0xffffffff ? STATUS_END_OF_FILE : STATUS_SUCCESS;
+    return STATUS_SUCCESS;
 }
 
-NTSTATUS
-FAT16FindAndMarkAvailableCluster(PDEVICE_EXTENSION DeviceExt,
-                                 PULONG Cluster)
 /*
  * FUNCTION: Finds the first available cluster in a FAT16 table
  */
+NTSTATUS
+FAT16FindAndMarkAvailableCluster(
+    PDEVICE_EXTENSION DeviceExt,
+    PULONG Cluster)
 {
-  ULONG FatLength;
-  ULONG StartCluster;
-  ULONG i, j;
-  PVOID BaseAddress;
-  ULONG ChunkSize;
-  PVOID Context = 0;
-  LARGE_INTEGER Offset;
-  PUSHORT Block;
-  PUSHORT BlockEnd;
-
-  ChunkSize = CACHEPAGESIZE(DeviceExt);
-  FatLength = (DeviceExt->FatInfo.NumberOfClusters + 2);
-  *Cluster = 0;
-  StartCluster = DeviceExt->LastAvailableCluster;
-
-  for (j = 0; j < 2; j++)
-  {
-    for (i = StartCluster; i < FatLength; )
-    {
-      Offset.QuadPart = ROUND_DOWN(i * 2, ChunkSize);
-      if(!CcPinRead(DeviceExt->FATFileObject, &Offset, ChunkSize, 1, &Context, &BaseAddress))
-      {
-        DPRINT1("CcMapData(Offset %x, Length %u) failed\n", (ULONG)Offset.QuadPart, ChunkSize);
-        return STATUS_UNSUCCESSFUL;
-      }
-      Block = (PUSHORT)((ULONG_PTR)BaseAddress + (i * 2) % ChunkSize);
-      BlockEnd = (PUSHORT)((ULONG_PTR)BaseAddress + ChunkSize);
-
-      /* Now process the whole block */
-      while (Block < BlockEnd && i < FatLength)
-      {
-        if (*Block == 0)
+    ULONG FatLength;
+    ULONG StartCluster;
+    ULONG i, j;
+    PVOID BaseAddress;
+    ULONG ChunkSize;
+    PVOID Context = 0;
+    LARGE_INTEGER Offset;
+    PUSHORT Block;
+    PUSHORT BlockEnd;
+
+    ChunkSize = CACHEPAGESIZE(DeviceExt);
+    FatLength = (DeviceExt->FatInfo.NumberOfClusters + 2);
+    *Cluster = 0;
+    StartCluster = DeviceExt->LastAvailableCluster;
+
+    for (j = 0; j < 2; j++)
+    {
+        for (i = StartCluster; i < FatLength;)
         {
-          DPRINT("Found available cluster 0x%x\n", i);
-          DeviceExt->LastAvailableCluster = *Cluster = i;
-          *Block = 0xffff;
-          CcSetDirtyPinnedData(Context, NULL);
-          CcUnpinData(Context);
-          if (DeviceExt->AvailableClustersValid)
-            InterlockedDecrement((PLONG)&DeviceExt->AvailableClusters);
-          return(STATUS_SUCCESS);
+            Offset.QuadPart = ROUND_DOWN(i * 2, ChunkSize);
+            _SEH2_TRY
+            {
+                CcPinRead(DeviceExt->FATFileObject, &Offset, ChunkSize, PIN_WAIT, &Context, &BaseAddress);
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                DPRINT1("CcPinRead(Offset %x, Length %u) failed\n", (ULONG)Offset.QuadPart, ChunkSize);
+                _SEH2_YIELD(return _SEH2_GetExceptionCode());
+            }
+            _SEH2_END;
+
+            Block = (PUSHORT)((ULONG_PTR)BaseAddress + (i * 2) % ChunkSize);
+            BlockEnd = (PUSHORT)((ULONG_PTR)BaseAddress + ChunkSize);
+
+            /* Now process the whole block */
+            while (Block < BlockEnd && i < FatLength)
+            {
+                if (*Block == 0)
+                {
+                    DPRINT("Found available cluster 0x%x\n", i);
+                    DeviceExt->LastAvailableCluster = *Cluster = i;
+                    *Block = 0xffff;
+                    CcSetDirtyPinnedData(Context, NULL);
+                    CcUnpinData(Context);
+                    if (DeviceExt->AvailableClustersValid)
+                        InterlockedDecrement((PLONG)&DeviceExt->AvailableClusters);
+                    return STATUS_SUCCESS;
+                }
+
+                Block++;
+                i++;
+            }
+
+            CcUnpinData(Context);
         }
 
-        Block++;
-        i++;
-      }
-
-      CcUnpinData(Context);
+        FatLength = StartCluster;
+        StartCluster = 2;
     }
-    FatLength = StartCluster;
-    StartCluster = 2;
-  }
-  return(STATUS_DISK_FULL);
+
+    return STATUS_DISK_FULL;
 }
 
-NTSTATUS
-FAT12FindAndMarkAvailableCluster(PDEVICE_EXTENSION DeviceExt, PULONG Cluster)
 /*
  * FUNCTION: Finds the first available cluster in a FAT12 table
  */
+NTSTATUS
+FAT12FindAndMarkAvailableCluster(
+    PDEVICE_EXTENSION DeviceExt,
+    PULONG Cluster)
 {
-  ULONG FatLength;
-  ULONG StartCluster;
-  ULONG Entry;
-  PUSHORT CBlock;
-  ULONG i, j;
-  PVOID BaseAddress;
-  PVOID Context;
-  LARGE_INTEGER Offset;
-
-  FatLength = DeviceExt->FatInfo.NumberOfClusters + 2;
-  *Cluster = 0;
-  StartCluster = DeviceExt->LastAvailableCluster;
-  Offset.QuadPart = 0;
-  if(!CcPinRead(DeviceExt->FATFileObject, &Offset, DeviceExt->FatInfo.FATSectors * DeviceExt->FatInfo.BytesPerSector, 1, &Context, &BaseAddress))
-  {
-    DPRINT1("CcMapData(Offset %x, Length %u) failed\n", (ULONG)Offset.QuadPart, DeviceExt->FatInfo.FATSectors * DeviceExt->FatInfo.BytesPerSector);
-    return STATUS_UNSUCCESSFUL;
-  }
-
-  for (j = 0; j < 2; j++)
-  {
-    for (i = StartCluster; i < FatLength; i++)
-    {
-      CBlock = (PUSHORT)((char*)BaseAddress + (i * 12) / 8);
-      if ((i % 2) == 0)
-          {
-            Entry = *CBlock & 0xfff;
-          }
-      else
-          {
-            Entry = *CBlock >> 4;
-          }
-      if (Entry == 0)
-          {
-            DPRINT("Found available cluster 0x%x\n", i);
-            DeviceExt->LastAvailableCluster = *Cluster = i;
-            if ((i % 2) == 0)
-              *CBlock = (*CBlock & 0xf000) | 0xfff;
-            else
-              *CBlock = (*CBlock & 0xf) | 0xfff0;
-            CcSetDirtyPinnedData(Context, NULL);
-            CcUnpinData(Context);
-            if (DeviceExt->AvailableClustersValid)
-              InterlockedDecrement((PLONG)&DeviceExt->AvailableClusters);
-            return(STATUS_SUCCESS);
-          }
-    }
-    FatLength = StartCluster;
-    StartCluster = 2;
-  }
-  CcUnpinData(Context);
-  return (STATUS_DISK_FULL);
+    ULONG FatLength;
+    ULONG StartCluster;
+    ULONG Entry;
+    PUSHORT CBlock;
+    ULONG i, j;
+    PVOID BaseAddress;
+    PVOID Context;
+    LARGE_INTEGER Offset;
+
+    FatLength = DeviceExt->FatInfo.NumberOfClusters + 2;
+    *Cluster = 0;
+    StartCluster = DeviceExt->LastAvailableCluster;
+    Offset.QuadPart = 0;
+    _SEH2_TRY
+    {
+        CcPinRead(DeviceExt->FATFileObject, &Offset, DeviceExt->FatInfo.FATSectors * DeviceExt->FatInfo.BytesPerSector, PIN_WAIT, &Context, &BaseAddress);
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        DPRINT1("CcPinRead(Offset %x, Length %u) failed\n", (ULONG)Offset.QuadPart, DeviceExt->FatInfo.FATSectors * DeviceExt->FatInfo.BytesPerSector);
+        _SEH2_YIELD(return _SEH2_GetExceptionCode());
+    }
+    _SEH2_END;
+
+    for (j = 0; j < 2; j++)
+    {
+        for (i = StartCluster; i < FatLength; i++)
+        {
+            CBlock = (PUSHORT)((char*)BaseAddress + (i * 12) / 8);
+            if ((i % 2) == 0)
+            {
+                Entry = *CBlock & 0xfff;
+            }
+            else
+            {
+                Entry = *CBlock >> 4;
+            }
+
+            if (Entry == 0)
+            {
+                DPRINT("Found available cluster 0x%x\n", i);
+                DeviceExt->LastAvailableCluster = *Cluster = i;
+                if ((i % 2) == 0)
+                    *CBlock = (*CBlock & 0xf000) | 0xfff;
+                else
+                    *CBlock = (*CBlock & 0xf) | 0xfff0;
+                CcSetDirtyPinnedData(Context, NULL);
+                CcUnpinData(Context);
+                if (DeviceExt->AvailableClustersValid)
+                    InterlockedDecrement((PLONG)&DeviceExt->AvailableClusters);
+                return STATUS_SUCCESS;
+            }
+        }
+        FatLength = StartCluster;
+        StartCluster = 2;
+    }
+    CcUnpinData(Context);
+    return STATUS_DISK_FULL;
 }
 
-NTSTATUS
-FAT32FindAndMarkAvailableCluster (PDEVICE_EXTENSION DeviceExt, PULONG Cluster)
 /*
  * FUNCTION: Finds the first available cluster in a FAT32 table
  */
+NTSTATUS
+FAT32FindAndMarkAvailableCluster(
+    PDEVICE_EXTENSION DeviceExt,
+    PULONG Cluster)
 {
-  ULONG FatLength;
-  ULONG StartCluster;
-  ULONG i, j;
-  PVOID BaseAddress;
-  ULONG ChunkSize;
-  PVOID Context;
-  LARGE_INTEGER Offset;
-  PULONG Block;
-  PULONG BlockEnd;
-
-  ChunkSize = CACHEPAGESIZE(DeviceExt);
-  FatLength = (DeviceExt->FatInfo.NumberOfClusters + 2);
-  *Cluster = 0;
-  StartCluster = DeviceExt->LastAvailableCluster;
-
-  for (j = 0; j < 2; j++)
-  {
-    for (i = StartCluster; i < FatLength;)
-    {
-      Offset.QuadPart = ROUND_DOWN(i * 4, ChunkSize);
-      if(!CcPinRead(DeviceExt->FATFileObject, &Offset, ChunkSize, 1, &Context, &BaseAddress))
-      {
-        DPRINT1("CcMapData(Offset %x, Length %u) failed\n", (ULONG)Offset.QuadPart, ChunkSize);
-        return STATUS_UNSUCCESSFUL;
-      }
-      Block = (PULONG)((ULONG_PTR)BaseAddress + (i * 4) % ChunkSize);
-      BlockEnd = (PULONG)((ULONG_PTR)BaseAddress + ChunkSize);
-
-      /* Now process the whole block */
-      while (Block < BlockEnd && i < FatLength)
-      {
-        if ((*Block & 0x0fffffff) == 0)
+    ULONG FatLength;
+    ULONG StartCluster;
+    ULONG i, j;
+    PVOID BaseAddress;
+    ULONG ChunkSize;
+    PVOID Context;
+    LARGE_INTEGER Offset;
+    PULONG Block;
+    PULONG BlockEnd;
+
+    ChunkSize = CACHEPAGESIZE(DeviceExt);
+    FatLength = (DeviceExt->FatInfo.NumberOfClusters + 2);
+    *Cluster = 0;
+    StartCluster = DeviceExt->LastAvailableCluster;
+
+    for (j = 0; j < 2; j++)
+    {
+        for (i = StartCluster; i < FatLength;)
         {
-          DPRINT("Found available cluster 0x%x\n", i);
-          DeviceExt->LastAvailableCluster = *Cluster = i;
-          *Block = 0x0fffffff;
-          CcSetDirtyPinnedData(Context, NULL);
-          CcUnpinData(Context);
-          if (DeviceExt->AvailableClustersValid)
-            InterlockedDecrement((PLONG)&DeviceExt->AvailableClusters);
-          return(STATUS_SUCCESS);
+            Offset.QuadPart = ROUND_DOWN(i * 4, ChunkSize);
+            _SEH2_TRY
+            {
+                CcPinRead(DeviceExt->FATFileObject, &Offset, ChunkSize, PIN_WAIT, &Context, &BaseAddress);
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                DPRINT1("CcPinRead(Offset %x, Length %u) failed\n", (ULONG)Offset.QuadPart, ChunkSize);
+                _SEH2_YIELD(return _SEH2_GetExceptionCode());
+            }
+            _SEH2_END;
+            Block = (PULONG)((ULONG_PTR)BaseAddress + (i * 4) % ChunkSize);
+            BlockEnd = (PULONG)((ULONG_PTR)BaseAddress + ChunkSize);
+
+            /* Now process the whole block */
+            while (Block < BlockEnd && i < FatLength)
+            {
+                if ((*Block & 0x0fffffff) == 0)
+                {
+                    DPRINT("Found available cluster 0x%x\n", i);
+                    DeviceExt->LastAvailableCluster = *Cluster = i;
+                    *Block = 0x0fffffff;
+                    CcSetDirtyPinnedData(Context, NULL);
+                    CcUnpinData(Context);
+                    if (DeviceExt->AvailableClustersValid)
+                        InterlockedDecrement((PLONG)&DeviceExt->AvailableClusters);
+                    return STATUS_SUCCESS;
+                }
+
+                Block++;
+                i++;
+            }
+
+            CcUnpinData(Context);
         }
-
-        Block++;
-        i++;
-      }
-
-      CcUnpinData(Context);
+        FatLength = StartCluster;
+        StartCluster = 2;
     }
-    FatLength = StartCluster;
-    StartCluster = 2;
-  }
-  return (STATUS_DISK_FULL);
+    return STATUS_DISK_FULL;
 }
 
-static NTSTATUS
-FAT12CountAvailableClusters(PDEVICE_EXTENSION DeviceExt)
 /*
  * FUNCTION: Counts free cluster in a FAT12 table
  */
+static
+NTSTATUS
+FAT12CountAvailableClusters(
+    PDEVICE_EXTENSION DeviceExt)
 {
-  ULONG Entry;
-  PVOID BaseAddress;
-  ULONG ulCount = 0;
-  ULONG i;
-  ULONG numberofclusters;
-  LARGE_INTEGER Offset;
-  PVOID Context;
-  PUSHORT CBlock;
-
-  Offset.QuadPart = 0;
-  if(!CcMapData(DeviceExt->FATFileObject, &Offset, DeviceExt->FatInfo.FATSectors * DeviceExt->FatInfo.BytesPerSector, 1, &Context, &BaseAddress))
-  {
-    return STATUS_UNSUCCESSFUL;
-  }
-
-  numberofclusters = DeviceExt->FatInfo.NumberOfClusters + 2;
-
-  for (i = 2; i < numberofclusters; i++)
-    {
-    CBlock = (PUSHORT)((char*)BaseAddress + (i * 12) / 8);
-      if ((i % 2) == 0)
-       {
-      Entry = *CBlock & 0x0fff;
-       }
-      else
-       {
-      Entry = *CBlock >> 4;
-       }
-      if (Entry == 0)
-       ulCount++;
-    }
-
-  CcUnpinData(Context);
-  DeviceExt->AvailableClusters = ulCount;
-  DeviceExt->AvailableClustersValid = TRUE;
-
-  return(STATUS_SUCCESS);
+    ULONG Entry;
+    PVOID BaseAddress;
+    ULONG ulCount = 0;
+    ULONG i;
+    ULONG numberofclusters;
+    LARGE_INTEGER Offset;
+    PVOID Context;
+    PUSHORT CBlock;
+
+    Offset.QuadPart = 0;
+    _SEH2_TRY
+    {
+        CcMapData(DeviceExt->FATFileObject, &Offset, DeviceExt->FatInfo.FATSectors * DeviceExt->FatInfo.BytesPerSector, MAP_WAIT, &Context, &BaseAddress);
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        _SEH2_YIELD(return _SEH2_GetExceptionCode());
+    }
+    _SEH2_END;
+
+    numberofclusters = DeviceExt->FatInfo.NumberOfClusters + 2;
+
+    for (i = 2; i < numberofclusters; i++)
+    {
+        CBlock = (PUSHORT)((char*)BaseAddress + (i * 12) / 8);
+        if ((i % 2) == 0)
+        {
+            Entry = *CBlock & 0x0fff;
+        }
+        else
+        {
+            Entry = *CBlock >> 4;
+        }
+
+        if (Entry == 0)
+            ulCount++;
+    }
+
+    CcUnpinData(Context);
+    DeviceExt->AvailableClusters = ulCount;
+    DeviceExt->AvailableClustersValid = TRUE;
+
+    return STATUS_SUCCESS;
 }
 
 
-static NTSTATUS
-FAT16CountAvailableClusters(PDEVICE_EXTENSION DeviceExt)
 /*
  * FUNCTION: Counts free clusters in a FAT16 table
  */
+static
+NTSTATUS
+FAT16CountAvailableClusters(
+    PDEVICE_EXTENSION DeviceExt)
 {
-  PUSHORT Block;
-  PUSHORT BlockEnd;
-  PVOID BaseAddress = NULL;
-  ULONG ulCount = 0;
-  ULONG i;
-  ULONG ChunkSize;
-  PVOID Context = NULL;
-  LARGE_INTEGER Offset;
-  ULONG FatLength;
-
-  ChunkSize = CACHEPAGESIZE(DeviceExt);
-  FatLength = (DeviceExt->FatInfo.NumberOfClusters + 2);
-
-  for (i = 2; i < FatLength; )
-  {
-    Offset.QuadPart = ROUND_DOWN(i * 2, ChunkSize);
-    if(!CcMapData(DeviceExt->FATFileObject, &Offset, ChunkSize, 1, &Context, &BaseAddress))
+    PUSHORT Block;
+    PUSHORT BlockEnd;
+    PVOID BaseAddress = NULL;
+    ULONG ulCount = 0;
+    ULONG i;
+    ULONG ChunkSize;
+    PVOID Context = NULL;
+    LARGE_INTEGER Offset;
+    ULONG FatLength;
+
+    ChunkSize = CACHEPAGESIZE(DeviceExt);
+    FatLength = (DeviceExt->FatInfo.NumberOfClusters + 2);
+
+    for (i = 2; i < FatLength; )
     {
-      return STATUS_UNSUCCESSFUL;
-    }
-    Block = (PUSHORT)((ULONG_PTR)BaseAddress + (i * 2) % ChunkSize);
-    BlockEnd = (PUSHORT)((ULONG_PTR)BaseAddress + ChunkSize);
+        Offset.QuadPart = ROUND_DOWN(i * 2, ChunkSize);
+        _SEH2_TRY
+        {
+            CcMapData(DeviceExt->FATFileObject, &Offset, ChunkSize, MAP_WAIT, &Context, &BaseAddress);
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            _SEH2_YIELD(return _SEH2_GetExceptionCode());
+        }
+        _SEH2_END;
+        Block = (PUSHORT)((ULONG_PTR)BaseAddress + (i * 2) % ChunkSize);
+        BlockEnd = (PUSHORT)((ULONG_PTR)BaseAddress + ChunkSize);
 
-    /* Now process the whole block */
-    while (Block < BlockEnd && i < FatLength)
-    {
-      if (*Block == 0)
-        ulCount++;
-      Block++;
-      i++;
-    }
+        /* Now process the whole block */
+        while (Block < BlockEnd && i < FatLength)
+        {
+            if (*Block == 0)
+                ulCount++;
+            Block++;
+            i++;
+        }
 
-    CcUnpinData(Context);
-  }
+        CcUnpinData(Context);
+    }
 
-  DeviceExt->AvailableClusters = ulCount;
-  DeviceExt->AvailableClustersValid = TRUE;
+    DeviceExt->AvailableClusters = ulCount;
+    DeviceExt->AvailableClustersValid = TRUE;
 
-  return(STATUS_SUCCESS);
+    return STATUS_SUCCESS;
 }
 
 
-static NTSTATUS
-FAT32CountAvailableClusters(PDEVICE_EXTENSION DeviceExt)
 /*
  * FUNCTION: Counts free clusters in a FAT32 table
  */
+static
+NTSTATUS
+FAT32CountAvailableClusters(
+    PDEVICE_EXTENSION DeviceExt)
 {
-  PULONG Block;
-  PULONG BlockEnd;
-  PVOID BaseAddress = NULL;
-  ULONG ulCount = 0;
-  ULONG i;
-  ULONG ChunkSize;
-  PVOID Context = NULL;
-  LARGE_INTEGER Offset;
-  ULONG FatLength;
-
-  ChunkSize = CACHEPAGESIZE(DeviceExt);
-  FatLength = (DeviceExt->FatInfo.NumberOfClusters + 2);
-
-  for (i = 2; i < FatLength; )
-  {
-    Offset.QuadPart = ROUND_DOWN(i * 4, ChunkSize);
-    if(!CcMapData(DeviceExt->FATFileObject, &Offset, ChunkSize, 1, &Context, &BaseAddress))
+    PULONG Block;
+    PULONG BlockEnd;
+    PVOID BaseAddress = NULL;
+    ULONG ulCount = 0;
+    ULONG i;
+    ULONG ChunkSize;
+    PVOID Context = NULL;
+    LARGE_INTEGER Offset;
+    ULONG FatLength;
+
+    ChunkSize = CACHEPAGESIZE(DeviceExt);
+    FatLength = (DeviceExt->FatInfo.NumberOfClusters + 2);
+
+    for (i = 2; i < FatLength; )
     {
-      DPRINT1("CcMapData(Offset %x, Length %u) failed\n", (ULONG)Offset.QuadPart, ChunkSize);
-      return STATUS_UNSUCCESSFUL;
-    }
-    Block = (PULONG)((ULONG_PTR)BaseAddress + (i * 4) % ChunkSize);
-    BlockEnd = (PULONG)((ULONG_PTR)BaseAddress + ChunkSize);
+        Offset.QuadPart = ROUND_DOWN(i * 4, ChunkSize);
+        _SEH2_TRY
+        {
+            CcMapData(DeviceExt->FATFileObject, &Offset, ChunkSize, MAP_WAIT, &Context, &BaseAddress);
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            DPRINT1("CcMapData(Offset %x, Length %u) failed\n", (ULONG)Offset.QuadPart, ChunkSize);
+            _SEH2_YIELD(return _SEH2_GetExceptionCode());
+        }
+        _SEH2_END;
+        Block = (PULONG)((ULONG_PTR)BaseAddress + (i * 4) % ChunkSize);
+        BlockEnd = (PULONG)((ULONG_PTR)BaseAddress + ChunkSize);
 
-    /* Now process the whole block */
-    while (Block < BlockEnd && i < FatLength)
-    {
-      if ((*Block & 0x0fffffff) == 0)
-        ulCount++;
-      Block++;
-      i++;
-    }
+        /* Now process the whole block */
+        while (Block < BlockEnd && i < FatLength)
+        {
+            if ((*Block & 0x0fffffff) == 0)
+                ulCount++;
+            Block++;
+            i++;
+        }
 
-    CcUnpinData(Context);
-  }
+        CcUnpinData(Context);
+    }
 
-  DeviceExt->AvailableClusters = ulCount;
-  DeviceExt->AvailableClustersValid = TRUE;
+    DeviceExt->AvailableClusters = ulCount;
+    DeviceExt->AvailableClustersValid = TRUE;
 
-  return(STATUS_SUCCESS);
+    return STATUS_SUCCESS;
 }
 
 NTSTATUS
-CountAvailableClusters(PDEVICE_EXTENSION DeviceExt,
-                           PLARGE_INTEGER Clusters)
+CountAvailableClusters(
+    PDEVICE_EXTENSION DeviceExt,
+    PLARGE_INTEGER Clusters)
 {
-  NTSTATUS Status = STATUS_SUCCESS;
-  ExAcquireResourceExclusiveLite (&DeviceExt->FatResource, TRUE);
-  if (!DeviceExt->AvailableClustersValid)
-  {
-       if (DeviceExt->FatInfo.FatType == FAT12)
-         Status = FAT12CountAvailableClusters(DeviceExt);
-       else if (DeviceExt->FatInfo.FatType == FAT16 || DeviceExt->FatInfo.FatType == FATX16)
-         Status = FAT16CountAvailableClusters(DeviceExt);
-       else
-         Status = FAT32CountAvailableClusters(DeviceExt);
-    }
-  Clusters->QuadPart = DeviceExt->AvailableClusters;
-  ExReleaseResourceLite (&DeviceExt->FatResource);
-
-  return Status;
-}
-
-
+    NTSTATUS Status = STATUS_SUCCESS;
+    ExAcquireResourceExclusiveLite (&DeviceExt->FatResource, TRUE);
+    if (!DeviceExt->AvailableClustersValid)
+    {
+        if (DeviceExt->FatInfo.FatType == FAT12)
+            Status = FAT12CountAvailableClusters(DeviceExt);
+        else if (DeviceExt->FatInfo.FatType == FAT16 || DeviceExt->FatInfo.FatType == FATX16)
+            Status = FAT16CountAvailableClusters(DeviceExt);
+        else
+            Status = FAT32CountAvailableClusters(DeviceExt);
+    }
+    if (Clusters != NULL)
+    {
+        Clusters->QuadPart = DeviceExt->AvailableClusters;
+    }
+    ExReleaseResourceLite (&DeviceExt->FatResource);
 
+    return Status;
+}
 
 
-NTSTATUS
-FAT12WriteCluster(PDEVICE_EXTENSION DeviceExt,
-                 ULONG ClusterToWrite,
-                 ULONG NewValue,
-                 PULONG OldValue)
 /*
  * FUNCTION: Writes a cluster to the FAT12 physical and in-memory tables
  */
+NTSTATUS
+FAT12WriteCluster(
+    PDEVICE_EXTENSION DeviceExt,
+    ULONG ClusterToWrite,
+    ULONG NewValue,
+    PULONG OldValue)
 {
-  ULONG FATOffset;
-  PUCHAR CBlock;
-  PVOID BaseAddress;
-  PVOID Context;
-  LARGE_INTEGER Offset;
-
-  Offset.QuadPart = 0;
-  if(!CcPinRead(DeviceExt->FATFileObject, &Offset, DeviceExt->FatInfo.FATSectors * DeviceExt->FatInfo.BytesPerSector, 1, &Context, &BaseAddress))
-  {
-    return STATUS_UNSUCCESSFUL;
-  }
-  CBlock = (PUCHAR)BaseAddress;
-
-  FATOffset = (ClusterToWrite * 12) / 8;
-  DPRINT("Writing 0x%x for 0x%x at 0x%x\n",
-         NewValue, ClusterToWrite, FATOffset);
-  if ((ClusterToWrite % 2) == 0)
-    {
-      *OldValue = CBlock[FATOffset] + ((CBlock[FATOffset + 1] & 0x0f) << 8);
-      CBlock[FATOffset] = (UCHAR)NewValue;
-      CBlock[FATOffset + 1] &= 0xf0;
-      CBlock[FATOffset + 1] |= (NewValue & 0xf00) >> 8;
-    }
-  else
-    {
-      *OldValue = (CBlock[FATOffset] >> 4) + (CBlock[FATOffset + 1] << 4);
-      CBlock[FATOffset] &= 0x0f;
-      CBlock[FATOffset] |= (NewValue & 0xf) << 4;
-      CBlock[FATOffset + 1] = (UCHAR)(NewValue >> 4);
-    }
-  /* Write the changed FAT sector(s) to disk */
-  CcSetDirtyPinnedData(Context, NULL);
-  CcUnpinData(Context);
-  return(STATUS_SUCCESS);
+    ULONG FATOffset;
+    PUCHAR CBlock;
+    PVOID BaseAddress;
+    PVOID Context;
+    LARGE_INTEGER Offset;
+
+    Offset.QuadPart = 0;
+    _SEH2_TRY
+    {
+        CcPinRead(DeviceExt->FATFileObject, &Offset, DeviceExt->FatInfo.FATSectors * DeviceExt->FatInfo.BytesPerSector, PIN_WAIT, &Context, &BaseAddress);
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        _SEH2_YIELD(return _SEH2_GetExceptionCode());
+    }
+    _SEH2_END;
+    CBlock = (PUCHAR)BaseAddress;
+
+    FATOffset = (ClusterToWrite * 12) / 8;
+    DPRINT("Writing 0x%x for 0x%x at 0x%x\n",
+           NewValue, ClusterToWrite, FATOffset);
+    if ((ClusterToWrite % 2) == 0)
+    {
+        *OldValue = CBlock[FATOffset] + ((CBlock[FATOffset + 1] & 0x0f) << 8);
+        CBlock[FATOffset] = (UCHAR)NewValue;
+        CBlock[FATOffset + 1] &= 0xf0;
+        CBlock[FATOffset + 1] |= (NewValue & 0xf00) >> 8;
+    }
+    else
+    {
+        *OldValue = (CBlock[FATOffset] >> 4) + (CBlock[FATOffset + 1] << 4);
+        CBlock[FATOffset] &= 0x0f;
+        CBlock[FATOffset] |= (NewValue & 0xf) << 4;
+        CBlock[FATOffset + 1] = (UCHAR)(NewValue >> 4);
+    }
+    /* Write the changed FAT sector(s) to disk */
+    CcSetDirtyPinnedData(Context, NULL);
+    CcUnpinData(Context);
+    return STATUS_SUCCESS;
 }
 
-NTSTATUS
-FAT16WriteCluster(PDEVICE_EXTENSION DeviceExt,
-                 ULONG ClusterToWrite,
-                 ULONG NewValue,
-                 PULONG OldValue)
 /*
  * FUNCTION: Writes a cluster to the FAT16 physical and in-memory tables
  */
+NTSTATUS
+FAT16WriteCluster(
+    PDEVICE_EXTENSION DeviceExt,
+    ULONG ClusterToWrite,
+    ULONG NewValue,
+    PULONG OldValue)
 {
-  PVOID BaseAddress;
-  ULONG FATOffset;
-  ULONG ChunkSize;
-  PVOID Context;
-  LARGE_INTEGER Offset;
-  PUSHORT Cluster;
-
-  ChunkSize = CACHEPAGESIZE(DeviceExt);
-  FATOffset = ClusterToWrite * 2;
-  Offset.QuadPart = ROUND_DOWN(FATOffset, ChunkSize);
-  if(!CcPinRead(DeviceExt->FATFileObject, &Offset, ChunkSize, 1, &Context, &BaseAddress))
-  {
-    return STATUS_UNSUCCESSFUL;
-  }
-  DPRINT("Writing 0x%x for offset 0x%x 0x%x\n", NewValue, FATOffset,
-            ClusterToWrite);
-  Cluster = ((PUSHORT)((char*)BaseAddress + (FATOffset % ChunkSize)));
-  *OldValue = *Cluster;
-  *Cluster = (USHORT)NewValue;
-  CcSetDirtyPinnedData(Context, NULL);
-  CcUnpinData(Context);
-  return(STATUS_SUCCESS);
+    PVOID BaseAddress;
+    ULONG FATOffset;
+    ULONG ChunkSize;
+    PVOID Context;
+    LARGE_INTEGER Offset;
+    PUSHORT Cluster;
+
+    ChunkSize = CACHEPAGESIZE(DeviceExt);
+    FATOffset = ClusterToWrite * 2;
+    Offset.QuadPart = ROUND_DOWN(FATOffset, ChunkSize);
+    _SEH2_TRY
+    {
+        CcPinRead(DeviceExt->FATFileObject, &Offset, ChunkSize, PIN_WAIT, &Context, &BaseAddress);
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        _SEH2_YIELD(return _SEH2_GetExceptionCode());
+    }
+    _SEH2_END;
+
+    DPRINT("Writing 0x%x for offset 0x%x 0x%x\n", NewValue, FATOffset,
+           ClusterToWrite);
+    Cluster = ((PUSHORT)((char*)BaseAddress + (FATOffset % ChunkSize)));
+    *OldValue = *Cluster;
+    *Cluster = (USHORT)NewValue;
+    CcSetDirtyPinnedData(Context, NULL);
+    CcUnpinData(Context);
+    return STATUS_SUCCESS;
 }
 
-NTSTATUS
-FAT32WriteCluster(PDEVICE_EXTENSION DeviceExt,
-                 ULONG ClusterToWrite,
-                 ULONG NewValue,
-                 PULONG OldValue)
 /*
  * FUNCTION: Writes a cluster to the FAT32 physical tables
  */
+NTSTATUS
+FAT32WriteCluster(
+    PDEVICE_EXTENSION DeviceExt,
+    ULONG ClusterToWrite,
+    ULONG NewValue,
+    PULONG OldValue)
 {
-  PVOID BaseAddress;
-  ULONG FATOffset;
-  ULONG ChunkSize;
-  PVOID Context;
-  LARGE_INTEGER Offset;
-  PULONG Cluster;
-
-  ChunkSize = CACHEPAGESIZE(DeviceExt);
-
-  FATOffset = (ClusterToWrite * 4);
-  Offset.QuadPart = ROUND_DOWN(FATOffset, ChunkSize);
-  if(!CcPinRead(DeviceExt->FATFileObject, &Offset, ChunkSize, 1, &Context, &BaseAddress))
-  {
-    return STATUS_UNSUCCESSFUL;
-  }
-  DPRINT("Writing 0x%x for offset 0x%x 0x%x\n", NewValue, FATOffset,
-            ClusterToWrite);
-  Cluster = ((PULONG)((char*)BaseAddress + (FATOffset % ChunkSize)));
-  *OldValue = *Cluster & 0x0fffffff;
-  *Cluster = (*Cluster & 0xf0000000) | (NewValue & 0x0fffffff);
-
-  CcSetDirtyPinnedData(Context, NULL);
-  CcUnpinData(Context);
-
-  return(STATUS_SUCCESS);
+    PVOID BaseAddress;
+    ULONG FATOffset;
+    ULONG ChunkSize;
+    PVOID Context;
+    LARGE_INTEGER Offset;
+    PULONG Cluster;
+
+    ChunkSize = CACHEPAGESIZE(DeviceExt);
+
+    FATOffset = (ClusterToWrite * 4);
+    Offset.QuadPart = ROUND_DOWN(FATOffset, ChunkSize);
+    _SEH2_TRY
+    {
+        CcPinRead(DeviceExt->FATFileObject, &Offset, ChunkSize, PIN_WAIT, &Context, &BaseAddress);
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        _SEH2_YIELD(return _SEH2_GetExceptionCode());
+    }
+    _SEH2_END;
+
+    DPRINT("Writing 0x%x for offset 0x%x 0x%x\n", NewValue, FATOffset,
+           ClusterToWrite);
+    Cluster = ((PULONG)((char*)BaseAddress + (FATOffset % ChunkSize)));
+    *OldValue = *Cluster & 0x0fffffff;
+    *Cluster = (*Cluster & 0xf0000000) | (NewValue & 0x0fffffff);
+
+    CcSetDirtyPinnedData(Context, NULL);
+    CcUnpinData(Context);
+
+    return STATUS_SUCCESS;
 }
 
 
-NTSTATUS
-WriteCluster(PDEVICE_EXTENSION DeviceExt,
-            ULONG ClusterToWrite,
-            ULONG NewValue)
 /*
  * FUNCTION: Write a changed FAT entry
  */
+NTSTATUS
+WriteCluster(
+    PDEVICE_EXTENSION DeviceExt,
+    ULONG ClusterToWrite,
+    ULONG NewValue)
 {
-  NTSTATUS Status;
-  ULONG OldValue;
-  ExAcquireResourceExclusiveLite (&DeviceExt->FatResource, TRUE);
-  Status = DeviceExt->WriteCluster(DeviceExt, ClusterToWrite, NewValue, &OldValue);
-  if (DeviceExt->AvailableClustersValid)
-  {
-      if (OldValue && NewValue == 0)
-        InterlockedIncrement((PLONG)&DeviceExt->AvailableClusters);
-      else if (OldValue == 0 && NewValue)
-        InterlockedDecrement((PLONG)&DeviceExt->AvailableClusters);
-  }
-  ExReleaseResourceLite(&DeviceExt->FatResource);
-  return(Status);
+    NTSTATUS Status;
+    ULONG OldValue;
+
+    ExAcquireResourceExclusiveLite (&DeviceExt->FatResource, TRUE);
+    Status = DeviceExt->WriteCluster(DeviceExt, ClusterToWrite, NewValue, &OldValue);
+    if (DeviceExt->AvailableClustersValid)
+    {
+        if (OldValue && NewValue == 0)
+            InterlockedIncrement((PLONG)&DeviceExt->AvailableClusters);
+        else if (OldValue == 0 && NewValue)
+            InterlockedDecrement((PLONG)&DeviceExt->AvailableClusters);
+    }
+    ExReleaseResourceLite(&DeviceExt->FatResource);
+    return Status;
 }
 
-ULONGLONG
-ClusterToSector(PDEVICE_EXTENSION DeviceExt,
-               ULONG Cluster)
 /*
  * FUNCTION: Converts the cluster number to a sector number for this physical
  *           device
  */
+ULONGLONG
+ClusterToSector(
+    PDEVICE_EXTENSION DeviceExt,
+    ULONG Cluster)
 {
-  return DeviceExt->FatInfo.dataStart +
-    ((ULONGLONG)(Cluster - 2) * DeviceExt->FatInfo.SectorsPerCluster);
+    return DeviceExt->FatInfo.dataStart +
+           ((ULONGLONG)(Cluster - 2) * DeviceExt->FatInfo.SectorsPerCluster);
 
 }
 
-NTSTATUS
-GetNextCluster(PDEVICE_EXTENSION DeviceExt,
-              ULONG CurrentCluster,
-              PULONG NextCluster)
 /*
  * FUNCTION: Retrieve the next cluster depending on the FAT type
  */
+NTSTATUS
+GetNextCluster(
+    PDEVICE_EXTENSION DeviceExt,
+    ULONG CurrentCluster,
+    PULONG NextCluster)
 {
-  NTSTATUS Status;
+    NTSTATUS Status;
 
-  DPRINT ("GetNextCluster(DeviceExt %p, CurrentCluster %x)\n",
-         DeviceExt, CurrentCluster);
+    DPRINT("GetNextCluster(DeviceExt %p, CurrentCluster %x)\n",
+           DeviceExt, CurrentCluster);
 
-  if (CurrentCluster == 0)
-     return(STATUS_INVALID_PARAMETER);
+    if (CurrentCluster == 0)
+    {
+        DPRINT1("WARNING: File system corruption detected. You may need to run a disk repair utility.\n");
+        if (VfatGlobalData->Flags & VFAT_BREAK_ON_CORRUPTION)
+            ASSERT(CurrentCluster != 0);
+        return STATUS_FILE_CORRUPT_ERROR;
+    }
 
-  ExAcquireResourceSharedLite(&DeviceExt->FatResource, TRUE);
-  Status = DeviceExt->GetNextCluster(DeviceExt, CurrentCluster, NextCluster);
-  ExReleaseResourceLite(&DeviceExt->FatResource);
+    ExAcquireResourceSharedLite(&DeviceExt->FatResource, TRUE);
+    Status = DeviceExt->GetNextCluster(DeviceExt, CurrentCluster, NextCluster);
+    ExReleaseResourceLite(&DeviceExt->FatResource);
 
-  return(Status);
+    return Status;
 }
 
-NTSTATUS
-GetNextClusterExtend(PDEVICE_EXTENSION DeviceExt,
-                    ULONG CurrentCluster,
-                    PULONG NextCluster)
 /*
  * FUNCTION: Retrieve the next cluster depending on the FAT type
  */
+NTSTATUS
+GetNextClusterExtend(
+    PDEVICE_EXTENSION DeviceExt,
+    ULONG CurrentCluster,
+    PULONG NextCluster)
 {
-  NTSTATUS Status;
-
-  DPRINT ("GetNextClusterExtend(DeviceExt %p, CurrentCluster %x)\n",
-         DeviceExt, CurrentCluster);
-
-  ExAcquireResourceExclusiveLite(&DeviceExt->FatResource, TRUE);
-  /*
-   * If the file hasn't any clusters allocated then we need special
-   * handling
-   */
-  if (CurrentCluster == 0)
-  {
     ULONG NewCluster;
+    NTSTATUS Status;
 
-    Status = DeviceExt->FindAndMarkAvailableCluster(DeviceExt, &NewCluster);
-    if (!NT_SUCCESS(Status))
+    DPRINT("GetNextClusterExtend(DeviceExt %p, CurrentCluster %x)\n",
+           DeviceExt, CurrentCluster);
+
+    ExAcquireResourceExclusiveLite(&DeviceExt->FatResource, TRUE);
+    /*
+     * If the file hasn't any clusters allocated then we need special
+     * handling
+     */
+    if (CurrentCluster == 0)
     {
-      ExReleaseResourceLite(&DeviceExt->FatResource);
-      return Status;
+        Status = DeviceExt->FindAndMarkAvailableCluster(DeviceExt, &NewCluster);
+        if (!NT_SUCCESS(Status))
+        {
+            ExReleaseResourceLite(&DeviceExt->FatResource);
+            return Status;
+        }
+
+        *NextCluster = NewCluster;
+        ExReleaseResourceLite(&DeviceExt->FatResource);
+        return STATUS_SUCCESS;
+    }
+
+    Status = DeviceExt->GetNextCluster(DeviceExt, CurrentCluster, NextCluster);
+
+    if ((*NextCluster) == 0xFFFFFFFF)
+    {
+        /* We are after last existing cluster, we must add one to file */
+        /* Firstly, find the next available open allocation unit and
+           mark it as end of file */
+        Status = DeviceExt->FindAndMarkAvailableCluster(DeviceExt, &NewCluster);
+        if (!NT_SUCCESS(Status))
+        {
+            ExReleaseResourceLite(&DeviceExt->FatResource);
+            return Status;
+        }
+
+        /* Now, write the AU of the LastCluster with the value of the newly
+           found AU */
+        WriteCluster(DeviceExt, CurrentCluster, NewCluster);
+        *NextCluster = NewCluster;
     }
 
-    *NextCluster = NewCluster;
     ExReleaseResourceLite(&DeviceExt->FatResource);
-    return(STATUS_SUCCESS);
-  }
+    return Status;
+}
+
+/*
+ * FUNCTION: Retrieve the dirty status
+ */
+NTSTATUS
+GetDirtyStatus(
+    PDEVICE_EXTENSION DeviceExt,
+    PBOOLEAN DirtyStatus)
+{
+    NTSTATUS Status;
 
-  Status = DeviceExt->GetNextCluster(DeviceExt, CurrentCluster, NextCluster);
+    DPRINT("GetDirtyStatus(DeviceExt %p)\n", DeviceExt);
 
-  if ((*NextCluster) == 0xFFFFFFFF)
-  {
-     ULONG NewCluster;
+    /* FAT12 has no dirty bit */
+    if (DeviceExt->FatInfo.FatType == FAT12)
+    {
+        *DirtyStatus = FALSE;
+        return STATUS_SUCCESS;
+    }
 
-     /* We are after last existing cluster, we must add one to file */
-     /* Firstly, find the next available open allocation unit and
-        mark it as end of file */
-     Status = DeviceExt->FindAndMarkAvailableCluster(DeviceExt, &NewCluster);
-     if (!NT_SUCCESS(Status))
-     {
-        ExReleaseResourceLite(&DeviceExt->FatResource);
+    /* Not really in the FAT, but share the lock because
+     * we're really low-level and shouldn't happent that often
+     * And call the appropriate function
+     */
+    ExAcquireResourceSharedLite(&DeviceExt->FatResource, TRUE);
+    Status = DeviceExt->GetDirtyStatus(DeviceExt, DirtyStatus);
+    ExReleaseResourceLite(&DeviceExt->FatResource);
+
+    return Status;
+}
+
+NTSTATUS
+FAT16GetDirtyStatus(
+    PDEVICE_EXTENSION DeviceExt,
+    PBOOLEAN DirtyStatus)
+{
+    LARGE_INTEGER Offset;
+    ULONG Length;
+#ifdef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
+    NTSTATUS Status;
+#else
+    PVOID Context;
+#endif
+    struct _BootSector * Sector;
+
+    /* We'll read the bootsector at 0 */
+    Offset.QuadPart = 0;
+    Length = DeviceExt->FatInfo.BytesPerSector;
+#ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
+    /* Go through Cc for this */
+    _SEH2_TRY
+    {
+        CcPinRead(DeviceExt->VolumeFcb->FileObject, &Offset, Length, PIN_WAIT, &Context, (PVOID *)&Sector);
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        _SEH2_YIELD(return _SEH2_GetExceptionCode());
+    }
+    _SEH2_END;
+#else
+    /* No Cc, do it the old way:
+     * - Allocate a big enough buffer
+     * - And read the disk
+     */
+    Sector = ExAllocatePoolWithTag(NonPagedPool, Length, TAG_BUFFER);
+    if (Sector == NULL)
+    {
+        *DirtyStatus = TRUE;
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    Status = VfatReadDisk(DeviceExt->StorageDevice, &Offset, Length, (PUCHAR)Sector, FALSE);
+    if  (!NT_SUCCESS(Status))
+    {
+        *DirtyStatus = TRUE;
+        ExFreePoolWithTag(Sector, TAG_BUFFER);
+        return Status;
+    }
+#endif
+
+    /* Make sure we have a boot sector...
+     * FIXME: This check is a bit lame and should be improved
+     */
+    if (Sector->Signatur1 != 0xaa55)
+    {
+        /* Set we are dirty so that we don't attempt anything */
+        *DirtyStatus = TRUE;
+#ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
+        CcUnpinData(Context);
+#else
+        ExFreePoolWithTag(Sector, TAG_BUFFER);
+#endif
+        return STATUS_DISK_CORRUPT_ERROR;
+    }
+
+    /* Return the status of the dirty bit */
+    if (Sector->Res1 & FAT_DIRTY_BIT)
+        *DirtyStatus = TRUE;
+    else
+        *DirtyStatus = FALSE;
+
+#ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
+    CcUnpinData(Context);
+#else
+    ExFreePoolWithTag(Sector, TAG_BUFFER);
+#endif
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+FAT32GetDirtyStatus(
+    PDEVICE_EXTENSION DeviceExt,
+    PBOOLEAN DirtyStatus)
+{
+    LARGE_INTEGER Offset;
+    ULONG Length;
+#ifdef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
+    NTSTATUS Status;
+#else
+    PVOID Context;
+#endif
+    struct _BootSector32 * Sector;
+
+    /* We'll read the bootsector at 0 */
+    Offset.QuadPart = 0;
+    Length = DeviceExt->FatInfo.BytesPerSector;
+#ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
+    /* Go through Cc for this */
+    _SEH2_TRY
+    {
+        CcPinRead(DeviceExt->VolumeFcb->FileObject, &Offset, Length, PIN_WAIT, &Context, (PVOID *)&Sector);
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        _SEH2_YIELD(return _SEH2_GetExceptionCode());
+    }
+    _SEH2_END;
+#else
+    /* No Cc, do it the old way:
+     * - Allocate a big enough buffer
+     * - And read the disk
+     */
+    Sector = ExAllocatePoolWithTag(NonPagedPool, Length, TAG_BUFFER);
+    if (Sector == NULL)
+    {
+        *DirtyStatus = TRUE;
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    Status = VfatReadDisk(DeviceExt->StorageDevice, &Offset, Length, (PUCHAR)Sector, FALSE);
+    if  (!NT_SUCCESS(Status))
+    {
+        *DirtyStatus = TRUE;
+        ExFreePoolWithTag(Sector, TAG_BUFFER);
         return Status;
-     }
+    }
+#endif
 
-     /* Now, write the AU of the LastCluster with the value of the newly
-        found AU */
-     WriteCluster(DeviceExt, CurrentCluster, NewCluster);
-     *NextCluster = NewCluster;
-  }
+    /* Make sure we have a boot sector...
+     * FIXME: This check is a bit lame and should be improved
+     */
+    if (Sector->Signature1 != 0xaa55)
+    {
+        /* Set we are dirty so that we don't attempt anything */
+        *DirtyStatus = TRUE;
+#ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
+        CcUnpinData(Context);
+#else
+        ExFreePoolWithTag(Sector, TAG_BUFFER);
+#endif
+        return STATUS_DISK_CORRUPT_ERROR;
+    }
 
-  ExReleaseResourceLite(&DeviceExt->FatResource);
+    /* Return the status of the dirty bit */
+    if (Sector->Res4 & FAT_DIRTY_BIT)
+        *DirtyStatus = TRUE;
+    else
+        *DirtyStatus = FALSE;
 
-  return(Status);
+#ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
+    CcUnpinData(Context);
+#else
+    ExFreePoolWithTag(Sector, TAG_BUFFER);
+#endif
+    return STATUS_SUCCESS;
+}
+
+/*
+ * FUNCTION: Set the dirty status
+ */
+NTSTATUS
+SetDirtyStatus(
+    PDEVICE_EXTENSION DeviceExt,
+    BOOLEAN DirtyStatus)
+{
+    NTSTATUS Status;
+
+    DPRINT("SetDirtyStatus(DeviceExt %p, DirtyStatus %d)\n", DeviceExt, DirtyStatus);
+
+    /* FAT12 has no dirty bit */
+    if (DeviceExt->FatInfo.FatType == FAT12)
+    {
+        return STATUS_SUCCESS;
+    }
+
+    /* Not really in the FAT, but share the lock because
+     * we're really low-level and shouldn't happent that often
+     * And call the appropriate function
+     * Acquire exclusive because we will modify ondisk value
+     */
+    ExAcquireResourceExclusiveLite(&DeviceExt->FatResource, TRUE);
+    Status = DeviceExt->SetDirtyStatus(DeviceExt, DirtyStatus);
+    ExReleaseResourceLite(&DeviceExt->FatResource);
+
+    return Status;
+}
+
+NTSTATUS
+FAT16SetDirtyStatus(
+    PDEVICE_EXTENSION DeviceExt,
+    BOOLEAN DirtyStatus)
+{
+    LARGE_INTEGER Offset;
+    ULONG Length;
+#ifdef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
+    NTSTATUS Status;
+#else
+    PVOID Context;
+#endif
+    struct _BootSector * Sector;
+
+    /* We'll read (and then write) the bootsector at 0 */
+    Offset.QuadPart = 0;
+    Length = DeviceExt->FatInfo.BytesPerSector;
+#ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
+    /* Go through Cc for this */
+    _SEH2_TRY
+    {
+        CcPinRead(DeviceExt->VolumeFcb->FileObject, &Offset, Length, PIN_WAIT, &Context, (PVOID *)&Sector);
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        _SEH2_YIELD(return _SEH2_GetExceptionCode());
+    }
+    _SEH2_END;
+#else
+    /* No Cc, do it the old way:
+     * - Allocate a big enough buffer
+     * - And read the disk
+     */
+    Sector = ExAllocatePoolWithTag(NonPagedPool, Length, TAG_BUFFER);
+    if (Sector == NULL)
+    {
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    Status = VfatReadDisk(DeviceExt->StorageDevice, &Offset, Length, (PUCHAR)Sector, FALSE);
+    if  (!NT_SUCCESS(Status))
+    {
+        ExFreePoolWithTag(Sector, TAG_BUFFER);
+        return Status;
+    }
+#endif
+
+    /* Make sure we have a boot sector...
+     * FIXME: This check is a bit lame and should be improved
+     */
+    if (Sector->Signatur1 != 0xaa55)
+    {
+#ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
+        CcUnpinData(Context);
+#else
+        ExFreePoolWithTag(Sector, TAG_BUFFER);
+#endif
+        return STATUS_DISK_CORRUPT_ERROR;
+    }
+
+    /* Modify the dirty bit status according
+     * to caller needs
+     */
+    if (!DirtyStatus)
+    {
+        Sector->Res1 &= ~FAT_DIRTY_BIT;
+    }
+    else
+    {
+        Sector->Res1 |= FAT_DIRTY_BIT;
+    }
+
+#ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
+    /* Mark boot sector dirty so that it gets written to the disk */
+    CcSetDirtyPinnedData(Context, NULL);
+    CcUnpinData(Context);
+    return STATUS_SUCCESS;
+#else
+    /* Write back the boot sector to the disk */
+    Status = VfatWriteDisk(DeviceExt->StorageDevice, &Offset, Length, (PUCHAR)Sector, FALSE);
+    ExFreePoolWithTag(Sector, TAG_BUFFER);
+    return Status;
+#endif
+}
+
+NTSTATUS
+FAT32SetDirtyStatus(
+    PDEVICE_EXTENSION DeviceExt,
+    BOOLEAN DirtyStatus)
+{
+    LARGE_INTEGER Offset;
+    ULONG Length;
+#ifdef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
+    NTSTATUS Status;
+#else
+    PVOID Context;
+#endif
+    struct _BootSector32 * Sector;
+
+    /* We'll read (and then write) the bootsector at 0 */
+    Offset.QuadPart = 0;
+    Length = DeviceExt->FatInfo.BytesPerSector;
+#ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
+    /* Go through Cc for this */
+    _SEH2_TRY
+    {
+        CcPinRead(DeviceExt->VolumeFcb->FileObject, &Offset, Length, PIN_WAIT, &Context, (PVOID *)&Sector);
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        _SEH2_YIELD(return _SEH2_GetExceptionCode());
+    }
+    _SEH2_END;
+#else
+    /* No Cc, do it the old way:
+     * - Allocate a big enough buffer
+     * - And read the disk
+     */
+    Sector = ExAllocatePoolWithTag(NonPagedPool, Length, TAG_BUFFER);
+    if (Sector == NULL)
+    {
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    Status = VfatReadDisk(DeviceExt->StorageDevice, &Offset, Length, (PUCHAR)Sector, FALSE);
+    if  (!NT_SUCCESS(Status))
+    {
+        ExFreePoolWithTag(Sector, TAG_BUFFER);
+        return Status;
+    }
+#endif
+
+    /* Make sure we have a boot sector...
+     * FIXME: This check is a bit lame and should be improved
+     */
+    if (Sector->Signature1 != 0xaa55)
+    {
+        ASSERT(FALSE);
+#ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
+        CcUnpinData(Context);
+#else
+        ExFreePoolWithTag(Sector, TAG_BUFFER);
+#endif
+        return STATUS_DISK_CORRUPT_ERROR;
+    }
+
+    /* Modify the dirty bit status according
+     * to caller needs
+     */
+    if (!DirtyStatus)
+    {
+        Sector->Res4 &= ~FAT_DIRTY_BIT;
+    }
+    else
+    {
+        Sector->Res4 |= FAT_DIRTY_BIT;
+    }
+
+#ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
+    /* Mark boot sector dirty so that it gets written to the disk */
+    CcSetDirtyPinnedData(Context, NULL);
+    CcUnpinData(Context);
+    return STATUS_SUCCESS;
+#else
+    /* Write back the boot sector to the disk */
+    Status = VfatWriteDisk(DeviceExt->StorageDevice, &Offset, Length, (PUCHAR)Sector, FALSE);
+    ExFreePoolWithTag(Sector, TAG_BUFFER);
+    return Status;
+#endif
+}
+
+NTSTATUS
+FAT32UpdateFreeClustersCount(
+    PDEVICE_EXTENSION DeviceExt)
+{
+    LARGE_INTEGER Offset;
+    ULONG Length;
+#ifdef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
+    NTSTATUS Status;
+#else
+    PVOID Context;
+#endif
+    struct _FsInfoSector * Sector;
+
+    if (!DeviceExt->AvailableClustersValid)
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    /* We'll read (and then write) the fsinfo sector */
+    Offset.QuadPart = DeviceExt->FatInfo.FSInfoSector * DeviceExt->FatInfo.BytesPerSector;
+    Length = DeviceExt->FatInfo.BytesPerSector;
+#ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
+    /* Go through Cc for this */
+    _SEH2_TRY
+    {
+        CcPinRead(DeviceExt->VolumeFcb->FileObject, &Offset, Length, PIN_WAIT, &Context, (PVOID *)&Sector);
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        _SEH2_YIELD(return _SEH2_GetExceptionCode());
+    }
+    _SEH2_END;
+#else
+    /* No Cc, do it the old way:
+     * - Allocate a big enough buffer
+     * - And read the disk
+     */
+    Sector = ExAllocatePoolWithTag(NonPagedPool, Length, TAG_BUFFER);
+    if (Sector == NULL)
+    {
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    Status = VfatReadDisk(DeviceExt->StorageDevice, &Offset, Length, (PUCHAR)Sector, FALSE);
+    if  (!NT_SUCCESS(Status))
+    {
+        ExFreePoolWithTag(Sector, TAG_BUFFER);
+        return Status;
+    }
+#endif
+
+    /* Make sure we have a FSINFO sector */
+    if (Sector->ExtBootSignature2 != 0x41615252 ||
+        Sector->FSINFOSignature != 0x61417272 ||
+        Sector->Signatur2 != 0xaa550000)
+    {
+        ASSERT(FALSE);
+#ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
+        CcUnpinData(Context);
+#else
+        ExFreePoolWithTag(Sector, TAG_BUFFER);
+#endif
+        return STATUS_DISK_CORRUPT_ERROR;
+    }
+
+    /* Update the free clusters count */
+    Sector->FreeCluster = InterlockedCompareExchange((PLONG)&DeviceExt->AvailableClusters, 0, 0);
+
+#ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
+    /* Mark FSINFO sector dirty so that it gets written to the disk */
+    CcSetDirtyPinnedData(Context, NULL);
+    CcUnpinData(Context);
+    return STATUS_SUCCESS;
+#else
+    /* Write back the FSINFO sector to the disk */
+    Status = VfatWriteDisk(DeviceExt->StorageDevice, &Offset, Length, (PUCHAR)Sector, FALSE);
+    ExFreePoolWithTag(Sector, TAG_BUFFER);
+    return Status;
+#endif
 }
 
 /* EOF */