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)
7 * Eric Kohl (ekohl@rz-online.de)
9 * EK 05/04-2003 Created
17 GetShiftCount(ULONG Value
)
30 CalcVolumeSerialNumber(VOID
)
32 LARGE_INTEGER SystemTime
;
33 TIME_FIELDS TimeFields
;
37 NtQuerySystemTime (&SystemTime
);
38 RtlTimeToTimeFields (&SystemTime
, &TimeFields
);
40 Buffer
= (PUCHAR
)&Serial
;
41 Buffer
[0] = (UCHAR
)(TimeFields
.Year
& 0xFF) + (UCHAR
)(TimeFields
.Hour
& 0xFF);
42 Buffer
[1] = (UCHAR
)(TimeFields
.Year
>> 8) + (UCHAR
)(TimeFields
.Minute
& 0xFF);
43 Buffer
[2] = (UCHAR
)(TimeFields
.Month
& 0xFF) + (UCHAR
)(TimeFields
.Second
& 0xFF);
44 Buffer
[3] = (UCHAR
)(TimeFields
.Day
& 0xFF) + (UCHAR
)(TimeFields
.Milliseconds
& 0xFF);
51 Fat32WriteBootSector (IN HANDLE FileHandle
,
52 IN PFAT32_BOOT_SECTOR BootSector
,
53 IN OUT PFORMAT_CONTEXT Context
)
55 IO_STATUS_BLOCK IoStatusBlock
;
58 LARGE_INTEGER FileOffset
;
60 /* Allocate buffer for new bootsector */
61 NewBootSector
= (PUCHAR
)RtlAllocateHeap(RtlGetProcessHeap(),
64 if (NewBootSector
== NULL
)
65 return(STATUS_INSUFFICIENT_RESOURCES
);
67 /* Zero the new bootsector */
68 memset(NewBootSector
, 0, SECTORSIZE
);
70 /* Copy FAT32 BPB to new bootsector */
71 memcpy((NewBootSector
+ 3),
72 &BootSector
->OEMName
[0],
73 87); /* FAT32 BPB length (up to (not including) Res2) */
76 FileOffset
.QuadPart
= 0ULL;
77 Status
= NtWriteFile(FileHandle
,
86 if (!NT_SUCCESS(Status
))
88 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
89 RtlFreeHeap(RtlGetProcessHeap(), 0, NewBootSector
);
93 UpdateProgress (Context
, 1);
95 /* Write backup boot sector */
96 if (BootSector
->BootBackup
!= 0x0000)
98 FileOffset
.QuadPart
= (ULONGLONG
)((ULONG
) BootSector
->BootBackup
* SECTORSIZE
);
99 Status
= NtWriteFile(FileHandle
,
108 if (!NT_SUCCESS(Status
))
110 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
111 RtlFreeHeap(RtlGetProcessHeap(), 0, NewBootSector
);
115 UpdateProgress (Context
, 1);
118 /* Free the new boot sector */
119 RtlFreeHeap(RtlGetProcessHeap(), 0, NewBootSector
);
126 Fat32WriteFsInfo (IN HANDLE FileHandle
,
127 IN PFAT32_BOOT_SECTOR BootSector
,
128 IN OUT PFORMAT_CONTEXT Context
)
130 IO_STATUS_BLOCK IoStatusBlock
;
132 PFAT32_FSINFO FsInfo
;
133 LARGE_INTEGER FileOffset
;
135 /* Allocate buffer for new sector */
136 FsInfo
= (PFAT32_FSINFO
)RtlAllocateHeap(RtlGetProcessHeap(),
138 BootSector
->BytesPerSector
);
140 return(STATUS_INSUFFICIENT_RESOURCES
);
142 /* Zero the new sector */
143 memset(FsInfo
, 0, BootSector
->BytesPerSector
);
145 FsInfo
->LeadSig
= 0x41615252;
146 FsInfo
->StrucSig
= 0x61417272;
147 FsInfo
->FreeCount
= 0xffffffff;
148 FsInfo
->NextFree
= 0xffffffff;
149 FsInfo
->TrailSig
= 0xaa550000;
152 FileOffset
.QuadPart
= BootSector
->FSInfoSector
* BootSector
->BytesPerSector
;
153 Status
= NtWriteFile(FileHandle
,
159 BootSector
->BytesPerSector
,
162 if (!NT_SUCCESS(Status
))
164 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
165 RtlFreeHeap(RtlGetProcessHeap(), 0, FsInfo
);
169 UpdateProgress (Context
, 1);
171 /* Free the new sector buffer */
172 RtlFreeHeap(RtlGetProcessHeap(), 0, FsInfo
);
179 Fat32WriteFAT (IN HANDLE FileHandle
,
180 IN ULONG SectorOffset
,
181 IN PFAT32_BOOT_SECTOR BootSector
,
182 IN OUT PFORMAT_CONTEXT Context
)
184 IO_STATUS_BLOCK IoStatusBlock
;
187 LARGE_INTEGER FileOffset
;
191 /* Allocate buffer */
192 Buffer
= (PUCHAR
)RtlAllocateHeap(RtlGetProcessHeap(),
196 return(STATUS_INSUFFICIENT_RESOURCES
);
198 /* Zero the buffer */
199 memset(Buffer
, 0, 64 * 1024);
202 Buffer
[0] = 0xf8; /* Media type */
207 Buffer
[4] = 0xff; /* Clean shutdown, no disk read/write errors, end-of-cluster (EOC) mark */
212 Buffer
[8] = 0xff; /* End of root directory */
217 /* Write first sector of the FAT */
218 FileOffset
.QuadPart
= (SectorOffset
+ BootSector
->ReservedSectors
) * BootSector
->BytesPerSector
;
219 Status
= NtWriteFile(FileHandle
,
225 BootSector
->BytesPerSector
,
228 if (!NT_SUCCESS(Status
))
230 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
231 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
235 UpdateProgress (Context
, 1);
237 /* Zero the begin of the buffer */
238 memset(Buffer
, 0, 12);
240 /* Zero the rest of the FAT */
241 Sectors
= 64 * 1024 / BootSector
->BytesPerSector
;
242 for (i
= 1; i
< BootSector
->FATSectors32
; i
+= Sectors
)
244 /* Zero some sectors of the FAT */
245 FileOffset
.QuadPart
= (SectorOffset
+ BootSector
->ReservedSectors
+ i
) * BootSector
->BytesPerSector
;
247 if ((BootSector
->FATSectors32
- i
) <= Sectors
)
249 Sectors
= BootSector
->FATSectors32
- i
;
252 Status
= NtWriteFile(FileHandle
,
258 Sectors
* BootSector
->BytesPerSector
,
261 if (!NT_SUCCESS(Status
))
263 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
264 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
268 UpdateProgress (Context
, Sectors
);
271 /* Free the buffer */
272 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
279 Fat32WriteRootDirectory (IN HANDLE FileHandle
,
280 IN PFAT32_BOOT_SECTOR BootSector
,
281 IN OUT PFORMAT_CONTEXT Context
)
283 IO_STATUS_BLOCK IoStatusBlock
;
286 LARGE_INTEGER FileOffset
;
287 ULONGLONG FirstDataSector
;
288 ULONGLONG FirstRootDirSector
;
290 /* Allocate buffer for the cluster */
291 Buffer
= (PUCHAR
)RtlAllocateHeap(RtlGetProcessHeap(),
293 BootSector
->SectorsPerCluster
* BootSector
->BytesPerSector
);
295 return(STATUS_INSUFFICIENT_RESOURCES
);
297 /* Zero the buffer */
298 memset(Buffer
, 0, BootSector
->SectorsPerCluster
* BootSector
->BytesPerSector
);
300 DPRINT("BootSector->ReservedSectors = %lu\n", BootSector
->ReservedSectors
);
301 DPRINT("BootSector->FATSectors32 = %lu\n", BootSector
->FATSectors32
);
302 DPRINT("BootSector->RootCluster = %lu\n", BootSector
->RootCluster
);
303 DPRINT("BootSector->SectorsPerCluster = %lu\n", BootSector
->SectorsPerCluster
);
306 FirstDataSector
= BootSector
->ReservedSectors
+
307 (BootSector
->FATCount
* BootSector
->FATSectors32
) + 0 /* RootDirSectors */;
309 DPRINT("FirstDataSector = %lu\n", FirstDataSector
);
311 FirstRootDirSector
= ((BootSector
->RootCluster
- 2) * BootSector
->SectorsPerCluster
) + FirstDataSector
;
312 FileOffset
.QuadPart
= FirstRootDirSector
* BootSector
->BytesPerSector
;
314 DPRINT("FirstRootDirSector = %lu\n", FirstRootDirSector
);
315 DPRINT("FileOffset = %lu\n", FileOffset
.QuadPart
);
317 Status
= NtWriteFile(FileHandle
,
323 BootSector
->SectorsPerCluster
* BootSector
->BytesPerSector
,
326 if (!NT_SUCCESS(Status
))
328 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
329 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
333 UpdateProgress (Context
, (ULONG
)BootSector
->SectorsPerCluster
);
335 /* Free the buffer */
336 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
343 Fat32Format (HANDLE FileHandle
,
344 PPARTITION_INFORMATION PartitionInfo
,
345 PDISK_GEOMETRY DiskGeometry
,
346 PUNICODE_STRING Label
,
349 PFORMAT_CONTEXT Context
)
351 FAT32_BOOT_SECTOR BootSector
;
352 OEM_STRING VolumeLabel
;
353 ULONG RootDirSectors
;
358 /* Calculate cluster size */
359 if (ClusterSize
== 0)
361 if (PartitionInfo
->PartitionLength
.QuadPart
< 8LL * 1024LL * 1024LL * 1024LL)
363 /* Partition < 8GB ==> 4KB Cluster */
366 else if (PartitionInfo
->PartitionLength
.QuadPart
< 16LL * 1024LL * 1024LL * 1024LL)
368 /* Partition 8GB - 16GB ==> 8KB Cluster */
371 else if (PartitionInfo
->PartitionLength
.QuadPart
< 32LL * 1024LL * 1024LL * 1024LL)
373 /* Partition 16GB - 32GB ==> 16KB Cluster */
378 /* Partition >= 32GB ==> 32KB Cluster */
383 memset(&BootSector
, 0, sizeof(FAT32_BOOT_SECTOR
));
384 memcpy(&BootSector
.OEMName
[0], "MSWIN4.1", 8);
385 BootSector
.BytesPerSector
= DiskGeometry
->BytesPerSector
;
386 BootSector
.SectorsPerCluster
= ClusterSize
/ BootSector
.BytesPerSector
;
387 BootSector
.ReservedSectors
= 32;
388 BootSector
.FATCount
= 2;
389 BootSector
.RootEntries
= 0;
390 BootSector
.Sectors
= 0;
391 BootSector
.Media
= 0xf8;
392 BootSector
.FATSectors
= 0;
393 BootSector
.SectorsPerTrack
= DiskGeometry
->SectorsPerTrack
;
394 BootSector
.Heads
= DiskGeometry
->TracksPerCylinder
;
395 BootSector
.HiddenSectors
= PartitionInfo
->HiddenSectors
;
396 BootSector
.SectorsHuge
= PartitionInfo
->PartitionLength
.QuadPart
>>
397 GetShiftCount(BootSector
.BytesPerSector
); /* Use shifting to avoid 64-bit division */
398 BootSector
.FATSectors32
= 0; /* Set later */
399 BootSector
.ExtFlag
= 0; /* Mirror all FATs */
400 BootSector
.FSVersion
= 0x0000; /* 0:0 */
401 BootSector
.RootCluster
= 2;
402 BootSector
.FSInfoSector
= 1;
403 BootSector
.BootBackup
= 6;
404 BootSector
.Drive
= 0xff; /* No BIOS boot drive available */
405 BootSector
.ExtBootSignature
= 0x29;
406 BootSector
.VolumeID
= CalcVolumeSerialNumber ();
407 if ((Label
== NULL
) || (Label
->Buffer
== NULL
))
409 memcpy(&BootSector
.VolumeLabel
[0], "NO NAME ", 11);
413 RtlUnicodeStringToOemString(&VolumeLabel
, Label
, TRUE
);
414 memset(&BootSector
.VolumeLabel
[0], ' ', 11);
415 memcpy(&BootSector
.VolumeLabel
[0], VolumeLabel
.Buffer
,
416 VolumeLabel
.Length
< 11 ? VolumeLabel
.Length
: 11);
417 RtlFreeOemString(&VolumeLabel
);
419 memcpy(&BootSector
.SysType
[0], "FAT32 ", 8);
421 RootDirSectors
= ((BootSector
.RootEntries
* 32) +
422 (BootSector
.BytesPerSector
- 1)) / BootSector
.BytesPerSector
;
424 /* Calculate number of FAT sectors */
425 /* (BytesPerSector / 4) FAT entries (32bit) fit into one sector */
426 TmpVal1
= BootSector
.SectorsHuge
- BootSector
.ReservedSectors
;
427 TmpVal2
= ((BootSector
.BytesPerSector
/ 4) * BootSector
.SectorsPerCluster
) + BootSector
.FATCount
;
428 BootSector
.FATSectors32
= (TmpVal1
+ (TmpVal2
- 1)) / TmpVal2
;
429 DPRINT("FATSectors32 = %lu\n", BootSector
.FATSectors32
);
431 /* Init context data */
432 Context
->TotalSectorCount
=
433 2 + (BootSector
.FATSectors32
* BootSector
.FATCount
) + BootSector
.SectorsPerCluster
;
435 Status
= Fat32WriteBootSector (FileHandle
,
438 if (!NT_SUCCESS(Status
))
440 DPRINT("Fat32WriteBootSector() failed with status 0x%.08x\n", Status
);
444 Status
= Fat32WriteFsInfo (FileHandle
,
447 if (!NT_SUCCESS(Status
))
449 DPRINT("Fat32WriteFsInfo() failed with status 0x%.08x\n", Status
);
453 /* Write first FAT copy */
454 Status
= Fat32WriteFAT (FileHandle
,
458 if (!NT_SUCCESS(Status
))
460 DPRINT("Fat32WriteFAT() failed with status 0x%.08x\n", Status
);
464 /* Write second FAT copy */
465 Status
= Fat32WriteFAT (FileHandle
,
466 BootSector
.FATSectors32
,
469 if (!NT_SUCCESS(Status
))
471 DPRINT("Fat32WriteFAT() failed with status 0x%.08x.\n", Status
);
475 Status
= Fat32WriteRootDirectory (FileHandle
,
478 if (!NT_SUCCESS(Status
))
480 DPRINT("Fat32WriteRootDirectory() failed with status 0x%.08x\n", Status
);
485 /* FIXME: Fill remaining sectors */