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)
9 * EK 05/04-2003 Created
17 GetShiftCount(IN ULONG Value
)
32 CalcVolumeSerialNumber(VOID
)
34 LARGE_INTEGER SystemTime
;
35 TIME_FIELDS TimeFields
;
39 NtQuerySystemTime (&SystemTime
);
40 RtlTimeToTimeFields (&SystemTime
, &TimeFields
);
42 Buffer
= (PUCHAR
)&Serial
;
43 Buffer
[0] = (UCHAR
)(TimeFields
.Year
& 0xFF) + (UCHAR
)(TimeFields
.Hour
& 0xFF);
44 Buffer
[1] = (UCHAR
)(TimeFields
.Year
>> 8) + (UCHAR
)(TimeFields
.Minute
& 0xFF);
45 Buffer
[2] = (UCHAR
)(TimeFields
.Month
& 0xFF) + (UCHAR
)(TimeFields
.Second
& 0xFF);
46 Buffer
[3] = (UCHAR
)(TimeFields
.Day
& 0xFF) + (UCHAR
)(TimeFields
.Milliseconds
& 0xFF);
53 Fat32WriteBootSector(IN HANDLE FileHandle
,
54 IN PFAT32_BOOT_SECTOR BootSector
,
55 IN OUT PFORMAT_CONTEXT Context
)
57 IO_STATUS_BLOCK IoStatusBlock
;
59 PFAT32_BOOT_SECTOR NewBootSector
;
60 LARGE_INTEGER FileOffset
;
62 /* Allocate buffer for new bootsector */
63 NewBootSector
= (PFAT32_BOOT_SECTOR
)RtlAllocateHeap(RtlGetProcessHeap(),
65 BootSector
->BytesPerSector
);
66 if (NewBootSector
== NULL
)
67 return STATUS_INSUFFICIENT_RESOURCES
;
69 /* Zero the new bootsector */
70 memset(NewBootSector
, 0, BootSector
->BytesPerSector
);
72 /* Copy FAT32 BPB to new bootsector */
73 memcpy(&NewBootSector
->OEMName
[0],
74 &BootSector
->OEMName
[0],
75 FIELD_OFFSET(FAT32_BOOT_SECTOR
, Res2
) - FIELD_OFFSET(FAT32_BOOT_SECTOR
, OEMName
)); /* FAT32 BPB length (up to (not including) Res2) */
77 /* Write the boot sector signature */
78 NewBootSector
->Signature1
= 0xAA550000;
81 FileOffset
.QuadPart
= 0ULL;
82 Status
= NtWriteFile(FileHandle
,
88 BootSector
->BytesPerSector
,
91 if (!NT_SUCCESS(Status
))
93 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
94 RtlFreeHeap(RtlGetProcessHeap(), 0, NewBootSector
);
98 UpdateProgress(Context
, 1);
100 /* Write backup boot sector */
101 if (BootSector
->BootBackup
!= 0x0000)
103 FileOffset
.QuadPart
= (ULONGLONG
)((ULONG
)BootSector
->BootBackup
* BootSector
->BytesPerSector
);
104 Status
= NtWriteFile(FileHandle
,
110 BootSector
->BytesPerSector
,
113 if (!NT_SUCCESS(Status
))
115 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
116 RtlFreeHeap(RtlGetProcessHeap(), 0, NewBootSector
);
120 UpdateProgress(Context
, 1);
123 /* Free the new boot sector */
124 RtlFreeHeap(RtlGetProcessHeap(), 0, NewBootSector
);
131 Fat32WriteFsInfo(IN HANDLE FileHandle
,
132 IN PFAT32_BOOT_SECTOR BootSector
,
133 IN OUT PFORMAT_CONTEXT Context
)
135 IO_STATUS_BLOCK IoStatusBlock
;
137 PFAT32_FSINFO FsInfo
;
138 LARGE_INTEGER FileOffset
;
140 /* Allocate buffer for new sector */
141 FsInfo
= (PFAT32_FSINFO
)RtlAllocateHeap(RtlGetProcessHeap(),
143 BootSector
->BytesPerSector
);
145 return STATUS_INSUFFICIENT_RESOURCES
;
147 /* Zero the new sector */
148 memset(FsInfo
, 0, BootSector
->BytesPerSector
);
150 FsInfo
->LeadSig
= 0x41615252;
151 FsInfo
->StrucSig
= 0x61417272;
152 FsInfo
->FreeCount
= 0xffffffff;
153 FsInfo
->NextFree
= 0xffffffff;
154 FsInfo
->TrailSig
= 0xaa550000;
157 FileOffset
.QuadPart
= BootSector
->FSInfoSector
* BootSector
->BytesPerSector
;
158 Status
= NtWriteFile(FileHandle
,
164 BootSector
->BytesPerSector
,
167 if (!NT_SUCCESS(Status
))
169 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
170 RtlFreeHeap(RtlGetProcessHeap(), 0, FsInfo
);
174 UpdateProgress(Context
, 1);
176 /* Free the new sector buffer */
177 RtlFreeHeap(RtlGetProcessHeap(), 0, FsInfo
);
184 Fat32WriteFAT(IN HANDLE FileHandle
,
185 IN ULONG SectorOffset
,
186 IN PFAT32_BOOT_SECTOR BootSector
,
187 IN OUT PFORMAT_CONTEXT Context
)
189 IO_STATUS_BLOCK IoStatusBlock
;
192 LARGE_INTEGER FileOffset
;
196 /* Allocate buffer */
197 Buffer
= (PUCHAR
)RtlAllocateHeap(RtlGetProcessHeap(),
201 return STATUS_INSUFFICIENT_RESOURCES
;
203 /* Zero the buffer */
204 memset(Buffer
, 0, 64 * 1024);
207 Buffer
[0] = 0xf8; /* Media type */
213 Buffer
[4] = 0xff; /* Clean shutdown, no disk read/write errors, end-of-cluster (EOC) mark */
219 Buffer
[8] = 0xff; /* End of root directory */
224 /* Write first sector of the FAT */
225 FileOffset
.QuadPart
= (SectorOffset
+ BootSector
->ReservedSectors
) * BootSector
->BytesPerSector
;
226 Status
= NtWriteFile(FileHandle
,
232 BootSector
->BytesPerSector
,
235 if (!NT_SUCCESS(Status
))
237 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
238 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
242 UpdateProgress(Context
, 1);
244 /* Zero the begin of the buffer */
245 memset(Buffer
, 0, 12);
247 /* Zero the rest of the FAT */
248 Sectors
= 64 * 1024 / BootSector
->BytesPerSector
;
249 for (i
= 1; i
< BootSector
->FATSectors32
; i
+= Sectors
)
251 /* Zero some sectors of the FAT */
252 FileOffset
.QuadPart
= (SectorOffset
+ BootSector
->ReservedSectors
+ i
) * BootSector
->BytesPerSector
;
254 if ((BootSector
->FATSectors32
- i
) <= Sectors
)
256 Sectors
= BootSector
->FATSectors32
- i
;
259 Status
= NtWriteFile(FileHandle
,
265 Sectors
* BootSector
->BytesPerSector
,
268 if (!NT_SUCCESS(Status
))
270 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
271 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
275 UpdateProgress(Context
, Sectors
);
278 /* Free the buffer */
279 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
286 Fat32WriteRootDirectory(IN HANDLE FileHandle
,
287 IN PFAT32_BOOT_SECTOR BootSector
,
288 IN OUT PFORMAT_CONTEXT Context
)
290 IO_STATUS_BLOCK IoStatusBlock
;
293 LARGE_INTEGER FileOffset
;
294 ULONGLONG FirstDataSector
;
295 ULONGLONG FirstRootDirSector
;
297 /* Allocate buffer for the cluster */
298 Buffer
= (PUCHAR
)RtlAllocateHeap(RtlGetProcessHeap(),
300 BootSector
->SectorsPerCluster
* BootSector
->BytesPerSector
);
302 return STATUS_INSUFFICIENT_RESOURCES
;
304 /* Zero the buffer */
305 memset(Buffer
, 0, BootSector
->SectorsPerCluster
* BootSector
->BytesPerSector
);
307 DPRINT("BootSector->ReservedSectors = %lu\n", BootSector
->ReservedSectors
);
308 DPRINT("BootSector->FATSectors32 = %lu\n", BootSector
->FATSectors32
);
309 DPRINT("BootSector->RootCluster = %lu\n", BootSector
->RootCluster
);
310 DPRINT("BootSector->SectorsPerCluster = %lu\n", BootSector
->SectorsPerCluster
);
313 FirstDataSector
= BootSector
->ReservedSectors
+
314 (BootSector
->FATCount
* BootSector
->FATSectors32
) + 0 /* RootDirSectors */;
316 DPRINT("FirstDataSector = %lu\n", FirstDataSector
);
318 FirstRootDirSector
= ((BootSector
->RootCluster
- 2) * BootSector
->SectorsPerCluster
) + FirstDataSector
;
319 FileOffset
.QuadPart
= FirstRootDirSector
* BootSector
->BytesPerSector
;
321 DPRINT("FirstRootDirSector = %lu\n", FirstRootDirSector
);
322 DPRINT("FileOffset = %lu\n", FileOffset
.QuadPart
);
324 Status
= NtWriteFile(FileHandle
,
330 BootSector
->SectorsPerCluster
* BootSector
->BytesPerSector
,
333 if (!NT_SUCCESS(Status
))
335 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
336 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
340 UpdateProgress(Context
, (ULONG
)BootSector
->SectorsPerCluster
);
342 /* Free the buffer */
343 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
352 IN HANDLE FileHandle
,
353 IN PFAT32_BOOT_SECTOR BootSector
,
354 IN OUT PFORMAT_CONTEXT Context
)
356 IO_STATUS_BLOCK IoStatusBlock
;
358 LARGE_INTEGER FileOffset
;
363 /* Allocate buffer for the cluster */
364 Buffer
= (PUCHAR
)RtlAllocateHeap(RtlGetProcessHeap(),
366 BootSector
->SectorsPerCluster
* BootSector
->BytesPerSector
);
368 return STATUS_INSUFFICIENT_RESOURCES
;
371 Length
= BootSector
->SectorsPerCluster
* BootSector
->BytesPerSector
;
373 while (Sector
+ BootSector
->SectorsPerCluster
< BootSector
->SectorsHuge
)
375 FileOffset
.QuadPart
= Sector
* BootSector
->BytesPerSector
;
377 Status
= NtWriteFile(FileHandle
,
386 if (!NT_SUCCESS(Status
))
388 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
392 UpdateProgress(Context
, (ULONG
)BootSector
->SectorsPerCluster
);
394 Sector
+= BootSector
->SectorsPerCluster
;
397 if (Sector
+ BootSector
->SectorsPerCluster
> BootSector
->SectorsHuge
)
399 DPRINT("Remaining sectors %lu\n", BootSector
->SectorsHuge
- Sector
);
401 FileOffset
.QuadPart
= Sector
* BootSector
->BytesPerSector
;
402 Length
= (BootSector
->SectorsHuge
- Sector
) * BootSector
->BytesPerSector
;
404 Status
= NtWriteFile(FileHandle
,
413 if (!NT_SUCCESS(Status
))
415 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
419 UpdateProgress(Context
, BootSector
->SectorsHuge
- Sector
);
423 /* Free the buffer */
424 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
431 Fat32Format(IN HANDLE FileHandle
,
432 IN PPARTITION_INFORMATION PartitionInfo
,
433 IN PDISK_GEOMETRY DiskGeometry
,
434 IN PUNICODE_STRING Label
,
435 IN BOOLEAN QuickFormat
,
436 IN ULONG ClusterSize
,
437 IN OUT PFORMAT_CONTEXT Context
)
439 FAT32_BOOT_SECTOR BootSector
;
440 OEM_STRING VolumeLabel
;
445 /* Calculate cluster size */
446 if (ClusterSize
== 0)
448 if (PartitionInfo
->PartitionLength
.QuadPart
< 8LL * 1024LL * 1024LL * 1024LL)
450 /* Partition < 8GB ==> 4KB Cluster */
453 else if (PartitionInfo
->PartitionLength
.QuadPart
< 16LL * 1024LL * 1024LL * 1024LL)
455 /* Partition 8GB - 16GB ==> 8KB Cluster */
458 else if (PartitionInfo
->PartitionLength
.QuadPart
< 32LL * 1024LL * 1024LL * 1024LL)
460 /* Partition 16GB - 32GB ==> 16KB Cluster */
465 /* Partition >= 32GB ==> 32KB Cluster */
470 memset(&BootSector
, 0, sizeof(FAT32_BOOT_SECTOR
));
471 memcpy(&BootSector
.OEMName
[0], "MSWIN4.1", 8);
472 BootSector
.BytesPerSector
= DiskGeometry
->BytesPerSector
;
473 BootSector
.SectorsPerCluster
= ClusterSize
/ BootSector
.BytesPerSector
;
474 BootSector
.ReservedSectors
= 32;
475 BootSector
.FATCount
= 2;
476 BootSector
.RootEntries
= 0;
477 BootSector
.Sectors
= 0;
478 BootSector
.Media
= 0xf8;
479 BootSector
.FATSectors
= 0;
480 BootSector
.SectorsPerTrack
= DiskGeometry
->SectorsPerTrack
;
481 BootSector
.Heads
= DiskGeometry
->TracksPerCylinder
;
482 BootSector
.HiddenSectors
= PartitionInfo
->HiddenSectors
;
483 BootSector
.SectorsHuge
= PartitionInfo
->PartitionLength
.QuadPart
>>
484 GetShiftCount(BootSector
.BytesPerSector
); /* Use shifting to avoid 64-bit division */
485 BootSector
.FATSectors32
= 0; /* Set later */
486 BootSector
.ExtFlag
= 0; /* Mirror all FATs */
487 BootSector
.FSVersion
= 0x0000; /* 0:0 */
488 BootSector
.RootCluster
= 2;
489 BootSector
.FSInfoSector
= 1;
490 BootSector
.BootBackup
= 6;
491 BootSector
.Drive
= (DiskGeometry
->MediaType
== FixedMedia
) ? 0x80 : 0x00;
492 BootSector
.ExtBootSignature
= 0x29;
493 BootSector
.VolumeID
= CalcVolumeSerialNumber ();
494 if ((Label
== NULL
) || (Label
->Buffer
== NULL
))
496 memcpy(&BootSector
.VolumeLabel
[0], "NO NAME ", 11);
500 RtlUnicodeStringToOemString(&VolumeLabel
, Label
, TRUE
);
501 memset(&BootSector
.VolumeLabel
[0], ' ', 11);
502 memcpy(&BootSector
.VolumeLabel
[0], VolumeLabel
.Buffer
,
503 VolumeLabel
.Length
< 11 ? VolumeLabel
.Length
: 11);
504 RtlFreeOemString(&VolumeLabel
);
507 memcpy(&BootSector
.SysType
[0], "FAT32 ", 8);
509 /* Calculate number of FAT sectors */
510 /* (BytesPerSector / 4) FAT entries (32bit) fit into one sector */
511 TmpVal1
= BootSector
.SectorsHuge
- BootSector
.ReservedSectors
;
512 TmpVal2
= ((BootSector
.BytesPerSector
/ 4) * BootSector
.SectorsPerCluster
) + BootSector
.FATCount
;
513 BootSector
.FATSectors32
= (TmpVal1
+ (TmpVal2
- 1)) / TmpVal2
;
514 DPRINT("FATSectors32 = %lu\n", BootSector
.FATSectors32
);
516 /* Init context data */
517 Context
->TotalSectorCount
=
518 2 + (BootSector
.FATSectors32
* BootSector
.FATCount
) + BootSector
.SectorsPerCluster
;
522 Context
->TotalSectorCount
+= BootSector
.SectorsHuge
;
524 Status
= Fat32WipeSectors(FileHandle
,
527 if (!NT_SUCCESS(Status
))
529 DPRINT("Fat32WipeSectors() failed with status 0x%.08x\n", Status
);
534 Status
= Fat32WriteBootSector(FileHandle
,
537 if (!NT_SUCCESS(Status
))
539 DPRINT("Fat32WriteBootSector() failed with status 0x%.08x\n", Status
);
543 Status
= Fat32WriteFsInfo(FileHandle
,
546 if (!NT_SUCCESS(Status
))
548 DPRINT("Fat32WriteFsInfo() failed with status 0x%.08x\n", Status
);
552 /* Write first FAT copy */
553 Status
= Fat32WriteFAT(FileHandle
,
557 if (!NT_SUCCESS(Status
))
559 DPRINT("Fat32WriteFAT() failed with status 0x%.08x\n", Status
);
563 /* Write second FAT copy */
564 Status
= Fat32WriteFAT(FileHandle
,
565 BootSector
.FATSectors32
,
568 if (!NT_SUCCESS(Status
))
570 DPRINT("Fat32WriteFAT() failed with status 0x%.08x.\n", Status
);
574 Status
= Fat32WriteRootDirectory(FileHandle
,
577 if (!NT_SUCCESS(Status
))
579 DPRINT("Fat32WriteRootDirectory() failed with status 0x%.08x\n", Status
);