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 /* FUNCTIONS ****************************************************************/
26 * FUNCTION: Retrieve the next FAT32 cluster from the FAT table via a physical
31 PDEVICE_EXTENSION DeviceExt
,
35 NTSTATUS Status
= STATUS_SUCCESS
;
42 ChunkSize
= CACHEPAGESIZE(DeviceExt
);
43 FATOffset
= CurrentCluster
* sizeof(ULONG
);
44 Offset
.QuadPart
= ROUND_DOWN(FATOffset
, ChunkSize
);
47 if (!CcMapData(DeviceExt
->FATFileObject
, &Offset
, ChunkSize
, MAP_WAIT
, &Context
, &BaseAddress
))
50 return STATUS_UNSUCCESSFUL
;
53 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
55 _SEH2_YIELD(return _SEH2_GetExceptionCode());
59 CurrentCluster
= (*(PULONG
)((char*)BaseAddress
+ (FATOffset
% ChunkSize
))) & 0x0fffffff;
60 if (CurrentCluster
>= 0xffffff8 && CurrentCluster
<= 0xfffffff)
61 CurrentCluster
= 0xffffffff;
63 if (CurrentCluster
== 0)
65 DPRINT1("WARNING: File system corruption detected. You may need to run a disk repair utility.\n");
66 Status
= STATUS_FILE_CORRUPT_ERROR
;
67 if (VfatGlobalData
->Flags
& VFAT_BREAK_ON_CORRUPTION
)
68 ASSERT(CurrentCluster
!= 0);
71 *NextCluster
= CurrentCluster
;
76 * FUNCTION: Retrieve the next FAT16 cluster from the FAT table
80 PDEVICE_EXTENSION DeviceExt
,
84 NTSTATUS Status
= STATUS_SUCCESS
;
91 ChunkSize
= CACHEPAGESIZE(DeviceExt
);
92 FATOffset
= CurrentCluster
* 2;
93 Offset
.QuadPart
= ROUND_DOWN(FATOffset
, ChunkSize
);
96 CcMapData(DeviceExt
->FATFileObject
, &Offset
, ChunkSize
, MAP_WAIT
, &Context
, &BaseAddress
);
98 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
100 _SEH2_YIELD(return _SEH2_GetExceptionCode());
104 CurrentCluster
= *((PUSHORT
)((char*)BaseAddress
+ (FATOffset
% ChunkSize
)));
105 if (CurrentCluster
>= 0xfff8 && CurrentCluster
<= 0xffff)
106 CurrentCluster
= 0xffffffff;
108 if (CurrentCluster
== 0)
110 DPRINT1("WARNING: File system corruption detected. You may need to run a disk repair utility.\n");
111 Status
= STATUS_FILE_CORRUPT_ERROR
;
112 if (VfatGlobalData
->Flags
& VFAT_BREAK_ON_CORRUPTION
)
113 ASSERT(CurrentCluster
!= 0);
116 CcUnpinData(Context
);
117 *NextCluster
= CurrentCluster
;
122 * FUNCTION: Retrieve the next FAT12 cluster from the FAT table
126 PDEVICE_EXTENSION DeviceExt
,
127 ULONG CurrentCluster
,
134 LARGE_INTEGER Offset
;
141 CcMapData(DeviceExt
->FATFileObject
, &Offset
, DeviceExt
->FatInfo
.FATSectors
* DeviceExt
->FatInfo
.BytesPerSector
, MAP_WAIT
, &Context
, &BaseAddress
);
143 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
145 _SEH2_YIELD(return _SEH2_GetExceptionCode());
149 CBlock
= (PUSHORT
)((char*)BaseAddress
+ (CurrentCluster
* 12) / 8);
150 if ((CurrentCluster
% 2) == 0)
152 Entry
= *CBlock
& 0x0fff;
156 Entry
= *CBlock
>> 4;
159 // DPRINT("Entry %x\n",Entry);
160 if (Entry
>= 0xff8 && Entry
<= 0xfff)
163 // DPRINT("Returning %x\n",Entry);
165 *NextCluster
= Entry
;
166 CcUnpinData(Context
);
167 // return Entry == 0xffffffff ? STATUS_END_OF_FILE : STATUS_SUCCESS;
168 return STATUS_SUCCESS
;
172 * FUNCTION: Finds the first available cluster in a FAT16 table
175 FAT16FindAndMarkAvailableCluster(
176 PDEVICE_EXTENSION DeviceExt
,
185 LARGE_INTEGER Offset
;
189 ChunkSize
= CACHEPAGESIZE(DeviceExt
);
190 FatLength
= (DeviceExt
->FatInfo
.NumberOfClusters
+ 2);
192 StartCluster
= DeviceExt
->LastAvailableCluster
;
194 for (j
= 0; j
< 2; j
++)
196 for (i
= StartCluster
; i
< FatLength
;)
198 Offset
.QuadPart
= ROUND_DOWN(i
* 2, ChunkSize
);
201 CcPinRead(DeviceExt
->FATFileObject
, &Offset
, ChunkSize
, PIN_WAIT
, &Context
, &BaseAddress
);
203 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
205 DPRINT1("CcPinRead(Offset %x, Length %u) failed\n", (ULONG
)Offset
.QuadPart
, ChunkSize
);
206 _SEH2_YIELD(return _SEH2_GetExceptionCode());
210 Block
= (PUSHORT
)((ULONG_PTR
)BaseAddress
+ (i
* 2) % ChunkSize
);
211 BlockEnd
= (PUSHORT
)((ULONG_PTR
)BaseAddress
+ ChunkSize
);
213 /* Now process the whole block */
214 while (Block
< BlockEnd
&& i
< FatLength
)
218 DPRINT("Found available cluster 0x%x\n", i
);
219 DeviceExt
->LastAvailableCluster
= *Cluster
= i
;
221 CcSetDirtyPinnedData(Context
, NULL
);
222 CcUnpinData(Context
);
223 if (DeviceExt
->AvailableClustersValid
)
224 InterlockedDecrement((PLONG
)&DeviceExt
->AvailableClusters
);
225 return STATUS_SUCCESS
;
232 CcUnpinData(Context
);
235 FatLength
= StartCluster
;
239 return STATUS_DISK_FULL
;
243 * FUNCTION: Finds the first available cluster in a FAT12 table
246 FAT12FindAndMarkAvailableCluster(
247 PDEVICE_EXTENSION DeviceExt
,
257 LARGE_INTEGER Offset
;
259 FatLength
= DeviceExt
->FatInfo
.NumberOfClusters
+ 2;
261 StartCluster
= DeviceExt
->LastAvailableCluster
;
265 CcPinRead(DeviceExt
->FATFileObject
, &Offset
, DeviceExt
->FatInfo
.FATSectors
* DeviceExt
->FatInfo
.BytesPerSector
, PIN_WAIT
, &Context
, &BaseAddress
);
267 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
269 DPRINT1("CcPinRead(Offset %x, Length %u) failed\n", (ULONG
)Offset
.QuadPart
, DeviceExt
->FatInfo
.FATSectors
* DeviceExt
->FatInfo
.BytesPerSector
);
270 _SEH2_YIELD(return _SEH2_GetExceptionCode());
274 for (j
= 0; j
< 2; j
++)
276 for (i
= StartCluster
; i
< FatLength
; i
++)
278 CBlock
= (PUSHORT
)((char*)BaseAddress
+ (i
* 12) / 8);
281 Entry
= *CBlock
& 0xfff;
285 Entry
= *CBlock
>> 4;
290 DPRINT("Found available cluster 0x%x\n", i
);
291 DeviceExt
->LastAvailableCluster
= *Cluster
= i
;
293 *CBlock
= (*CBlock
& 0xf000) | 0xfff;
295 *CBlock
= (*CBlock
& 0xf) | 0xfff0;
296 CcSetDirtyPinnedData(Context
, NULL
);
297 CcUnpinData(Context
);
298 if (DeviceExt
->AvailableClustersValid
)
299 InterlockedDecrement((PLONG
)&DeviceExt
->AvailableClusters
);
300 return STATUS_SUCCESS
;
303 FatLength
= StartCluster
;
306 CcUnpinData(Context
);
307 return STATUS_DISK_FULL
;
311 * FUNCTION: Finds the first available cluster in a FAT32 table
314 FAT32FindAndMarkAvailableCluster(
315 PDEVICE_EXTENSION DeviceExt
,
324 LARGE_INTEGER Offset
;
328 ChunkSize
= CACHEPAGESIZE(DeviceExt
);
329 FatLength
= (DeviceExt
->FatInfo
.NumberOfClusters
+ 2);
331 StartCluster
= DeviceExt
->LastAvailableCluster
;
333 for (j
= 0; j
< 2; j
++)
335 for (i
= StartCluster
; i
< FatLength
;)
337 Offset
.QuadPart
= ROUND_DOWN(i
* 4, ChunkSize
);
340 CcPinRead(DeviceExt
->FATFileObject
, &Offset
, ChunkSize
, PIN_WAIT
, &Context
, &BaseAddress
);
342 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
344 DPRINT1("CcPinRead(Offset %x, Length %u) failed\n", (ULONG
)Offset
.QuadPart
, ChunkSize
);
345 _SEH2_YIELD(return _SEH2_GetExceptionCode());
348 Block
= (PULONG
)((ULONG_PTR
)BaseAddress
+ (i
* 4) % ChunkSize
);
349 BlockEnd
= (PULONG
)((ULONG_PTR
)BaseAddress
+ ChunkSize
);
351 /* Now process the whole block */
352 while (Block
< BlockEnd
&& i
< FatLength
)
354 if ((*Block
& 0x0fffffff) == 0)
356 DPRINT("Found available cluster 0x%x\n", i
);
357 DeviceExt
->LastAvailableCluster
= *Cluster
= i
;
359 CcSetDirtyPinnedData(Context
, NULL
);
360 CcUnpinData(Context
);
361 if (DeviceExt
->AvailableClustersValid
)
362 InterlockedDecrement((PLONG
)&DeviceExt
->AvailableClusters
);
363 return STATUS_SUCCESS
;
370 CcUnpinData(Context
);
372 FatLength
= StartCluster
;
375 return STATUS_DISK_FULL
;
379 * FUNCTION: Counts free cluster in a FAT12 table
383 FAT12CountAvailableClusters(
384 PDEVICE_EXTENSION DeviceExt
)
390 ULONG numberofclusters
;
391 LARGE_INTEGER Offset
;
398 CcMapData(DeviceExt
->FATFileObject
, &Offset
, DeviceExt
->FatInfo
.FATSectors
* DeviceExt
->FatInfo
.BytesPerSector
, MAP_WAIT
, &Context
, &BaseAddress
);
400 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
402 _SEH2_YIELD(return _SEH2_GetExceptionCode());
406 numberofclusters
= DeviceExt
->FatInfo
.NumberOfClusters
+ 2;
408 for (i
= 2; i
< numberofclusters
; i
++)
410 CBlock
= (PUSHORT
)((char*)BaseAddress
+ (i
* 12) / 8);
413 Entry
= *CBlock
& 0x0fff;
417 Entry
= *CBlock
>> 4;
424 CcUnpinData(Context
);
425 DeviceExt
->AvailableClusters
= ulCount
;
426 DeviceExt
->AvailableClustersValid
= TRUE
;
428 return STATUS_SUCCESS
;
433 * FUNCTION: Counts free clusters in a FAT16 table
437 FAT16CountAvailableClusters(
438 PDEVICE_EXTENSION DeviceExt
)
442 PVOID BaseAddress
= NULL
;
446 PVOID Context
= NULL
;
447 LARGE_INTEGER Offset
;
450 ChunkSize
= CACHEPAGESIZE(DeviceExt
);
451 FatLength
= (DeviceExt
->FatInfo
.NumberOfClusters
+ 2);
453 for (i
= 2; i
< FatLength
; )
455 Offset
.QuadPart
= ROUND_DOWN(i
* 2, ChunkSize
);
458 CcMapData(DeviceExt
->FATFileObject
, &Offset
, ChunkSize
, MAP_WAIT
, &Context
, &BaseAddress
);
460 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
462 _SEH2_YIELD(return _SEH2_GetExceptionCode());
465 Block
= (PUSHORT
)((ULONG_PTR
)BaseAddress
+ (i
* 2) % ChunkSize
);
466 BlockEnd
= (PUSHORT
)((ULONG_PTR
)BaseAddress
+ ChunkSize
);
468 /* Now process the whole block */
469 while (Block
< BlockEnd
&& i
< FatLength
)
477 CcUnpinData(Context
);
480 DeviceExt
->AvailableClusters
= ulCount
;
481 DeviceExt
->AvailableClustersValid
= TRUE
;
483 return STATUS_SUCCESS
;
488 * FUNCTION: Counts free clusters in a FAT32 table
492 FAT32CountAvailableClusters(
493 PDEVICE_EXTENSION DeviceExt
)
497 PVOID BaseAddress
= NULL
;
501 PVOID Context
= NULL
;
502 LARGE_INTEGER Offset
;
505 ChunkSize
= CACHEPAGESIZE(DeviceExt
);
506 FatLength
= (DeviceExt
->FatInfo
.NumberOfClusters
+ 2);
508 for (i
= 2; i
< FatLength
; )
510 Offset
.QuadPart
= ROUND_DOWN(i
* 4, ChunkSize
);
513 CcMapData(DeviceExt
->FATFileObject
, &Offset
, ChunkSize
, MAP_WAIT
, &Context
, &BaseAddress
);
515 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
517 DPRINT1("CcMapData(Offset %x, Length %u) failed\n", (ULONG
)Offset
.QuadPart
, ChunkSize
);
518 _SEH2_YIELD(return _SEH2_GetExceptionCode());
521 Block
= (PULONG
)((ULONG_PTR
)BaseAddress
+ (i
* 4) % ChunkSize
);
522 BlockEnd
= (PULONG
)((ULONG_PTR
)BaseAddress
+ ChunkSize
);
524 /* Now process the whole block */
525 while (Block
< BlockEnd
&& i
< FatLength
)
527 if ((*Block
& 0x0fffffff) == 0)
533 CcUnpinData(Context
);
536 DeviceExt
->AvailableClusters
= ulCount
;
537 DeviceExt
->AvailableClustersValid
= TRUE
;
539 return STATUS_SUCCESS
;
543 CountAvailableClusters(
544 PDEVICE_EXTENSION DeviceExt
,
545 PLARGE_INTEGER Clusters
)
547 NTSTATUS Status
= STATUS_SUCCESS
;
548 ExAcquireResourceExclusiveLite (&DeviceExt
->FatResource
, TRUE
);
549 if (!DeviceExt
->AvailableClustersValid
)
551 if (DeviceExt
->FatInfo
.FatType
== FAT12
)
552 Status
= FAT12CountAvailableClusters(DeviceExt
);
553 else if (DeviceExt
->FatInfo
.FatType
== FAT16
|| DeviceExt
->FatInfo
.FatType
== FATX16
)
554 Status
= FAT16CountAvailableClusters(DeviceExt
);
556 Status
= FAT32CountAvailableClusters(DeviceExt
);
558 if (Clusters
!= NULL
)
560 Clusters
->QuadPart
= DeviceExt
->AvailableClusters
;
562 ExReleaseResourceLite (&DeviceExt
->FatResource
);
569 * FUNCTION: Writes a cluster to the FAT12 physical and in-memory tables
573 PDEVICE_EXTENSION DeviceExt
,
574 ULONG ClusterToWrite
,
582 LARGE_INTEGER Offset
;
587 CcPinRead(DeviceExt
->FATFileObject
, &Offset
, DeviceExt
->FatInfo
.FATSectors
* DeviceExt
->FatInfo
.BytesPerSector
, PIN_WAIT
, &Context
, &BaseAddress
);
589 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
591 _SEH2_YIELD(return _SEH2_GetExceptionCode());
594 CBlock
= (PUCHAR
)BaseAddress
;
596 FATOffset
= (ClusterToWrite
* 12) / 8;
597 DPRINT("Writing 0x%x for 0x%x at 0x%x\n",
598 NewValue
, ClusterToWrite
, FATOffset
);
599 if ((ClusterToWrite
% 2) == 0)
601 *OldValue
= CBlock
[FATOffset
] + ((CBlock
[FATOffset
+ 1] & 0x0f) << 8);
602 CBlock
[FATOffset
] = (UCHAR
)NewValue
;
603 CBlock
[FATOffset
+ 1] &= 0xf0;
604 CBlock
[FATOffset
+ 1] |= (NewValue
& 0xf00) >> 8;
608 *OldValue
= (CBlock
[FATOffset
] >> 4) + (CBlock
[FATOffset
+ 1] << 4);
609 CBlock
[FATOffset
] &= 0x0f;
610 CBlock
[FATOffset
] |= (NewValue
& 0xf) << 4;
611 CBlock
[FATOffset
+ 1] = (UCHAR
)(NewValue
>> 4);
613 /* Write the changed FAT sector(s) to disk */
614 CcSetDirtyPinnedData(Context
, NULL
);
615 CcUnpinData(Context
);
616 return STATUS_SUCCESS
;
620 * FUNCTION: Writes a cluster to the FAT16 physical and in-memory tables
624 PDEVICE_EXTENSION DeviceExt
,
625 ULONG ClusterToWrite
,
633 LARGE_INTEGER Offset
;
636 ChunkSize
= CACHEPAGESIZE(DeviceExt
);
637 FATOffset
= ClusterToWrite
* 2;
638 Offset
.QuadPart
= ROUND_DOWN(FATOffset
, ChunkSize
);
641 CcPinRead(DeviceExt
->FATFileObject
, &Offset
, ChunkSize
, PIN_WAIT
, &Context
, &BaseAddress
);
643 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
645 _SEH2_YIELD(return _SEH2_GetExceptionCode());
649 DPRINT("Writing 0x%x for offset 0x%x 0x%x\n", NewValue
, FATOffset
,
651 Cluster
= ((PUSHORT
)((char*)BaseAddress
+ (FATOffset
% ChunkSize
)));
652 *OldValue
= *Cluster
;
653 *Cluster
= (USHORT
)NewValue
;
654 CcSetDirtyPinnedData(Context
, NULL
);
655 CcUnpinData(Context
);
656 return STATUS_SUCCESS
;
660 * FUNCTION: Writes a cluster to the FAT32 physical tables
664 PDEVICE_EXTENSION DeviceExt
,
665 ULONG ClusterToWrite
,
673 LARGE_INTEGER Offset
;
676 ChunkSize
= CACHEPAGESIZE(DeviceExt
);
678 FATOffset
= (ClusterToWrite
* 4);
679 Offset
.QuadPart
= ROUND_DOWN(FATOffset
, ChunkSize
);
682 CcPinRead(DeviceExt
->FATFileObject
, &Offset
, ChunkSize
, PIN_WAIT
, &Context
, &BaseAddress
);
684 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
686 _SEH2_YIELD(return _SEH2_GetExceptionCode());
690 DPRINT("Writing 0x%x for offset 0x%x 0x%x\n", NewValue
, FATOffset
,
692 Cluster
= ((PULONG
)((char*)BaseAddress
+ (FATOffset
% ChunkSize
)));
693 *OldValue
= *Cluster
& 0x0fffffff;
694 *Cluster
= (*Cluster
& 0xf0000000) | (NewValue
& 0x0fffffff);
696 CcSetDirtyPinnedData(Context
, NULL
);
697 CcUnpinData(Context
);
699 return STATUS_SUCCESS
;
704 * FUNCTION: Write a changed FAT entry
708 PDEVICE_EXTENSION DeviceExt
,
709 ULONG ClusterToWrite
,
715 ExAcquireResourceExclusiveLite (&DeviceExt
->FatResource
, TRUE
);
716 Status
= DeviceExt
->WriteCluster(DeviceExt
, ClusterToWrite
, NewValue
, &OldValue
);
717 if (DeviceExt
->AvailableClustersValid
)
719 if (OldValue
&& NewValue
== 0)
720 InterlockedIncrement((PLONG
)&DeviceExt
->AvailableClusters
);
721 else if (OldValue
== 0 && NewValue
)
722 InterlockedDecrement((PLONG
)&DeviceExt
->AvailableClusters
);
724 ExReleaseResourceLite(&DeviceExt
->FatResource
);
729 * FUNCTION: Converts the cluster number to a sector number for this physical
734 PDEVICE_EXTENSION DeviceExt
,
737 return DeviceExt
->FatInfo
.dataStart
+
738 ((ULONGLONG
)(Cluster
- 2) * DeviceExt
->FatInfo
.SectorsPerCluster
);
743 * FUNCTION: Retrieve the next cluster depending on the FAT type
747 PDEVICE_EXTENSION DeviceExt
,
748 ULONG CurrentCluster
,
753 DPRINT("GetNextCluster(DeviceExt %p, CurrentCluster %x)\n",
754 DeviceExt
, CurrentCluster
);
756 if (CurrentCluster
== 0)
758 DPRINT1("WARNING: File system corruption detected. You may need to run a disk repair utility.\n");
759 if (VfatGlobalData
->Flags
& VFAT_BREAK_ON_CORRUPTION
)
760 ASSERT(CurrentCluster
!= 0);
761 return STATUS_FILE_CORRUPT_ERROR
;
764 ExAcquireResourceSharedLite(&DeviceExt
->FatResource
, TRUE
);
765 Status
= DeviceExt
->GetNextCluster(DeviceExt
, CurrentCluster
, NextCluster
);
766 ExReleaseResourceLite(&DeviceExt
->FatResource
);
772 * FUNCTION: Retrieve the next cluster depending on the FAT type
775 GetNextClusterExtend(
776 PDEVICE_EXTENSION DeviceExt
,
777 ULONG CurrentCluster
,
783 DPRINT("GetNextClusterExtend(DeviceExt %p, CurrentCluster %x)\n",
784 DeviceExt
, CurrentCluster
);
786 ExAcquireResourceExclusiveLite(&DeviceExt
->FatResource
, TRUE
);
788 * If the file hasn't any clusters allocated then we need special
791 if (CurrentCluster
== 0)
793 Status
= DeviceExt
->FindAndMarkAvailableCluster(DeviceExt
, &NewCluster
);
794 if (!NT_SUCCESS(Status
))
796 ExReleaseResourceLite(&DeviceExt
->FatResource
);
800 *NextCluster
= NewCluster
;
801 ExReleaseResourceLite(&DeviceExt
->FatResource
);
802 return STATUS_SUCCESS
;
805 Status
= DeviceExt
->GetNextCluster(DeviceExt
, CurrentCluster
, NextCluster
);
807 if ((*NextCluster
) == 0xFFFFFFFF)
809 /* We are after last existing cluster, we must add one to file */
810 /* Firstly, find the next available open allocation unit and
811 mark it as end of file */
812 Status
= DeviceExt
->FindAndMarkAvailableCluster(DeviceExt
, &NewCluster
);
813 if (!NT_SUCCESS(Status
))
815 ExReleaseResourceLite(&DeviceExt
->FatResource
);
819 /* Now, write the AU of the LastCluster with the value of the newly
821 WriteCluster(DeviceExt
, CurrentCluster
, NewCluster
);
822 *NextCluster
= NewCluster
;
825 ExReleaseResourceLite(&DeviceExt
->FatResource
);
830 * FUNCTION: Retrieve the dirty status
834 PDEVICE_EXTENSION DeviceExt
,
835 PBOOLEAN DirtyStatus
)
839 DPRINT("GetDirtyStatus(DeviceExt %p)\n", DeviceExt
);
841 /* FAT12 has no dirty bit */
842 if (DeviceExt
->FatInfo
.FatType
== FAT12
)
844 *DirtyStatus
= FALSE
;
845 return STATUS_SUCCESS
;
848 /* Not really in the FAT, but share the lock because
849 * we're really low-level and shouldn't happent that often
850 * And call the appropriate function
852 ExAcquireResourceSharedLite(&DeviceExt
->FatResource
, TRUE
);
853 Status
= DeviceExt
->GetDirtyStatus(DeviceExt
, DirtyStatus
);
854 ExReleaseResourceLite(&DeviceExt
->FatResource
);
861 PDEVICE_EXTENSION DeviceExt
,
862 PBOOLEAN DirtyStatus
)
864 LARGE_INTEGER Offset
;
866 #ifdef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
871 struct _BootSector
* Sector
;
873 /* We'll read the bootsector at 0 */
875 Length
= DeviceExt
->FatInfo
.BytesPerSector
;
876 #ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
877 /* Go through Cc for this */
880 CcPinRead(DeviceExt
->VolumeFcb
->FileObject
, &Offset
, Length
, PIN_WAIT
, &Context
, (PVOID
*)&Sector
);
882 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
884 _SEH2_YIELD(return _SEH2_GetExceptionCode());
888 /* No Cc, do it the old way:
889 * - Allocate a big enough buffer
890 * - And read the disk
892 Sector
= ExAllocatePoolWithTag(NonPagedPool
, Length
, TAG_BUFFER
);
896 return STATUS_INSUFFICIENT_RESOURCES
;
899 Status
= VfatReadDisk(DeviceExt
->StorageDevice
, &Offset
, Length
, (PUCHAR
)Sector
, FALSE
);
900 if (!NT_SUCCESS(Status
))
903 ExFreePoolWithTag(Sector
, TAG_BUFFER
);
908 /* Make sure we have a boot sector...
909 * FIXME: This check is a bit lame and should be improved
911 if (Sector
->Signatur1
!= 0xaa55)
913 /* Set we are dirty so that we don't attempt anything */
915 #ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
916 CcUnpinData(Context
);
918 ExFreePoolWithTag(Sector
, TAG_BUFFER
);
920 return STATUS_DISK_CORRUPT_ERROR
;
923 /* Return the status of the dirty bit */
924 if (Sector
->Res1
& FAT_DIRTY_BIT
)
927 *DirtyStatus
= FALSE
;
929 #ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
930 CcUnpinData(Context
);
932 ExFreePoolWithTag(Sector
, TAG_BUFFER
);
934 return STATUS_SUCCESS
;
939 PDEVICE_EXTENSION DeviceExt
,
940 PBOOLEAN DirtyStatus
)
942 LARGE_INTEGER Offset
;
944 #ifdef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
949 struct _BootSector32
* Sector
;
951 /* We'll read the bootsector at 0 */
953 Length
= DeviceExt
->FatInfo
.BytesPerSector
;
954 #ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
955 /* Go through Cc for this */
958 CcPinRead(DeviceExt
->VolumeFcb
->FileObject
, &Offset
, Length
, PIN_WAIT
, &Context
, (PVOID
*)&Sector
);
960 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
962 _SEH2_YIELD(return _SEH2_GetExceptionCode());
966 /* No Cc, do it the old way:
967 * - Allocate a big enough buffer
968 * - And read the disk
970 Sector
= ExAllocatePoolWithTag(NonPagedPool
, Length
, TAG_BUFFER
);
974 return STATUS_INSUFFICIENT_RESOURCES
;
977 Status
= VfatReadDisk(DeviceExt
->StorageDevice
, &Offset
, Length
, (PUCHAR
)Sector
, FALSE
);
978 if (!NT_SUCCESS(Status
))
981 ExFreePoolWithTag(Sector
, TAG_BUFFER
);
986 /* Make sure we have a boot sector...
987 * FIXME: This check is a bit lame and should be improved
989 if (Sector
->Signature1
!= 0xaa55)
991 /* Set we are dirty so that we don't attempt anything */
993 #ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
994 CcUnpinData(Context
);
996 ExFreePoolWithTag(Sector
, TAG_BUFFER
);
998 return STATUS_DISK_CORRUPT_ERROR
;
1001 /* Return the status of the dirty bit */
1002 if (Sector
->Res4
& FAT_DIRTY_BIT
)
1003 *DirtyStatus
= TRUE
;
1005 *DirtyStatus
= FALSE
;
1007 #ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
1008 CcUnpinData(Context
);
1010 ExFreePoolWithTag(Sector
, TAG_BUFFER
);
1012 return STATUS_SUCCESS
;
1016 * FUNCTION: Set the dirty status
1020 PDEVICE_EXTENSION DeviceExt
,
1021 BOOLEAN DirtyStatus
)
1025 DPRINT("SetDirtyStatus(DeviceExt %p, DirtyStatus %d)\n", DeviceExt
, DirtyStatus
);
1027 /* FAT12 has no dirty bit */
1028 if (DeviceExt
->FatInfo
.FatType
== FAT12
)
1030 return STATUS_SUCCESS
;
1033 /* Not really in the FAT, but share the lock because
1034 * we're really low-level and shouldn't happent that often
1035 * And call the appropriate function
1036 * Acquire exclusive because we will modify ondisk value
1038 ExAcquireResourceExclusiveLite(&DeviceExt
->FatResource
, TRUE
);
1039 Status
= DeviceExt
->SetDirtyStatus(DeviceExt
, DirtyStatus
);
1040 ExReleaseResourceLite(&DeviceExt
->FatResource
);
1046 FAT16SetDirtyStatus(
1047 PDEVICE_EXTENSION DeviceExt
,
1048 BOOLEAN DirtyStatus
)
1050 LARGE_INTEGER Offset
;
1052 #ifdef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
1057 struct _BootSector
* Sector
;
1059 /* We'll read (and then write) the bootsector at 0 */
1060 Offset
.QuadPart
= 0;
1061 Length
= DeviceExt
->FatInfo
.BytesPerSector
;
1062 #ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
1063 /* Go through Cc for this */
1066 CcPinRead(DeviceExt
->VolumeFcb
->FileObject
, &Offset
, Length
, PIN_WAIT
, &Context
, (PVOID
*)&Sector
);
1068 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1070 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1074 /* No Cc, do it the old way:
1075 * - Allocate a big enough buffer
1076 * - And read the disk
1078 Sector
= ExAllocatePoolWithTag(NonPagedPool
, Length
, TAG_BUFFER
);
1081 return STATUS_INSUFFICIENT_RESOURCES
;
1084 Status
= VfatReadDisk(DeviceExt
->StorageDevice
, &Offset
, Length
, (PUCHAR
)Sector
, FALSE
);
1085 if (!NT_SUCCESS(Status
))
1087 ExFreePoolWithTag(Sector
, TAG_BUFFER
);
1092 /* Make sure we have a boot sector...
1093 * FIXME: This check is a bit lame and should be improved
1095 if (Sector
->Signatur1
!= 0xaa55)
1097 #ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
1098 CcUnpinData(Context
);
1100 ExFreePoolWithTag(Sector
, TAG_BUFFER
);
1102 return STATUS_DISK_CORRUPT_ERROR
;
1105 /* Modify the dirty bit status according
1110 Sector
->Res1
&= ~FAT_DIRTY_BIT
;
1114 Sector
->Res1
|= FAT_DIRTY_BIT
;
1117 #ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
1118 /* Mark boot sector dirty so that it gets written to the disk */
1119 CcSetDirtyPinnedData(Context
, NULL
);
1120 CcUnpinData(Context
);
1121 return STATUS_SUCCESS
;
1123 /* Write back the boot sector to the disk */
1124 Status
= VfatWriteDisk(DeviceExt
->StorageDevice
, &Offset
, Length
, (PUCHAR
)Sector
, FALSE
);
1125 ExFreePoolWithTag(Sector
, TAG_BUFFER
);
1131 FAT32SetDirtyStatus(
1132 PDEVICE_EXTENSION DeviceExt
,
1133 BOOLEAN DirtyStatus
)
1135 LARGE_INTEGER Offset
;
1137 #ifdef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
1142 struct _BootSector32
* Sector
;
1144 /* We'll read (and then write) the bootsector at 0 */
1145 Offset
.QuadPart
= 0;
1146 Length
= DeviceExt
->FatInfo
.BytesPerSector
;
1147 #ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
1148 /* Go through Cc for this */
1151 CcPinRead(DeviceExt
->VolumeFcb
->FileObject
, &Offset
, Length
, PIN_WAIT
, &Context
, (PVOID
*)&Sector
);
1153 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1155 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1159 /* No Cc, do it the old way:
1160 * - Allocate a big enough buffer
1161 * - And read the disk
1163 Sector
= ExAllocatePoolWithTag(NonPagedPool
, Length
, TAG_BUFFER
);
1166 return STATUS_INSUFFICIENT_RESOURCES
;
1169 Status
= VfatReadDisk(DeviceExt
->StorageDevice
, &Offset
, Length
, (PUCHAR
)Sector
, FALSE
);
1170 if (!NT_SUCCESS(Status
))
1172 ExFreePoolWithTag(Sector
, TAG_BUFFER
);
1177 /* Make sure we have a boot sector...
1178 * FIXME: This check is a bit lame and should be improved
1180 if (Sector
->Signature1
!= 0xaa55)
1183 #ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
1184 CcUnpinData(Context
);
1186 ExFreePoolWithTag(Sector
, TAG_BUFFER
);
1188 return STATUS_DISK_CORRUPT_ERROR
;
1191 /* Modify the dirty bit status according
1196 Sector
->Res4
&= ~FAT_DIRTY_BIT
;
1200 Sector
->Res4
|= FAT_DIRTY_BIT
;
1203 #ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
1204 /* Mark boot sector dirty so that it gets written to the disk */
1205 CcSetDirtyPinnedData(Context
, NULL
);
1206 CcUnpinData(Context
);
1207 return STATUS_SUCCESS
;
1209 /* Write back the boot sector to the disk */
1210 Status
= VfatWriteDisk(DeviceExt
->StorageDevice
, &Offset
, Length
, (PUCHAR
)Sector
, FALSE
);
1211 ExFreePoolWithTag(Sector
, TAG_BUFFER
);
1217 FAT32UpdateFreeClustersCount(
1218 PDEVICE_EXTENSION DeviceExt
)
1220 LARGE_INTEGER Offset
;
1222 #ifdef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
1227 struct _FsInfoSector
* Sector
;
1229 if (!DeviceExt
->AvailableClustersValid
)
1231 return STATUS_INVALID_PARAMETER
;
1234 /* We'll read (and then write) the fsinfo sector */
1235 Offset
.QuadPart
= DeviceExt
->FatInfo
.FSInfoSector
* DeviceExt
->FatInfo
.BytesPerSector
;
1236 Length
= DeviceExt
->FatInfo
.BytesPerSector
;
1237 #ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
1238 /* Go through Cc for this */
1241 CcPinRead(DeviceExt
->VolumeFcb
->FileObject
, &Offset
, Length
, PIN_WAIT
, &Context
, (PVOID
*)&Sector
);
1243 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1245 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1249 /* No Cc, do it the old way:
1250 * - Allocate a big enough buffer
1251 * - And read the disk
1253 Sector
= ExAllocatePoolWithTag(NonPagedPool
, Length
, TAG_BUFFER
);
1256 return STATUS_INSUFFICIENT_RESOURCES
;
1259 Status
= VfatReadDisk(DeviceExt
->StorageDevice
, &Offset
, Length
, (PUCHAR
)Sector
, FALSE
);
1260 if (!NT_SUCCESS(Status
))
1262 ExFreePoolWithTag(Sector
, TAG_BUFFER
);
1267 /* Make sure we have a FSINFO sector */
1268 if (Sector
->ExtBootSignature2
!= 0x41615252 ||
1269 Sector
->FSINFOSignature
!= 0x61417272 ||
1270 Sector
->Signatur2
!= 0xaa550000)
1273 #ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
1274 CcUnpinData(Context
);
1276 ExFreePoolWithTag(Sector
, TAG_BUFFER
);
1278 return STATUS_DISK_CORRUPT_ERROR
;
1281 /* Update the free clusters count */
1282 Sector
->FreeCluster
= InterlockedCompareExchange((PLONG
)&DeviceExt
->AvailableClusters
, 0, 0);
1284 #ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
1285 /* Mark FSINFO sector dirty so that it gets written to the disk */
1286 CcSetDirtyPinnedData(Context
, NULL
);
1287 CcUnpinData(Context
);
1288 return STATUS_SUCCESS
;
1290 /* Write back the FSINFO sector to the disk */
1291 Status
= VfatWriteDisk(DeviceExt
->StorageDevice
, &Offset
, Length
, (PUCHAR
)Sector
, FALSE
);
1292 ExFreePoolWithTag(Sector
, TAG_BUFFER
);