2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS VFAT filesystem library
5 * PURPOSE: Fat32 support
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
10 /* INCLUDES *******************************************************************/
18 /* FUNCTIONS ******************************************************************/
21 Fat32WriteBootSector(IN HANDLE FileHandle
,
22 IN PFAT32_BOOT_SECTOR BootSector
,
23 IN OUT PFORMAT_CONTEXT Context
)
25 IO_STATUS_BLOCK IoStatusBlock
;
27 PFAT32_BOOT_SECTOR NewBootSector
;
28 LARGE_INTEGER FileOffset
;
30 /* Allocate buffer for new bootsector */
31 NewBootSector
= (PFAT32_BOOT_SECTOR
)RtlAllocateHeap(RtlGetProcessHeap(),
33 BootSector
->BytesPerSector
);
34 if (NewBootSector
== NULL
)
35 return STATUS_INSUFFICIENT_RESOURCES
;
37 /* Zero the new bootsector */
38 RtlZeroMemory(NewBootSector
, BootSector
->BytesPerSector
);
40 /* Copy FAT32 BPB to new bootsector */
41 memcpy(&NewBootSector
->OEMName
[0],
42 &BootSector
->OEMName
[0],
43 FIELD_OFFSET(FAT32_BOOT_SECTOR
, Res2
) - FIELD_OFFSET(FAT32_BOOT_SECTOR
, OEMName
));
44 /* FAT32 BPB length (up to (not including) Res2) */
46 /* Write the boot sector signature */
47 NewBootSector
->Signature1
= 0xAA550000;
50 FileOffset
.QuadPart
= 0ULL;
51 Status
= NtWriteFile(FileHandle
,
57 BootSector
->BytesPerSector
,
60 if (!NT_SUCCESS(Status
))
62 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
66 UpdateProgress(Context
, 1);
68 /* Write backup boot sector */
69 if (BootSector
->BootBackup
!= 0x0000)
71 FileOffset
.QuadPart
= (ULONGLONG
)((ULONG
)BootSector
->BootBackup
* BootSector
->BytesPerSector
);
72 Status
= NtWriteFile(FileHandle
,
78 BootSector
->BytesPerSector
,
81 if (!NT_SUCCESS(Status
))
83 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
87 UpdateProgress(Context
, 1);
92 RtlFreeHeap(RtlGetProcessHeap(), 0, NewBootSector
);
98 Fat32WriteFsInfo(IN HANDLE FileHandle
,
99 IN PFAT32_BOOT_SECTOR BootSector
,
100 IN OUT PFORMAT_CONTEXT Context
)
102 IO_STATUS_BLOCK IoStatusBlock
;
104 PFAT32_FSINFO FsInfo
;
105 LARGE_INTEGER FileOffset
;
106 ULONGLONG FirstDataSector
;
108 /* Allocate buffer for new sector */
109 FsInfo
= (PFAT32_FSINFO
)RtlAllocateHeap(RtlGetProcessHeap(),
111 BootSector
->BytesPerSector
);
113 return STATUS_INSUFFICIENT_RESOURCES
;
115 /* Zero the first FsInfo sector */
116 RtlZeroMemory(FsInfo
, BootSector
->BytesPerSector
);
118 FirstDataSector
= BootSector
->ReservedSectors
+
119 (BootSector
->FATCount
* BootSector
->FATSectors32
) + 0 /* RootDirSectors */;
121 FsInfo
->LeadSig
= FSINFO_SECTOR_BEGIN_SIGNATURE
;
122 FsInfo
->StrucSig
= FSINFO_SIGNATURE
;
123 FsInfo
->FreeCount
= (BootSector
->SectorsHuge
- FirstDataSector
) / BootSector
->SectorsPerCluster
- 1;
124 FsInfo
->NextFree
= 0xffffffff;
125 FsInfo
->TrailSig
= FSINFO_SECTOR_END_SIGNATURE
;
127 /* Write the first FsInfo sector */
128 FileOffset
.QuadPart
= BootSector
->FSInfoSector
* BootSector
->BytesPerSector
;
129 Status
= NtWriteFile(FileHandle
,
135 BootSector
->BytesPerSector
,
138 if (!NT_SUCCESS(Status
))
140 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
144 UpdateProgress(Context
, 1);
146 /* Write backup of the first FsInfo sector */
147 if (BootSector
->BootBackup
!= 0x0000)
149 /* Reset the free cluster count for the backup */
150 FsInfo
->FreeCount
= 0xffffffff;
152 FileOffset
.QuadPart
= (ULONGLONG
)(((ULONG
)BootSector
->BootBackup
+ (ULONG
)BootSector
->FSInfoSector
) * BootSector
->BytesPerSector
);
153 Status
= NtWriteFile(FileHandle
,
159 BootSector
->BytesPerSector
,
162 if (!NT_SUCCESS(Status
))
164 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
168 UpdateProgress(Context
, 1);
171 /* Zero the second FsInfo sector */
172 RtlZeroMemory(FsInfo
, BootSector
->BytesPerSector
);
173 FsInfo
->TrailSig
= FSINFO_SECTOR_END_SIGNATURE
;
175 /* Write the second FsInfo sector */
176 FileOffset
.QuadPart
= (BootSector
->FSInfoSector
+ 1) * BootSector
->BytesPerSector
;
177 Status
= NtWriteFile(FileHandle
,
183 BootSector
->BytesPerSector
,
186 if (!NT_SUCCESS(Status
))
188 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
192 UpdateProgress(Context
, 1);
194 /* Write backup of the second FsInfo sector */
195 if (BootSector
->BootBackup
!= 0x0000)
197 FileOffset
.QuadPart
= (ULONGLONG
)(((ULONG
)BootSector
->BootBackup
+ (ULONG
)BootSector
->FSInfoSector
+ 1) * BootSector
->BytesPerSector
);
198 Status
= NtWriteFile(FileHandle
,
204 BootSector
->BytesPerSector
,
207 if (!NT_SUCCESS(Status
))
209 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
213 UpdateProgress(Context
, 1);
217 /* Free the buffer */
218 RtlFreeHeap(RtlGetProcessHeap(), 0, FsInfo
);
224 Fat32WriteFAT(IN HANDLE FileHandle
,
225 IN ULONG SectorOffset
,
226 IN PFAT32_BOOT_SECTOR BootSector
,
227 IN OUT PFORMAT_CONTEXT Context
)
229 IO_STATUS_BLOCK IoStatusBlock
;
232 LARGE_INTEGER FileOffset
;
236 /* Allocate buffer */
237 Buffer
= (PUCHAR
)RtlAllocateHeap(RtlGetProcessHeap(),
241 return STATUS_INSUFFICIENT_RESOURCES
;
243 /* Zero the buffer */
244 RtlZeroMemory(Buffer
, 64 * 1024);
247 Buffer
[0] = 0xf8; /* Media type */
253 Buffer
[4] = 0xff; /* Clean shutdown, no disk read/write errors, end-of-cluster (EOC) mark */
259 Buffer
[8] = 0xff; /* End of root directory */
264 /* Write first sector of the FAT */
265 FileOffset
.QuadPart
= (SectorOffset
+ BootSector
->ReservedSectors
) * BootSector
->BytesPerSector
;
266 Status
= NtWriteFile(FileHandle
,
272 BootSector
->BytesPerSector
,
275 if (!NT_SUCCESS(Status
))
277 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
281 UpdateProgress(Context
, 1);
283 /* Zero the begin of the buffer */
284 RtlZeroMemory(Buffer
, 12);
286 /* Zero the rest of the FAT */
287 Sectors
= 64 * 1024 / BootSector
->BytesPerSector
;
288 for (i
= 1; i
< BootSector
->FATSectors32
; i
+= Sectors
)
290 /* Zero some sectors of the FAT */
291 FileOffset
.QuadPart
= (SectorOffset
+ BootSector
->ReservedSectors
+ i
) * BootSector
->BytesPerSector
;
293 if ((BootSector
->FATSectors32
- i
) <= Sectors
)
295 Sectors
= BootSector
->FATSectors32
- i
;
298 Status
= NtWriteFile(FileHandle
,
304 Sectors
* BootSector
->BytesPerSector
,
307 if (!NT_SUCCESS(Status
))
309 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
313 UpdateProgress(Context
, Sectors
);
317 /* Free the buffer */
318 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
324 Fat32WriteRootDirectory(IN HANDLE FileHandle
,
325 IN PFAT32_BOOT_SECTOR BootSector
,
326 IN OUT PFORMAT_CONTEXT Context
)
328 IO_STATUS_BLOCK IoStatusBlock
;
331 LARGE_INTEGER FileOffset
;
332 ULONGLONG FirstDataSector
;
333 ULONGLONG FirstRootDirSector
;
335 /* Allocate buffer for the cluster */
336 Buffer
= (PUCHAR
)RtlAllocateHeap(RtlGetProcessHeap(),
338 BootSector
->SectorsPerCluster
* BootSector
->BytesPerSector
);
340 return STATUS_INSUFFICIENT_RESOURCES
;
342 /* Zero the buffer */
343 RtlZeroMemory(Buffer
, BootSector
->SectorsPerCluster
* BootSector
->BytesPerSector
);
345 DPRINT("BootSector->ReservedSectors = %lu\n", BootSector
->ReservedSectors
);
346 DPRINT("BootSector->FATSectors32 = %lu\n", BootSector
->FATSectors32
);
347 DPRINT("BootSector->RootCluster = %lu\n", BootSector
->RootCluster
);
348 DPRINT("BootSector->SectorsPerCluster = %lu\n", BootSector
->SectorsPerCluster
);
351 FirstDataSector
= BootSector
->ReservedSectors
+
352 (BootSector
->FATCount
* BootSector
->FATSectors32
) + 0 /* RootDirSectors */;
354 DPRINT("FirstDataSector = %lu\n", FirstDataSector
);
356 FirstRootDirSector
= ((BootSector
->RootCluster
- 2) * BootSector
->SectorsPerCluster
) + FirstDataSector
;
357 FileOffset
.QuadPart
= FirstRootDirSector
* BootSector
->BytesPerSector
;
359 DPRINT("FirstRootDirSector = %lu\n", FirstRootDirSector
);
360 DPRINT("FileOffset = %lu\n", FileOffset
.QuadPart
);
362 Status
= NtWriteFile(FileHandle
,
368 BootSector
->SectorsPerCluster
* BootSector
->BytesPerSector
,
371 if (!NT_SUCCESS(Status
))
373 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
377 UpdateProgress(Context
, (ULONG
)BootSector
->SectorsPerCluster
);
380 /* Free the buffer */
381 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
387 Fat32Format(IN HANDLE FileHandle
,
388 IN PPARTITION_INFORMATION PartitionInfo
,
389 IN PDISK_GEOMETRY DiskGeometry
,
390 IN PUNICODE_STRING Label
,
391 IN BOOLEAN QuickFormat
,
392 IN ULONG ClusterSize
,
393 IN OUT PFORMAT_CONTEXT Context
)
395 FAT32_BOOT_SECTOR BootSector
;
396 OEM_STRING VolumeLabel
;
400 ULONG UsableFatEntries
;
401 ULONG FirstDataSector
;
404 /* Calculate cluster size */
405 if (ClusterSize
== 0)
407 if (PartitionInfo
->PartitionLength
.QuadPart
< 8LL * 1024LL * 1024LL * 1024LL)
409 /* Partition < 8GB ==> 4KB Cluster */
412 else if (PartitionInfo
->PartitionLength
.QuadPart
< 16LL * 1024LL * 1024LL * 1024LL)
414 /* Partition 8GB - 16GB ==> 8KB Cluster */
417 else if (PartitionInfo
->PartitionLength
.QuadPart
< 32LL * 1024LL * 1024LL * 1024LL)
419 /* Partition 16GB - 32GB ==> 16KB Cluster */
424 /* Partition >= 32GB ==> 32KB Cluster */
429 RtlZeroMemory(&BootSector
, sizeof(FAT32_BOOT_SECTOR
));
430 memcpy(&BootSector
.OEMName
[0], "MSWIN4.1", 8);
431 BootSector
.BytesPerSector
= DiskGeometry
->BytesPerSector
;
432 BootSector
.SectorsPerCluster
= ClusterSize
/ BootSector
.BytesPerSector
;
433 BootSector
.ReservedSectors
= 32;
434 BootSector
.FATCount
= 2;
435 BootSector
.RootEntries
= 0;
436 BootSector
.Sectors
= 0;
437 BootSector
.Media
= 0xf8;
438 BootSector
.FATSectors
= 0;
439 BootSector
.SectorsPerTrack
= DiskGeometry
->SectorsPerTrack
;
440 BootSector
.Heads
= DiskGeometry
->TracksPerCylinder
;
441 BootSector
.HiddenSectors
= PartitionInfo
->HiddenSectors
;
442 BootSector
.SectorsHuge
= PartitionInfo
->PartitionLength
.QuadPart
>>
443 GetShiftCount(BootSector
.BytesPerSector
); /* Use shifting to avoid 64-bit division */
444 BootSector
.FATSectors32
= 0; /* Set later */
445 BootSector
.ExtFlag
= 0; /* Mirror all FATs */
446 BootSector
.FSVersion
= 0x0000; /* 0:0 */
447 BootSector
.RootCluster
= 2;
448 BootSector
.FSInfoSector
= 1;
449 BootSector
.BootBackup
= 6;
450 BootSector
.Drive
= (DiskGeometry
->MediaType
== FixedMedia
) ? 0x80 : 0x00;
451 BootSector
.ExtBootSignature
= 0x29;
452 BootSector
.VolumeID
= CalcVolumeSerialNumber();
453 if ((Label
== NULL
) || (Label
->Buffer
== NULL
))
455 memcpy(&BootSector
.VolumeLabel
[0], "NO NAME ", 11);
459 RtlUnicodeStringToOemString(&VolumeLabel
, Label
, TRUE
);
460 RtlFillMemory(&BootSector
.VolumeLabel
[0], 11, ' ');
461 memcpy(&BootSector
.VolumeLabel
[0], VolumeLabel
.Buffer
,
462 VolumeLabel
.Length
< 11 ? VolumeLabel
.Length
: 11);
463 RtlFreeOemString(&VolumeLabel
);
466 memcpy(&BootSector
.SysType
[0], "FAT32 ", 8);
468 /* Calculate number of FAT sectors */
469 /* (BytesPerSector / 4) FAT entries (32bit) fit into one sector */
470 TmpVal1
= BootSector
.SectorsHuge
- BootSector
.ReservedSectors
;
471 TmpVal2
= ((BootSector
.BytesPerSector
/ 4) * BootSector
.SectorsPerCluster
) + BootSector
.FATCount
;
472 BootSector
.FATSectors32
= (TmpVal1
+ (TmpVal2
- 1)) / TmpVal2
;
473 DPRINT("FATSectors32 = %lu\n", BootSector
.FATSectors32
);
475 /* edge case: first 2 fat entries are not usable, so the calculation might need a correction */
476 UsableFatEntries
= BootSector
.FATSectors32
* (BootSector
.BytesPerSector
/ 4) - 2;
477 FirstDataSector
= BootSector
.ReservedSectors
+ BootSector
.FATCount
* BootSector
.FATSectors32
;
478 DataClusters
= (BootSector
.SectorsHuge
- FirstDataSector
) / BootSector
.SectorsPerCluster
;
479 if (DataClusters
> UsableFatEntries
)
481 /* Need more fat entries */
482 BootSector
.FATSectors32
+= (DataClusters
- UsableFatEntries
);
484 DPRINT("UsableFatEntries = %lu\n", UsableFatEntries
);
485 DPRINT("DataClusters = %lu\n", DataClusters
);
486 DPRINT("BootSector.FATSectors32 incremented to %lu\n", BootSector
.FATSectors32
);
489 /* Init context data */
490 Context
->TotalSectorCount
=
491 2 + (BootSector
.FATSectors32
* BootSector
.FATCount
) + BootSector
.SectorsPerCluster
;
495 Context
->TotalSectorCount
+= BootSector
.SectorsHuge
;
497 Status
= FatWipeSectors(FileHandle
,
498 BootSector
.SectorsHuge
,
499 (ULONG
)BootSector
.SectorsPerCluster
,
500 (ULONG
)BootSector
.BytesPerSector
,
502 if (!NT_SUCCESS(Status
))
504 DPRINT("FatWipeSectors() failed with status 0x%.08x\n", Status
);
509 Status
= Fat32WriteBootSector(FileHandle
,
512 if (!NT_SUCCESS(Status
))
514 DPRINT("Fat32WriteBootSector() failed with status 0x%.08x\n", Status
);
518 Status
= Fat32WriteFsInfo(FileHandle
,
521 if (!NT_SUCCESS(Status
))
523 DPRINT("Fat32WriteFsInfo() failed with status 0x%.08x\n", Status
);
527 /* Write first FAT copy */
528 Status
= Fat32WriteFAT(FileHandle
,
532 if (!NT_SUCCESS(Status
))
534 DPRINT("Fat32WriteFAT() failed with status 0x%.08x\n", Status
);
538 /* Write second FAT copy */
539 Status
= Fat32WriteFAT(FileHandle
,
540 BootSector
.FATSectors32
,
543 if (!NT_SUCCESS(Status
))
545 DPRINT("Fat32WriteFAT() failed with status 0x%.08x.\n", Status
);
549 Status
= Fat32WriteRootDirectory(FileHandle
,
552 if (!NT_SUCCESS(Status
))
554 DPRINT("Fat32WriteRootDirectory() failed with status 0x%.08x\n", Status
);