/*
* 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)
*
*/
#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 ****************************************************************/
/*
ULONG CurrentCluster,
PULONG NextCluster)
{
+ NTSTATUS Status = STATUS_SUCCESS;
PVOID BaseAddress;
ULONG FATOffset;
ULONG ChunkSize;
ChunkSize = CACHEPAGESIZE(DeviceExt);
FATOffset = CurrentCluster * sizeof(ULONG);
Offset.QuadPart = ROUND_DOWN(FATOffset, ChunkSize);
- if (!CcMapData(DeviceExt->FATFileObject, &Offset, ChunkSize, 1, &Context, &BaseAddress))
+ _SEH2_TRY
+ {
+ CcMapData(DeviceExt->FATFileObject, &Offset, ChunkSize, MAP_WAIT, &Context, &BaseAddress);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
- return STATUS_UNSUCCESSFUL;
+ _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_SUCCESS;
+ return Status;
}
/*
ULONG CurrentCluster,
PULONG NextCluster)
{
+ NTSTATUS Status = STATUS_SUCCESS;
PVOID BaseAddress;
ULONG FATOffset;
ULONG ChunkSize;
ChunkSize = CACHEPAGESIZE(DeviceExt);
FATOffset = CurrentCluster * 2;
Offset.QuadPart = ROUND_DOWN(FATOffset, ChunkSize);
- if (!CcMapData(DeviceExt->FATFileObject, &Offset, ChunkSize, MAP_WAIT, &Context, &BaseAddress))
+ _SEH2_TRY
+ {
+ CcMapData(DeviceExt->FATFileObject, &Offset, ChunkSize, MAP_WAIT, &Context, &BaseAddress);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
- return STATUS_UNSUCCESSFUL;
+ _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_SUCCESS;
+ return Status;
}
/*
*NextCluster = 0;
Offset.QuadPart = 0;
- if (!CcMapData(DeviceExt->FATFileObject, &Offset, DeviceExt->FatInfo.FATSectors * DeviceExt->FatInfo.BytesPerSector, 1, &Context, &BaseAddress))
+ _SEH2_TRY
{
- return STATUS_UNSUCCESSFUL;
+ 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;
CBlock = (PUSHORT)((char*)BaseAddress + (CurrentCluster * 12) / 8);
if ((CurrentCluster % 2) == 0)
Entry = 0xffffffff;
// DPRINT("Returning %x\n",Entry);
+ ASSERT(Entry != 0);
*NextCluster = Entry;
CcUnpinData(Context);
// return Entry == 0xffffffff ? STATUS_END_OF_FILE : STATUS_SUCCESS;
for (i = StartCluster; i < FatLength;)
{
Offset.QuadPart = ROUND_DOWN(i * 2, ChunkSize);
- if (!CcPinRead(DeviceExt->FATFileObject, &Offset, ChunkSize, 1, &Context, &BaseAddress))
+ _SEH2_TRY
+ {
+ CcPinRead(DeviceExt->FATFileObject, &Offset, ChunkSize, PIN_WAIT, &Context, &BaseAddress);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
- DPRINT1("CcMapData(Offset %x, Length %u) failed\n", (ULONG)Offset.QuadPart, ChunkSize);
- return STATUS_UNSUCCESSFUL;
+ 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);
*Cluster = 0;
StartCluster = DeviceExt->LastAvailableCluster;
Offset.QuadPart = 0;
- if (!CcPinRead(DeviceExt->FATFileObject, &Offset, DeviceExt->FatInfo.FATSectors * DeviceExt->FatInfo.BytesPerSector, 1, &Context, &BaseAddress))
+ _SEH2_TRY
{
- DPRINT1("CcMapData(Offset %x, Length %u) failed\n", (ULONG)Offset.QuadPart, DeviceExt->FatInfo.FATSectors * DeviceExt->FatInfo.BytesPerSector);
- return STATUS_UNSUCCESSFUL;
+ 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;)
{
Offset.QuadPart = ROUND_DOWN(i * 4, ChunkSize);
- if (!CcPinRead(DeviceExt->FATFileObject, &Offset, ChunkSize, 1, &Context, &BaseAddress))
+ _SEH2_TRY
+ {
+ CcPinRead(DeviceExt->FATFileObject, &Offset, ChunkSize, PIN_WAIT, &Context, &BaseAddress);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
- DPRINT1("CcMapData(Offset %x, Length %u) failed\n", (ULONG)Offset.QuadPart, ChunkSize);
- return STATUS_UNSUCCESSFUL;
+ 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);
PUSHORT CBlock;
Offset.QuadPart = 0;
- if (!CcMapData(DeviceExt->FATFileObject, &Offset, DeviceExt->FatInfo.FATSectors * DeviceExt->FatInfo.BytesPerSector, 1, &Context, &BaseAddress))
+ _SEH2_TRY
{
- return STATUS_UNSUCCESSFUL;
+ 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 < FatLength; )
{
Offset.QuadPart = ROUND_DOWN(i * 2, ChunkSize);
- if (!CcMapData(DeviceExt->FATFileObject, &Offset, ChunkSize, 1, &Context, &BaseAddress))
+ _SEH2_TRY
+ {
+ CcMapData(DeviceExt->FATFileObject, &Offset, ChunkSize, MAP_WAIT, &Context, &BaseAddress);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
- return STATUS_UNSUCCESSFUL;
+ _SEH2_YIELD(return _SEH2_GetExceptionCode());
}
+ _SEH2_END;
Block = (PUSHORT)((ULONG_PTR)BaseAddress + (i * 2) % ChunkSize);
BlockEnd = (PUSHORT)((ULONG_PTR)BaseAddress + ChunkSize);
for (i = 2; i < FatLength; )
{
Offset.QuadPart = ROUND_DOWN(i * 4, ChunkSize);
- if (!CcMapData(DeviceExt->FATFileObject, &Offset, ChunkSize, 1, &Context, &BaseAddress))
+ _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);
- return STATUS_UNSUCCESSFUL;
+ _SEH2_YIELD(return _SEH2_GetExceptionCode());
}
+ _SEH2_END;
Block = (PULONG)((ULONG_PTR)BaseAddress + (i * 4) % ChunkSize);
BlockEnd = (PULONG)((ULONG_PTR)BaseAddress + ChunkSize);
else
Status = FAT32CountAvailableClusters(DeviceExt);
}
- Clusters->QuadPart = DeviceExt->AvailableClusters;
+ if (Clusters != NULL)
+ {
+ Clusters->QuadPart = DeviceExt->AvailableClusters;
+ }
ExReleaseResourceLite (&DeviceExt->FatResource);
return Status;
LARGE_INTEGER Offset;
Offset.QuadPart = 0;
- if (!CcPinRead(DeviceExt->FATFileObject, &Offset, DeviceExt->FatInfo.FATSectors * DeviceExt->FatInfo.BytesPerSector, 1, &Context, &BaseAddress))
+ _SEH2_TRY
{
- return STATUS_UNSUCCESSFUL;
+ 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;
ChunkSize = CACHEPAGESIZE(DeviceExt);
FATOffset = ClusterToWrite * 2;
Offset.QuadPart = ROUND_DOWN(FATOffset, ChunkSize);
- if (!CcPinRead(DeviceExt->FATFileObject, &Offset, ChunkSize, 1, &Context, &BaseAddress))
+ _SEH2_TRY
+ {
+ CcPinRead(DeviceExt->FATFileObject, &Offset, ChunkSize, PIN_WAIT, &Context, &BaseAddress);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
- return STATUS_UNSUCCESSFUL;
+ _SEH2_YIELD(return _SEH2_GetExceptionCode());
}
+ _SEH2_END;
DPRINT("Writing 0x%x for offset 0x%x 0x%x\n", NewValue, FATOffset,
ClusterToWrite);
FATOffset = (ClusterToWrite * 4);
Offset.QuadPart = ROUND_DOWN(FATOffset, ChunkSize);
- if (!CcPinRead(DeviceExt->FATFileObject, &Offset, ChunkSize, 1, &Context, &BaseAddress))
+ _SEH2_TRY
{
- return STATUS_UNSUCCESSFUL;
+ 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);
DeviceExt, CurrentCluster);
if (CurrentCluster == 0)
- return STATUS_INVALID_PARAMETER;
+ {
+ 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);
return Status;
}
+/*
+ * FUNCTION: Retrieve the dirty status
+ */
+NTSTATUS
+GetDirtyStatus(
+ PDEVICE_EXTENSION DeviceExt,
+ PBOOLEAN DirtyStatus)
+{
+ NTSTATUS Status;
+
+ DPRINT("GetDirtyStatus(DeviceExt %p)\n", DeviceExt);
+
+ /* FAT12 has no dirty bit */
+ if (DeviceExt->FatInfo.FatType == FAT12)
+ {
+ *DirtyStatus = FALSE;
+ 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
+ */
+ 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
+
+ /* 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;
+ }
+
+ /* Return the status of the dirty bit */
+ if (Sector->Res4 & 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;
+}
+
+/*
+ * 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 */