mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 01:55:19 +00:00
[FASTFAT] Completely rewrite support for dirty volumes.
Until now, our support for dirty volumes was totally broken to a point where, on FAT32 volume, the dirty couldn't even be written nor read from the disk. This commit totally rewrites its handling, for both FAT16 and FAT32 so that it's now fully functionnal. Furthermore, it also gets totally compatible with our vfatlib, and thus, autochk. Now, on mount, FastFAT will check if the volume is dirty or not, and autochk will be able to ask for a repair if dirty. vfatlib will repair the volume and remove the dirty bit. So that, on next reboot, the volume will be mounted clean. As a reminder, the dirty bit is set immediately after mounting the volume, so that, if you crash or have a powercut, autochk will always attempt to repair your volume (with more or less, that's FAT!). If you want to experience without breaking your FAT volume, just boot, open a cmd prompt and type: fsutil dirty set c: and reboot! CORE-13758 CORE-13760 CORE-13759
This commit is contained in:
parent
efa75dd5b2
commit
7c01587680
5 changed files with 550 additions and 40 deletions
|
@ -248,6 +248,89 @@ again:
|
|||
return Status;
|
||||
}
|
||||
|
||||
/* Used by dirty bit code, likely to be killed the day it's properly handle
|
||||
* This is just a copy paste from VfatReadDisk()
|
||||
*/
|
||||
NTSTATUS
|
||||
VfatWriteDisk(
|
||||
IN PDEVICE_OBJECT pDeviceObject,
|
||||
IN PLARGE_INTEGER WriteOffset,
|
||||
IN ULONG WriteLength,
|
||||
IN OUT PUCHAR Buffer,
|
||||
IN BOOLEAN Override)
|
||||
{
|
||||
PIO_STACK_LOCATION Stack;
|
||||
PIRP Irp;
|
||||
IO_STATUS_BLOCK IoStatus;
|
||||
KEVENT Event;
|
||||
NTSTATUS Status;
|
||||
|
||||
again:
|
||||
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
||||
|
||||
DPRINT("VfatWriteDisk(pDeviceObject %p, Offset %I64x, Length %u, Buffer %p)\n",
|
||||
pDeviceObject, WriteOffset->QuadPart, WriteLength, Buffer);
|
||||
|
||||
DPRINT ("Building synchronous FSD Request...\n");
|
||||
Irp = IoBuildSynchronousFsdRequest(IRP_MJ_WRITE,
|
||||
pDeviceObject,
|
||||
Buffer,
|
||||
WriteLength,
|
||||
WriteOffset,
|
||||
&Event,
|
||||
&IoStatus);
|
||||
if (Irp == NULL)
|
||||
{
|
||||
DPRINT("IoBuildSynchronousFsdRequest failed\n");
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
if (Override)
|
||||
{
|
||||
Stack = IoGetNextIrpStackLocation(Irp);
|
||||
Stack->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
|
||||
}
|
||||
|
||||
DPRINT("Calling IO Driver... with irp %p\n", Irp);
|
||||
Status = IoCallDriver (pDeviceObject, Irp);
|
||||
|
||||
DPRINT("Waiting for IO Operation for %p\n", Irp);
|
||||
if (Status == STATUS_PENDING)
|
||||
{
|
||||
DPRINT("Operation pending\n");
|
||||
KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
|
||||
DPRINT("Getting IO Status... for %p\n", Irp);
|
||||
Status = IoStatus.Status;
|
||||
}
|
||||
|
||||
if (Status == STATUS_VERIFY_REQUIRED)
|
||||
{
|
||||
PDEVICE_OBJECT DeviceToVerify;
|
||||
|
||||
DPRINT1 ("Media change detected!\n");
|
||||
|
||||
/* Find the device to verify and reset the thread field to empty value again. */
|
||||
DeviceToVerify = IoGetDeviceToVerify(PsGetCurrentThread());
|
||||
IoSetDeviceToVerify(PsGetCurrentThread(), NULL);
|
||||
Status = IoVerifyVolume(DeviceToVerify,
|
||||
FALSE);
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("Volume verification successful; Reissuing write request\n");
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT("IO failed!!! VfatWriteDisk : Error code: %x\n", Status);
|
||||
DPRINT("(pDeviceObject %p, Offset %I64x, Size %u, Buffer %p\n",
|
||||
pDeviceObject, WriteOffset->QuadPart, WriteLength, Buffer);
|
||||
return Status;
|
||||
}
|
||||
DPRINT("Block request succeeded for %p\n", Irp);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
VfatWriteDiskPartial(
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
/*
|
||||
* 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)
|
||||
*
|
||||
*/
|
||||
|
||||
|
@ -19,6 +20,12 @@
|
|||
#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 ****************************************************************/
|
||||
|
||||
/*
|
||||
|
@ -818,4 +825,391 @@ GetNextClusterExtend(
|
|||
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
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
|
|
|
@ -531,9 +531,9 @@ VfatMount(
|
|||
UNICODE_STRING VolumeNameU = RTL_CONSTANT_STRING(L"\\$$Volume$$");
|
||||
UNICODE_STRING VolumeLabelU;
|
||||
ULONG HashTableSize;
|
||||
ULONG eocMark;
|
||||
ULONG i;
|
||||
FATINFO FatInfo;
|
||||
BOOLEAN Dirty;
|
||||
|
||||
DPRINT("VfatMount(IrpContext %p)\n", IrpContext);
|
||||
|
||||
|
@ -617,7 +617,9 @@ VfatMount(
|
|||
DeviceExt->GetNextCluster = FAT12GetNextCluster;
|
||||
DeviceExt->FindAndMarkAvailableCluster = FAT12FindAndMarkAvailableCluster;
|
||||
DeviceExt->WriteCluster = FAT12WriteCluster;
|
||||
DeviceExt->CleanShutBitMask = 0;
|
||||
/* We don't define dirty bit functions here
|
||||
* FAT12 doesn't have such bit and they won't get called
|
||||
*/
|
||||
break;
|
||||
|
||||
case FAT16:
|
||||
|
@ -625,7 +627,8 @@ VfatMount(
|
|||
DeviceExt->GetNextCluster = FAT16GetNextCluster;
|
||||
DeviceExt->FindAndMarkAvailableCluster = FAT16FindAndMarkAvailableCluster;
|
||||
DeviceExt->WriteCluster = FAT16WriteCluster;
|
||||
DeviceExt->CleanShutBitMask = 0x8000;
|
||||
DeviceExt->GetDirtyStatus = FAT16GetDirtyStatus;
|
||||
DeviceExt->SetDirtyStatus = FAT16SetDirtyStatus;
|
||||
break;
|
||||
|
||||
case FAT32:
|
||||
|
@ -633,7 +636,8 @@ VfatMount(
|
|||
DeviceExt->GetNextCluster = FAT32GetNextCluster;
|
||||
DeviceExt->FindAndMarkAvailableCluster = FAT32FindAndMarkAvailableCluster;
|
||||
DeviceExt->WriteCluster = FAT32WriteCluster;
|
||||
DeviceExt->CleanShutBitMask = 0x80000000;
|
||||
DeviceExt->GetDirtyStatus = FAT32GetDirtyStatus;
|
||||
DeviceExt->SetDirtyStatus = FAT32SetDirtyStatus;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -763,17 +767,21 @@ VfatMount(
|
|||
ReadVolumeLabel(DeviceExt, 0, vfatVolumeIsFatX(DeviceExt), &VolumeLabelU);
|
||||
Vpb->VolumeLabelLength = VolumeLabelU.Length;
|
||||
|
||||
/* read clean shutdown bit status */
|
||||
Status = GetNextCluster(DeviceExt, 1, &eocMark);
|
||||
/* read dirty bit status */
|
||||
Status = GetDirtyStatus(DeviceExt, &Dirty);
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
if (eocMark & DeviceExt->CleanShutBitMask)
|
||||
/* The volume wasn't dirty, it was properly dismounted */
|
||||
if (!Dirty)
|
||||
{
|
||||
/* unset clean shutdown bit */
|
||||
eocMark &= ~DeviceExt->CleanShutBitMask;
|
||||
WriteCluster(DeviceExt, 1, eocMark);
|
||||
/* Mark it dirty now! */
|
||||
SetDirtyStatus(DeviceExt, TRUE);
|
||||
VolumeFcb->Flags |= VCB_CLEAR_DIRTY;
|
||||
}
|
||||
else
|
||||
{
|
||||
DPRINT1("Mounting a dirty volume\n");
|
||||
}
|
||||
}
|
||||
|
||||
VolumeFcb->Flags |= VCB_IS_DIRTY;
|
||||
|
@ -1055,7 +1063,6 @@ NTSTATUS
|
|||
VfatMarkVolumeDirty(
|
||||
PVFAT_IRP_CONTEXT IrpContext)
|
||||
{
|
||||
ULONG eocMark;
|
||||
PDEVICE_EXTENSION DeviceExt;
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
|
||||
|
@ -1064,13 +1071,7 @@ VfatMarkVolumeDirty(
|
|||
|
||||
if (!BooleanFlagOn(DeviceExt->VolumeFcb->Flags, VCB_IS_DIRTY))
|
||||
{
|
||||
Status = GetNextCluster(DeviceExt, 1, &eocMark);
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
/* unset clean shutdown bit */
|
||||
eocMark &= ~DeviceExt->CleanShutBitMask;
|
||||
Status = WriteCluster(DeviceExt, 1, eocMark);
|
||||
}
|
||||
Status = SetDirtyStatus(DeviceExt, TRUE);
|
||||
}
|
||||
|
||||
DeviceExt->VolumeFcb->Flags &= ~VCB_CLEAR_DIRTY;
|
||||
|
@ -1237,8 +1238,6 @@ VfatDismountVolume(
|
|||
PLIST_ENTRY NextEntry;
|
||||
PVFATFCB Fcb;
|
||||
PFILE_OBJECT FileObject;
|
||||
ULONG eocMark;
|
||||
NTSTATUS Status;
|
||||
|
||||
DPRINT("VfatDismountVolume(%p)\n", IrpContext);
|
||||
|
||||
|
@ -1270,16 +1269,12 @@ VfatDismountVolume(
|
|||
|
||||
ExAcquireResourceExclusiveLite(&DeviceExt->FatResource, TRUE);
|
||||
|
||||
/* We're performing a clean shutdown */
|
||||
if (BooleanFlagOn(DeviceExt->VolumeFcb->Flags, VCB_CLEAR_DIRTY))
|
||||
{
|
||||
/* Set clean shutdown bit */
|
||||
Status = GetNextCluster(DeviceExt, 1, &eocMark);
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
eocMark |= DeviceExt->CleanShutBitMask;
|
||||
if (NT_SUCCESS(WriteCluster(DeviceExt, 1, eocMark)))
|
||||
DeviceExt->VolumeFcb->Flags &= ~VCB_IS_DIRTY;
|
||||
}
|
||||
/* Drop the dirty bit */
|
||||
if (NT_SUCCESS(SetDirtyStatus(DeviceExt, FALSE)))
|
||||
DeviceExt->VolumeFcb->Flags &= ~VCB_IS_DIRTY;
|
||||
}
|
||||
|
||||
/* Flush volume & files */
|
||||
|
|
|
@ -55,7 +55,6 @@ VfatShutdown(
|
|||
NTSTATUS Status;
|
||||
PLIST_ENTRY ListEntry;
|
||||
PDEVICE_EXTENSION DeviceExt;
|
||||
ULONG eocMark;
|
||||
|
||||
DPRINT("VfatShutdown(DeviceObject %p, Irp %p)\n",DeviceObject, Irp);
|
||||
|
||||
|
@ -74,16 +73,12 @@ VfatShutdown(
|
|||
ListEntry = ListEntry->Flink;
|
||||
|
||||
ExAcquireResourceExclusiveLite(&DeviceExt->DirResource, TRUE);
|
||||
/* It was a clean volume mounted */
|
||||
if (DeviceExt->VolumeFcb->Flags & VCB_CLEAR_DIRTY)
|
||||
{
|
||||
/* set clean shutdown bit */
|
||||
Status = GetNextCluster(DeviceExt, 1, &eocMark);
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
eocMark |= DeviceExt->CleanShutBitMask;
|
||||
if (NT_SUCCESS(WriteCluster(DeviceExt, 1, eocMark)))
|
||||
DeviceExt->VolumeFcb->Flags &= ~VCB_IS_DIRTY;
|
||||
}
|
||||
/* So, drop the dirty bit we set */
|
||||
if (NT_SUCCESS(SetDirtyStatus(DeviceExt, FALSE)))
|
||||
DeviceExt->VolumeFcb->Flags &= ~VCB_IS_DIRTY;
|
||||
}
|
||||
|
||||
Status = VfatFlushVolume(DeviceExt, DeviceExt->VolumeFcb);
|
||||
|
|
|
@ -83,6 +83,8 @@ struct _BootSector32
|
|||
unsigned short Signature1; // 510
|
||||
};
|
||||
|
||||
#define FAT_DIRTY_BIT 0x01
|
||||
|
||||
struct _BootSectorFatX
|
||||
{
|
||||
unsigned char SysType[4]; // 0
|
||||
|
@ -285,6 +287,8 @@ typedef BOOLEAN (*PIS_DIRECTORY_EMPTY)(PDEVICE_EXTENSION,struct _VFATFCB*);
|
|||
typedef NTSTATUS (*PADD_ENTRY)(PDEVICE_EXTENSION,PUNICODE_STRING,struct _VFATFCB**,struct _VFATFCB*,ULONG,UCHAR,struct _VFAT_MOVE_CONTEXT*);
|
||||
typedef NTSTATUS (*PDEL_ENTRY)(PDEVICE_EXTENSION,struct _VFATFCB*,struct _VFAT_MOVE_CONTEXT*);
|
||||
typedef NTSTATUS (*PGET_NEXT_DIR_ENTRY)(PVOID*,PVOID*,struct _VFATFCB*,struct _VFAT_DIRENTRY_CONTEXT*,BOOLEAN);
|
||||
typedef NTSTATUS (*PGET_DIRTY_STATUS)(PDEVICE_EXTENSION,PBOOLEAN);
|
||||
typedef NTSTATUS (*PSET_DIRTY_STATUS)(PDEVICE_EXTENSION,BOOLEAN);
|
||||
|
||||
typedef struct _VFAT_DISPATCH
|
||||
{
|
||||
|
@ -326,7 +330,8 @@ typedef struct DEVICE_EXTENSION
|
|||
PGET_NEXT_CLUSTER GetNextCluster;
|
||||
PFIND_AND_MARK_AVAILABLE_CLUSTER FindAndMarkAvailableCluster;
|
||||
PWRITE_CLUSTER WriteCluster;
|
||||
ULONG CleanShutBitMask;
|
||||
PGET_DIRTY_STATUS GetDirtyStatus;
|
||||
PSET_DIRTY_STATUS SetDirtyStatus;
|
||||
|
||||
ULONG BaseDateYear;
|
||||
|
||||
|
@ -654,6 +659,14 @@ VfatReadDiskPartial(
|
|||
IN ULONG BufferOffset,
|
||||
IN BOOLEAN Wait);
|
||||
|
||||
NTSTATUS
|
||||
VfatWriteDisk(
|
||||
IN PDEVICE_OBJECT pDeviceObject,
|
||||
IN PLARGE_INTEGER WriteOffset,
|
||||
IN ULONG WriteLength,
|
||||
IN OUT PUCHAR Buffer,
|
||||
IN BOOLEAN Override);
|
||||
|
||||
NTSTATUS
|
||||
VfatWriteDiskPartial(
|
||||
IN PVFAT_IRP_CONTEXT IrpContext,
|
||||
|
@ -885,6 +898,36 @@ WriteCluster(
|
|||
ULONG ClusterToWrite,
|
||||
ULONG NewValue);
|
||||
|
||||
NTSTATUS
|
||||
GetDirtyStatus(
|
||||
PDEVICE_EXTENSION DeviceExt,
|
||||
PBOOLEAN DirtyStatus);
|
||||
|
||||
NTSTATUS
|
||||
FAT16GetDirtyStatus(
|
||||
PDEVICE_EXTENSION DeviceExt,
|
||||
PBOOLEAN DirtyStatus);
|
||||
|
||||
NTSTATUS
|
||||
FAT32GetDirtyStatus(
|
||||
PDEVICE_EXTENSION DeviceExt,
|
||||
PBOOLEAN DirtyStatus);
|
||||
|
||||
NTSTATUS
|
||||
SetDirtyStatus(
|
||||
PDEVICE_EXTENSION DeviceExt,
|
||||
BOOLEAN DirtyStatus);
|
||||
|
||||
NTSTATUS
|
||||
FAT16SetDirtyStatus(
|
||||
PDEVICE_EXTENSION DeviceExt,
|
||||
BOOLEAN DirtyStatus);
|
||||
|
||||
NTSTATUS
|
||||
FAT32SetDirtyStatus(
|
||||
PDEVICE_EXTENSION DeviceExt,
|
||||
BOOLEAN DirtyStatus);
|
||||
|
||||
/* fcb.c */
|
||||
|
||||
PVFATFCB
|
||||
|
|
Loading…
Reference in a new issue