2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: drivers/filesystems/fastfat/fat.c
5 * PURPOSE: FastFAT Filesystem
6 * PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
7 * Pierre Schweitzer (pierre@reactos.org)
11 /* INCLUDES *****************************************************************/
18 /* GLOBALS ******************************************************************/
20 #define CACHEPAGESIZE(pDeviceExt) ((pDeviceExt)->FatInfo.BytesPerCluster > PAGE_SIZE ? \
21 (pDeviceExt)->FatInfo.BytesPerCluster : PAGE_SIZE)
23 /* FIXME: because volume is not cached, we have to perform direct IOs
24 * The day this is fixed, just comment out that line, and check
25 * it still works (and delete old code ;-))
27 #define VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
29 /* FUNCTIONS ****************************************************************/
32 * FUNCTION: Retrieve the next FAT32 cluster from the FAT table via a physical
37 PDEVICE_EXTENSION DeviceExt
,
41 NTSTATUS Status
= STATUS_SUCCESS
;
48 ChunkSize
= CACHEPAGESIZE(DeviceExt
);
49 FATOffset
= CurrentCluster
* sizeof(ULONG
);
50 Offset
.QuadPart
= ROUND_DOWN(FATOffset
, ChunkSize
);
53 CcMapData(DeviceExt
->FATFileObject
, &Offset
, ChunkSize
, MAP_WAIT
, &Context
, &BaseAddress
);
55 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
57 _SEH2_YIELD(return _SEH2_GetExceptionCode());
61 CurrentCluster
= (*(PULONG
)((char*)BaseAddress
+ (FATOffset
% ChunkSize
))) & 0x0fffffff;
62 if (CurrentCluster
>= 0xffffff8 && CurrentCluster
<= 0xfffffff)
63 CurrentCluster
= 0xffffffff;
65 if (CurrentCluster
== 0)
67 DPRINT1("WARNING: File system corruption detected. You may need to run a disk repair utility.\n");
68 Status
= STATUS_FILE_CORRUPT_ERROR
;
69 if (VfatGlobalData
->Flags
& VFAT_BREAK_ON_CORRUPTION
)
70 ASSERT(CurrentCluster
!= 0);
73 *NextCluster
= CurrentCluster
;
78 * FUNCTION: Retrieve the next FAT16 cluster from the FAT table
82 PDEVICE_EXTENSION DeviceExt
,
86 NTSTATUS Status
= STATUS_SUCCESS
;
93 ChunkSize
= CACHEPAGESIZE(DeviceExt
);
94 FATOffset
= CurrentCluster
* 2;
95 Offset
.QuadPart
= ROUND_DOWN(FATOffset
, ChunkSize
);
98 CcMapData(DeviceExt
->FATFileObject
, &Offset
, ChunkSize
, MAP_WAIT
, &Context
, &BaseAddress
);
100 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
102 _SEH2_YIELD(return _SEH2_GetExceptionCode());
106 CurrentCluster
= *((PUSHORT
)((char*)BaseAddress
+ (FATOffset
% ChunkSize
)));
107 if (CurrentCluster
>= 0xfff8 && CurrentCluster
<= 0xffff)
108 CurrentCluster
= 0xffffffff;
110 if (CurrentCluster
== 0)
112 DPRINT1("WARNING: File system corruption detected. You may need to run a disk repair utility.\n");
113 Status
= STATUS_FILE_CORRUPT_ERROR
;
114 if (VfatGlobalData
->Flags
& VFAT_BREAK_ON_CORRUPTION
)
115 ASSERT(CurrentCluster
!= 0);
118 CcUnpinData(Context
);
119 *NextCluster
= CurrentCluster
;
124 * FUNCTION: Retrieve the next FAT12 cluster from the FAT table
128 PDEVICE_EXTENSION DeviceExt
,
129 ULONG CurrentCluster
,
136 LARGE_INTEGER Offset
;
143 CcMapData(DeviceExt
->FATFileObject
, &Offset
, DeviceExt
->FatInfo
.FATSectors
* DeviceExt
->FatInfo
.BytesPerSector
, MAP_WAIT
, &Context
, &BaseAddress
);
145 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
147 _SEH2_YIELD(return _SEH2_GetExceptionCode());
151 CBlock
= (PUSHORT
)((char*)BaseAddress
+ (CurrentCluster
* 12) / 8);
152 if ((CurrentCluster
% 2) == 0)
154 Entry
= *CBlock
& 0x0fff;
158 Entry
= *CBlock
>> 4;
161 // DPRINT("Entry %x\n",Entry);
162 if (Entry
>= 0xff8 && Entry
<= 0xfff)
165 // DPRINT("Returning %x\n",Entry);
167 *NextCluster
= Entry
;
168 CcUnpinData(Context
);
169 // return Entry == 0xffffffff ? STATUS_END_OF_FILE : STATUS_SUCCESS;
170 return STATUS_SUCCESS
;
174 * FUNCTION: Finds the first available cluster in a FAT16 table
177 FAT16FindAndMarkAvailableCluster(
178 PDEVICE_EXTENSION DeviceExt
,
187 LARGE_INTEGER Offset
;
191 ChunkSize
= CACHEPAGESIZE(DeviceExt
);
192 FatLength
= (DeviceExt
->FatInfo
.NumberOfClusters
+ 2);
194 StartCluster
= DeviceExt
->LastAvailableCluster
;
196 for (j
= 0; j
< 2; j
++)
198 for (i
= StartCluster
; i
< FatLength
;)
200 Offset
.QuadPart
= ROUND_DOWN(i
* 2, ChunkSize
);
203 CcPinRead(DeviceExt
->FATFileObject
, &Offset
, ChunkSize
, PIN_WAIT
, &Context
, &BaseAddress
);
205 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
207 DPRINT1("CcPinRead(Offset %x, Length %u) failed\n", (ULONG
)Offset
.QuadPart
, ChunkSize
);
208 _SEH2_YIELD(return _SEH2_GetExceptionCode());
212 Block
= (PUSHORT
)((ULONG_PTR
)BaseAddress
+ (i
* 2) % ChunkSize
);
213 BlockEnd
= (PUSHORT
)((ULONG_PTR
)BaseAddress
+ ChunkSize
);
215 /* Now process the whole block */
216 while (Block
< BlockEnd
&& i
< FatLength
)
220 DPRINT("Found available cluster 0x%x\n", i
);
221 DeviceExt
->LastAvailableCluster
= *Cluster
= i
;
223 CcSetDirtyPinnedData(Context
, NULL
);
224 CcUnpinData(Context
);
225 if (DeviceExt
->AvailableClustersValid
)
226 InterlockedDecrement((PLONG
)&DeviceExt
->AvailableClusters
);
227 return STATUS_SUCCESS
;
234 CcUnpinData(Context
);
237 FatLength
= StartCluster
;
241 return STATUS_DISK_FULL
;
245 * FUNCTION: Finds the first available cluster in a FAT12 table
248 FAT12FindAndMarkAvailableCluster(
249 PDEVICE_EXTENSION DeviceExt
,
259 LARGE_INTEGER Offset
;
261 FatLength
= DeviceExt
->FatInfo
.NumberOfClusters
+ 2;
263 StartCluster
= DeviceExt
->LastAvailableCluster
;
267 CcPinRead(DeviceExt
->FATFileObject
, &Offset
, DeviceExt
->FatInfo
.FATSectors
* DeviceExt
->FatInfo
.BytesPerSector
, PIN_WAIT
, &Context
, &BaseAddress
);
269 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
271 DPRINT1("CcPinRead(Offset %x, Length %u) failed\n", (ULONG
)Offset
.QuadPart
, DeviceExt
->FatInfo
.FATSectors
* DeviceExt
->FatInfo
.BytesPerSector
);
272 _SEH2_YIELD(return _SEH2_GetExceptionCode());
276 for (j
= 0; j
< 2; j
++)
278 for (i
= StartCluster
; i
< FatLength
; i
++)
280 CBlock
= (PUSHORT
)((char*)BaseAddress
+ (i
* 12) / 8);
283 Entry
= *CBlock
& 0xfff;
287 Entry
= *CBlock
>> 4;
292 DPRINT("Found available cluster 0x%x\n", i
);
293 DeviceExt
->LastAvailableCluster
= *Cluster
= i
;
295 *CBlock
= (*CBlock
& 0xf000) | 0xfff;
297 *CBlock
= (*CBlock
& 0xf) | 0xfff0;
298 CcSetDirtyPinnedData(Context
, NULL
);
299 CcUnpinData(Context
);
300 if (DeviceExt
->AvailableClustersValid
)
301 InterlockedDecrement((PLONG
)&DeviceExt
->AvailableClusters
);
302 return STATUS_SUCCESS
;
305 FatLength
= StartCluster
;
308 CcUnpinData(Context
);
309 return STATUS_DISK_FULL
;
313 * FUNCTION: Finds the first available cluster in a FAT32 table
316 FAT32FindAndMarkAvailableCluster(
317 PDEVICE_EXTENSION DeviceExt
,
326 LARGE_INTEGER Offset
;
330 ChunkSize
= CACHEPAGESIZE(DeviceExt
);
331 FatLength
= (DeviceExt
->FatInfo
.NumberOfClusters
+ 2);
333 StartCluster
= DeviceExt
->LastAvailableCluster
;
335 for (j
= 0; j
< 2; j
++)
337 for (i
= StartCluster
; i
< FatLength
;)
339 Offset
.QuadPart
= ROUND_DOWN(i
* 4, ChunkSize
);
342 CcPinRead(DeviceExt
->FATFileObject
, &Offset
, ChunkSize
, PIN_WAIT
, &Context
, &BaseAddress
);
344 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
346 DPRINT1("CcPinRead(Offset %x, Length %u) failed\n", (ULONG
)Offset
.QuadPart
, ChunkSize
);
347 _SEH2_YIELD(return _SEH2_GetExceptionCode());
350 Block
= (PULONG
)((ULONG_PTR
)BaseAddress
+ (i
* 4) % ChunkSize
);
351 BlockEnd
= (PULONG
)((ULONG_PTR
)BaseAddress
+ ChunkSize
);
353 /* Now process the whole block */
354 while (Block
< BlockEnd
&& i
< FatLength
)
356 if ((*Block
& 0x0fffffff) == 0)
358 DPRINT("Found available cluster 0x%x\n", i
);
359 DeviceExt
->LastAvailableCluster
= *Cluster
= i
;
361 CcSetDirtyPinnedData(Context
, NULL
);
362 CcUnpinData(Context
);
363 if (DeviceExt
->AvailableClustersValid
)
364 InterlockedDecrement((PLONG
)&DeviceExt
->AvailableClusters
);
365 return STATUS_SUCCESS
;
372 CcUnpinData(Context
);
374 FatLength
= StartCluster
;
377 return STATUS_DISK_FULL
;
381 * FUNCTION: Counts free cluster in a FAT12 table
385 FAT12CountAvailableClusters(
386 PDEVICE_EXTENSION DeviceExt
)
392 ULONG numberofclusters
;
393 LARGE_INTEGER Offset
;
400 CcMapData(DeviceExt
->FATFileObject
, &Offset
, DeviceExt
->FatInfo
.FATSectors
* DeviceExt
->FatInfo
.BytesPerSector
, MAP_WAIT
, &Context
, &BaseAddress
);
402 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
404 _SEH2_YIELD(return _SEH2_GetExceptionCode());
408 numberofclusters
= DeviceExt
->FatInfo
.NumberOfClusters
+ 2;
410 for (i
= 2; i
< numberofclusters
; i
++)
412 CBlock
= (PUSHORT
)((char*)BaseAddress
+ (i
* 12) / 8);
415 Entry
= *CBlock
& 0x0fff;
419 Entry
= *CBlock
>> 4;
426 CcUnpinData(Context
);
427 DeviceExt
->AvailableClusters
= ulCount
;
428 DeviceExt
->AvailableClustersValid
= TRUE
;
430 return STATUS_SUCCESS
;
435 * FUNCTION: Counts free clusters in a FAT16 table
439 FAT16CountAvailableClusters(
440 PDEVICE_EXTENSION DeviceExt
)
444 PVOID BaseAddress
= NULL
;
448 PVOID Context
= NULL
;
449 LARGE_INTEGER Offset
;
452 ChunkSize
= CACHEPAGESIZE(DeviceExt
);
453 FatLength
= (DeviceExt
->FatInfo
.NumberOfClusters
+ 2);
455 for (i
= 2; i
< FatLength
; )
457 Offset
.QuadPart
= ROUND_DOWN(i
* 2, ChunkSize
);
460 CcMapData(DeviceExt
->FATFileObject
, &Offset
, ChunkSize
, MAP_WAIT
, &Context
, &BaseAddress
);
462 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
464 _SEH2_YIELD(return _SEH2_GetExceptionCode());
467 Block
= (PUSHORT
)((ULONG_PTR
)BaseAddress
+ (i
* 2) % ChunkSize
);
468 BlockEnd
= (PUSHORT
)((ULONG_PTR
)BaseAddress
+ ChunkSize
);
470 /* Now process the whole block */
471 while (Block
< BlockEnd
&& i
< FatLength
)
479 CcUnpinData(Context
);
482 DeviceExt
->AvailableClusters
= ulCount
;
483 DeviceExt
->AvailableClustersValid
= TRUE
;
485 return STATUS_SUCCESS
;
490 * FUNCTION: Counts free clusters in a FAT32 table
494 FAT32CountAvailableClusters(
495 PDEVICE_EXTENSION DeviceExt
)
499 PVOID BaseAddress
= NULL
;
503 PVOID Context
= NULL
;
504 LARGE_INTEGER Offset
;
507 ChunkSize
= CACHEPAGESIZE(DeviceExt
);
508 FatLength
= (DeviceExt
->FatInfo
.NumberOfClusters
+ 2);
510 for (i
= 2; i
< FatLength
; )
512 Offset
.QuadPart
= ROUND_DOWN(i
* 4, ChunkSize
);
515 CcMapData(DeviceExt
->FATFileObject
, &Offset
, ChunkSize
, MAP_WAIT
, &Context
, &BaseAddress
);
517 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
519 DPRINT1("CcMapData(Offset %x, Length %u) failed\n", (ULONG
)Offset
.QuadPart
, ChunkSize
);
520 _SEH2_YIELD(return _SEH2_GetExceptionCode());
523 Block
= (PULONG
)((ULONG_PTR
)BaseAddress
+ (i
* 4) % ChunkSize
);
524 BlockEnd
= (PULONG
)((ULONG_PTR
)BaseAddress
+ ChunkSize
);
526 /* Now process the whole block */
527 while (Block
< BlockEnd
&& i
< FatLength
)
529 if ((*Block
& 0x0fffffff) == 0)
535 CcUnpinData(Context
);
538 DeviceExt
->AvailableClusters
= ulCount
;
539 DeviceExt
->AvailableClustersValid
= TRUE
;
541 return STATUS_SUCCESS
;
545 CountAvailableClusters(
546 PDEVICE_EXTENSION DeviceExt
,
547 PLARGE_INTEGER Clusters
)
549 NTSTATUS Status
= STATUS_SUCCESS
;
550 ExAcquireResourceExclusiveLite (&DeviceExt
->FatResource
, TRUE
);
551 if (!DeviceExt
->AvailableClustersValid
)
553 if (DeviceExt
->FatInfo
.FatType
== FAT12
)
554 Status
= FAT12CountAvailableClusters(DeviceExt
);
555 else if (DeviceExt
->FatInfo
.FatType
== FAT16
|| DeviceExt
->FatInfo
.FatType
== FATX16
)
556 Status
= FAT16CountAvailableClusters(DeviceExt
);
558 Status
= FAT32CountAvailableClusters(DeviceExt
);
560 Clusters
->QuadPart
= DeviceExt
->AvailableClusters
;
561 ExReleaseResourceLite (&DeviceExt
->FatResource
);
568 * FUNCTION: Writes a cluster to the FAT12 physical and in-memory tables
572 PDEVICE_EXTENSION DeviceExt
,
573 ULONG ClusterToWrite
,
581 LARGE_INTEGER Offset
;
586 CcPinRead(DeviceExt
->FATFileObject
, &Offset
, DeviceExt
->FatInfo
.FATSectors
* DeviceExt
->FatInfo
.BytesPerSector
, PIN_WAIT
, &Context
, &BaseAddress
);
588 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
590 _SEH2_YIELD(return _SEH2_GetExceptionCode());
593 CBlock
= (PUCHAR
)BaseAddress
;
595 FATOffset
= (ClusterToWrite
* 12) / 8;
596 DPRINT("Writing 0x%x for 0x%x at 0x%x\n",
597 NewValue
, ClusterToWrite
, FATOffset
);
598 if ((ClusterToWrite
% 2) == 0)
600 *OldValue
= CBlock
[FATOffset
] + ((CBlock
[FATOffset
+ 1] & 0x0f) << 8);
601 CBlock
[FATOffset
] = (UCHAR
)NewValue
;
602 CBlock
[FATOffset
+ 1] &= 0xf0;
603 CBlock
[FATOffset
+ 1] |= (NewValue
& 0xf00) >> 8;
607 *OldValue
= (CBlock
[FATOffset
] >> 4) + (CBlock
[FATOffset
+ 1] << 4);
608 CBlock
[FATOffset
] &= 0x0f;
609 CBlock
[FATOffset
] |= (NewValue
& 0xf) << 4;
610 CBlock
[FATOffset
+ 1] = (UCHAR
)(NewValue
>> 4);
612 /* Write the changed FAT sector(s) to disk */
613 CcSetDirtyPinnedData(Context
, NULL
);
614 CcUnpinData(Context
);
615 return STATUS_SUCCESS
;
619 * FUNCTION: Writes a cluster to the FAT16 physical and in-memory tables
623 PDEVICE_EXTENSION DeviceExt
,
624 ULONG ClusterToWrite
,
632 LARGE_INTEGER Offset
;
635 ChunkSize
= CACHEPAGESIZE(DeviceExt
);
636 FATOffset
= ClusterToWrite
* 2;
637 Offset
.QuadPart
= ROUND_DOWN(FATOffset
, ChunkSize
);
640 CcPinRead(DeviceExt
->FATFileObject
, &Offset
, ChunkSize
, PIN_WAIT
, &Context
, &BaseAddress
);
642 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
644 _SEH2_YIELD(return _SEH2_GetExceptionCode());
648 DPRINT("Writing 0x%x for offset 0x%x 0x%x\n", NewValue
, FATOffset
,
650 Cluster
= ((PUSHORT
)((char*)BaseAddress
+ (FATOffset
% ChunkSize
)));
651 *OldValue
= *Cluster
;
652 *Cluster
= (USHORT
)NewValue
;
653 CcSetDirtyPinnedData(Context
, NULL
);
654 CcUnpinData(Context
);
655 return STATUS_SUCCESS
;
659 * FUNCTION: Writes a cluster to the FAT32 physical tables
663 PDEVICE_EXTENSION DeviceExt
,
664 ULONG ClusterToWrite
,
672 LARGE_INTEGER Offset
;
675 ChunkSize
= CACHEPAGESIZE(DeviceExt
);
677 FATOffset
= (ClusterToWrite
* 4);
678 Offset
.QuadPart
= ROUND_DOWN(FATOffset
, ChunkSize
);
681 CcPinRead(DeviceExt
->FATFileObject
, &Offset
, ChunkSize
, PIN_WAIT
, &Context
, &BaseAddress
);
683 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
685 _SEH2_YIELD(return _SEH2_GetExceptionCode());
689 DPRINT("Writing 0x%x for offset 0x%x 0x%x\n", NewValue
, FATOffset
,
691 Cluster
= ((PULONG
)((char*)BaseAddress
+ (FATOffset
% ChunkSize
)));
692 *OldValue
= *Cluster
& 0x0fffffff;
693 *Cluster
= (*Cluster
& 0xf0000000) | (NewValue
& 0x0fffffff);
695 CcSetDirtyPinnedData(Context
, NULL
);
696 CcUnpinData(Context
);
698 return STATUS_SUCCESS
;
703 * FUNCTION: Write a changed FAT entry
707 PDEVICE_EXTENSION DeviceExt
,
708 ULONG ClusterToWrite
,
714 ExAcquireResourceExclusiveLite (&DeviceExt
->FatResource
, TRUE
);
715 Status
= DeviceExt
->WriteCluster(DeviceExt
, ClusterToWrite
, NewValue
, &OldValue
);
716 if (DeviceExt
->AvailableClustersValid
)
718 if (OldValue
&& NewValue
== 0)
719 InterlockedIncrement((PLONG
)&DeviceExt
->AvailableClusters
);
720 else if (OldValue
== 0 && NewValue
)
721 InterlockedDecrement((PLONG
)&DeviceExt
->AvailableClusters
);
723 ExReleaseResourceLite(&DeviceExt
->FatResource
);
728 * FUNCTION: Converts the cluster number to a sector number for this physical
733 PDEVICE_EXTENSION DeviceExt
,
736 return DeviceExt
->FatInfo
.dataStart
+
737 ((ULONGLONG
)(Cluster
- 2) * DeviceExt
->FatInfo
.SectorsPerCluster
);
742 * FUNCTION: Retrieve the next cluster depending on the FAT type
746 PDEVICE_EXTENSION DeviceExt
,
747 ULONG CurrentCluster
,
752 DPRINT("GetNextCluster(DeviceExt %p, CurrentCluster %x)\n",
753 DeviceExt
, CurrentCluster
);
755 if (CurrentCluster
== 0)
757 DPRINT1("WARNING: File system corruption detected. You may need to run a disk repair utility.\n");
758 if (VfatGlobalData
->Flags
& VFAT_BREAK_ON_CORRUPTION
)
759 ASSERT(CurrentCluster
!= 0);
760 return STATUS_FILE_CORRUPT_ERROR
;
763 ExAcquireResourceSharedLite(&DeviceExt
->FatResource
, TRUE
);
764 Status
= DeviceExt
->GetNextCluster(DeviceExt
, CurrentCluster
, NextCluster
);
765 ExReleaseResourceLite(&DeviceExt
->FatResource
);
771 * FUNCTION: Retrieve the next cluster depending on the FAT type
774 GetNextClusterExtend(
775 PDEVICE_EXTENSION DeviceExt
,
776 ULONG CurrentCluster
,
782 DPRINT("GetNextClusterExtend(DeviceExt %p, CurrentCluster %x)\n",
783 DeviceExt
, CurrentCluster
);
785 ExAcquireResourceExclusiveLite(&DeviceExt
->FatResource
, TRUE
);
787 * If the file hasn't any clusters allocated then we need special
790 if (CurrentCluster
== 0)
792 Status
= DeviceExt
->FindAndMarkAvailableCluster(DeviceExt
, &NewCluster
);
793 if (!NT_SUCCESS(Status
))
795 ExReleaseResourceLite(&DeviceExt
->FatResource
);
799 *NextCluster
= NewCluster
;
800 ExReleaseResourceLite(&DeviceExt
->FatResource
);
801 return STATUS_SUCCESS
;
804 Status
= DeviceExt
->GetNextCluster(DeviceExt
, CurrentCluster
, NextCluster
);
806 if ((*NextCluster
) == 0xFFFFFFFF)
808 /* We are after last existing cluster, we must add one to file */
809 /* Firstly, find the next available open allocation unit and
810 mark it as end of file */
811 Status
= DeviceExt
->FindAndMarkAvailableCluster(DeviceExt
, &NewCluster
);
812 if (!NT_SUCCESS(Status
))
814 ExReleaseResourceLite(&DeviceExt
->FatResource
);
818 /* Now, write the AU of the LastCluster with the value of the newly
820 WriteCluster(DeviceExt
, CurrentCluster
, NewCluster
);
821 *NextCluster
= NewCluster
;
824 ExReleaseResourceLite(&DeviceExt
->FatResource
);
829 * FUNCTION: Retrieve the dirty status
833 PDEVICE_EXTENSION DeviceExt
,
834 PBOOLEAN DirtyStatus
)
838 DPRINT("GetDirtyStatus(DeviceExt %p)\n", DeviceExt
);
840 /* FAT12 has no dirty bit */
841 if (DeviceExt
->FatInfo
.FatType
== FAT12
)
843 *DirtyStatus
= FALSE
;
844 return STATUS_SUCCESS
;
847 /* Not really in the FAT, but share the lock because
848 * we're really low-level and shouldn't happent that often
849 * And call the appropriate function
851 ExAcquireResourceSharedLite(&DeviceExt
->FatResource
, TRUE
);
852 Status
= DeviceExt
->GetDirtyStatus(DeviceExt
, DirtyStatus
);
853 ExReleaseResourceLite(&DeviceExt
->FatResource
);
860 PDEVICE_EXTENSION DeviceExt
,
861 PBOOLEAN DirtyStatus
)
863 LARGE_INTEGER Offset
;
865 #ifdef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
870 struct _BootSector
* Sector
;
872 /* We'll read the bootsector at 0 */
874 Length
= DeviceExt
->FatInfo
.BytesPerSector
;
875 #ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
876 /* Go through Cc for this */
879 CcPinRead(DeviceExt
->VolumeFcb
->FileObject
, &Offset
, Length
, PIN_WAIT
, &Context
, (PVOID
*)&Sector
);
881 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
883 _SEH2_YIELD(return _SEH2_GetExceptionCode());
887 /* No Cc, do it the old way:
888 * - Allocate a big enough buffer
889 * - And read the disk
891 Sector
= ExAllocatePoolWithTag(NonPagedPool
, Length
, TAG_VFAT
);
895 return STATUS_INSUFFICIENT_RESOURCES
;
898 Status
= VfatReadDisk(DeviceExt
->StorageDevice
, &Offset
, Length
, (PUCHAR
)Sector
, FALSE
);
899 if (!NT_SUCCESS(Status
))
902 ExFreePoolWithTag(Sector
, TAG_VFAT
);
907 /* Make sure we have a boot sector...
908 * FIXME: This check is a bit lame and should be improved
910 if (Sector
->Signatur1
!= 0xaa55)
912 /* Set we are dirty so that we don't attempt anything */
914 #ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
915 CcUnpinData(Context
);
917 ExFreePoolWithTag(Sector
, TAG_VFAT
);
919 return STATUS_DISK_CORRUPT_ERROR
;
922 /* Return the status of the dirty bit */
923 if (Sector
->Res1
& FAT_DIRTY_BIT
)
926 *DirtyStatus
= FALSE
;
928 #ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
929 CcUnpinData(Context
);
931 ExFreePoolWithTag(Sector
, TAG_VFAT
);
933 return STATUS_SUCCESS
;
938 PDEVICE_EXTENSION DeviceExt
,
939 PBOOLEAN DirtyStatus
)
941 LARGE_INTEGER Offset
;
943 #ifdef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
948 struct _BootSector32
* Sector
;
950 /* We'll read the bootsector at 0 */
952 Length
= DeviceExt
->FatInfo
.BytesPerSector
;
953 #ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
954 /* Go through Cc for this */
957 CcPinRead(DeviceExt
->VolumeFcb
->FileObject
, &Offset
, Length
, PIN_WAIT
, &Context
, (PVOID
*)&Sector
);
959 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
961 _SEH2_YIELD(return _SEH2_GetExceptionCode());
965 /* No Cc, do it the old way:
966 * - Allocate a big enough buffer
967 * - And read the disk
969 Sector
= ExAllocatePoolWithTag(NonPagedPool
, Length
, TAG_VFAT
);
973 return STATUS_INSUFFICIENT_RESOURCES
;
976 Status
= VfatReadDisk(DeviceExt
->StorageDevice
, &Offset
, Length
, (PUCHAR
)Sector
, FALSE
);
977 if (!NT_SUCCESS(Status
))
980 ExFreePoolWithTag(Sector
, TAG_VFAT
);
985 /* Make sure we have a boot sector...
986 * FIXME: This check is a bit lame and should be improved
988 if (Sector
->Signature1
!= 0xaa55)
990 /* Set we are dirty so that we don't attempt anything */
992 #ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
993 CcUnpinData(Context
);
995 ExFreePoolWithTag(Sector
, TAG_VFAT
);
997 return STATUS_DISK_CORRUPT_ERROR
;
1000 /* Return the status of the dirty bit */
1001 if (Sector
->Res4
& FAT_DIRTY_BIT
)
1002 *DirtyStatus
= TRUE
;
1004 *DirtyStatus
= FALSE
;
1006 #ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
1007 CcUnpinData(Context
);
1009 ExFreePoolWithTag(Sector
, TAG_VFAT
);
1011 return STATUS_SUCCESS
;
1015 * FUNCTION: Set the dirty status
1019 PDEVICE_EXTENSION DeviceExt
,
1020 BOOLEAN DirtyStatus
)
1024 DPRINT("SetDirtyStatus(DeviceExt %p, DirtyStatus %d)\n", DeviceExt
, DirtyStatus
);
1026 /* FAT12 has no dirty bit */
1027 if (DeviceExt
->FatInfo
.FatType
== FAT12
)
1029 return STATUS_SUCCESS
;
1032 /* Not really in the FAT, but share the lock because
1033 * we're really low-level and shouldn't happent that often
1034 * And call the appropriate function
1035 * Acquire exclusive because we will modify ondisk value
1037 ExAcquireResourceExclusiveLite(&DeviceExt
->FatResource
, TRUE
);
1038 Status
= DeviceExt
->SetDirtyStatus(DeviceExt
, DirtyStatus
);
1039 ExReleaseResourceLite(&DeviceExt
->FatResource
);
1045 FAT16SetDirtyStatus(
1046 PDEVICE_EXTENSION DeviceExt
,
1047 BOOLEAN DirtyStatus
)
1049 LARGE_INTEGER Offset
;
1051 #ifdef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
1056 struct _BootSector
* Sector
;
1058 /* We'll read (and then write) the bootsector at 0 */
1059 Offset
.QuadPart
= 0;
1060 Length
= DeviceExt
->FatInfo
.BytesPerSector
;
1061 #ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
1062 /* Go through Cc for this */
1065 CcPinRead(DeviceExt
->VolumeFcb
->FileObject
, &Offset
, Length
, PIN_WAIT
, &Context
, (PVOID
*)&Sector
);
1067 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1069 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1073 /* No Cc, do it the old way:
1074 * - Allocate a big enough buffer
1075 * - And read the disk
1077 Sector
= ExAllocatePoolWithTag(NonPagedPool
, Length
, TAG_VFAT
);
1080 return STATUS_INSUFFICIENT_RESOURCES
;
1083 Status
= VfatReadDisk(DeviceExt
->StorageDevice
, &Offset
, Length
, (PUCHAR
)Sector
, FALSE
);
1084 if (!NT_SUCCESS(Status
))
1086 ExFreePoolWithTag(Sector
, TAG_VFAT
);
1091 /* Make sure we have a boot sector...
1092 * FIXME: This check is a bit lame and should be improved
1094 if (Sector
->Signatur1
!= 0xaa55)
1096 #ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
1097 CcUnpinData(Context
);
1099 ExFreePoolWithTag(Sector
, TAG_VFAT
);
1101 return STATUS_DISK_CORRUPT_ERROR
;
1104 /* Modify the dirty bit status according
1109 Sector
->Res1
&= ~FAT_DIRTY_BIT
;
1113 Sector
->Res1
|= FAT_DIRTY_BIT
;
1116 #ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
1117 /* Mark boot sector dirty so that it gets written to the disk */
1118 CcSetDirtyPinnedData(Context
, NULL
);
1119 CcUnpinData(Context
);
1120 return STATUS_SUCCESS
;
1122 /* Write back the boot sector to the disk */
1123 Status
= VfatWriteDisk(DeviceExt
->StorageDevice
, &Offset
, Length
, (PUCHAR
)Sector
, FALSE
);
1124 ExFreePoolWithTag(Sector
, TAG_VFAT
);
1130 FAT32SetDirtyStatus(
1131 PDEVICE_EXTENSION DeviceExt
,
1132 BOOLEAN DirtyStatus
)
1134 LARGE_INTEGER Offset
;
1136 #ifdef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
1141 struct _BootSector32
* Sector
;
1143 /* We'll read (and then write) the bootsector at 0 */
1144 Offset
.QuadPart
= 0;
1145 Length
= DeviceExt
->FatInfo
.BytesPerSector
;
1146 #ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
1147 /* Go through Cc for this */
1150 CcPinRead(DeviceExt
->VolumeFcb
->FileObject
, &Offset
, Length
, PIN_WAIT
, &Context
, (PVOID
*)&Sector
);
1152 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1154 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1158 /* No Cc, do it the old way:
1159 * - Allocate a big enough buffer
1160 * - And read the disk
1162 Sector
= ExAllocatePoolWithTag(NonPagedPool
, Length
, TAG_VFAT
);
1165 return STATUS_INSUFFICIENT_RESOURCES
;
1168 Status
= VfatReadDisk(DeviceExt
->StorageDevice
, &Offset
, Length
, (PUCHAR
)Sector
, FALSE
);
1169 if (!NT_SUCCESS(Status
))
1171 ExFreePoolWithTag(Sector
, TAG_VFAT
);
1176 /* Make sure we have a boot sector...
1177 * FIXME: This check is a bit lame and should be improved
1179 if (Sector
->Signature1
!= 0xaa55)
1182 #ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
1183 CcUnpinData(Context
);
1185 ExFreePoolWithTag(Sector
, TAG_VFAT
);
1187 return STATUS_DISK_CORRUPT_ERROR
;
1190 /* Modify the dirty bit status according
1195 Sector
->Res4
&= ~FAT_DIRTY_BIT
;
1199 Sector
->Res4
|= FAT_DIRTY_BIT
;
1202 #ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
1203 /* Mark boot sector dirty so that it gets written to the disk */
1204 CcSetDirtyPinnedData(Context
, NULL
);
1205 CcUnpinData(Context
);
1206 return STATUS_SUCCESS
;
1208 /* Write back the boot sector to the disk */
1209 Status
= VfatWriteDisk(DeviceExt
->StorageDevice
, &Offset
, Length
, (PUCHAR
)Sector
, FALSE
);
1210 ExFreePoolWithTag(Sector
, TAG_VFAT
);