/*
* 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 %d) 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 %d) 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 %d) 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 %d) 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_VFAT);
+ 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_VFAT);
+ 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_VFAT);
+#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_VFAT);
+#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_VFAT);
+ 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_VFAT);
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_VFAT);
+#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_VFAT);
+#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_VFAT);
+ if (Sector == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ Status = VfatReadDisk(DeviceExt->StorageDevice, &Offset, Length, (PUCHAR)Sector, FALSE);
+ if (!NT_SUCCESS(Status))
+ {
+ ExFreePoolWithTag(Sector, TAG_VFAT);
+ 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_VFAT);
+#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_VFAT);
+ 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_VFAT);
+ if (Sector == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ Status = VfatReadDisk(DeviceExt->StorageDevice, &Offset, Length, (PUCHAR)Sector, FALSE);
+ if (!NT_SUCCESS(Status))
+ {
+ ExFreePoolWithTag(Sector, TAG_VFAT);
+ 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_VFAT);
+#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_VFAT);
+ 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_VFAT);
+ if (Sector == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ Status = VfatReadDisk(DeviceExt->StorageDevice, &Offset, Length, (PUCHAR)Sector, FALSE);
+ if (!NT_SUCCESS(Status))
+ {
+ ExFreePoolWithTag(Sector, TAG_VFAT);
+ 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_VFAT);
+#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_VFAT);
+ return Status;
+#endif
}
/* EOF */