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
13 #define NTOS_MODE_USER
15 #include <ddk/ntddscsi.h>
21 GetShiftCount(ULONG Value)
34 CalcVolumeSerialNumber(VOID)
36 LARGE_INTEGER SystemTime;
37 TIME_FIELDS TimeFields;
41 NtQuerySystemTime (&SystemTime);
42 RtlTimeToTimeFields (&SystemTime, &TimeFields);
44 Buffer = (PUCHAR)&Serial;
45 Buffer[0] = (UCHAR)(TimeFields.Year & 0xFF) + (UCHAR)(TimeFields.Hour & 0xFF);
46 Buffer[1] = (UCHAR)(TimeFields.Year >> 8) + (UCHAR)(TimeFields.Minute & 0xFF);
47 Buffer[2] = (UCHAR)(TimeFields.Month & 0xFF) + (UCHAR)(TimeFields.Second & 0xFF);
48 Buffer[3] = (UCHAR)(TimeFields.Day & 0xFF) + (UCHAR)(TimeFields.Milliseconds & 0xFF);
55 Fat32WriteBootSector(IN HANDLE FileHandle,
56 IN PFAT32_BOOT_SECTOR BootSector)
58 IO_STATUS_BLOCK IoStatusBlock;
61 LARGE_INTEGER FileOffset;
63 /* Allocate buffer for new bootsector */
64 NewBootSector = (PUCHAR)RtlAllocateHeap(RtlGetProcessHeap(),
67 if (NewBootSector == NULL)
68 return(STATUS_INSUFFICIENT_RESOURCES);
70 /* Zero the new bootsector */
71 memset(NewBootSector, 0, SECTORSIZE);
73 /* Copy FAT32 BPB to new bootsector */
74 memcpy((NewBootSector + 3),
75 &BootSector->OEMName[0],
76 87); /* FAT32 BPB length (up to (not including) Res2) */
79 FileOffset.QuadPart = 0ULL;
80 Status = NtWriteFile(FileHandle,
89 if (!NT_SUCCESS(Status))
91 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
92 RtlFreeHeap(RtlGetProcessHeap(), 0, NewBootSector);
96 /* Write backup boot sector */
97 if (BootSector->BootBackup != 0x0000)
99 FileOffset.QuadPart = (ULONGLONG)((ULONG) BootSector->BootBackup * SECTORSIZE);
100 Status = NtWriteFile(FileHandle,
109 if (!NT_SUCCESS(Status))
111 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
112 RtlFreeHeap(RtlGetProcessHeap(), 0, NewBootSector);
117 /* Free the new boot sector */
118 RtlFreeHeap(RtlGetProcessHeap(), 0, NewBootSector);
125 Fat32WriteFsInfo(IN HANDLE FileHandle,
126 IN PFAT32_BOOT_SECTOR BootSector)
128 IO_STATUS_BLOCK IoStatusBlock;
130 PFAT32_FSINFO FsInfo;
131 LARGE_INTEGER FileOffset;
133 /* Allocate buffer for new sector */
134 FsInfo = (PFAT32_FSINFO)RtlAllocateHeap(RtlGetProcessHeap(),
136 BootSector->BytesPerSector);
138 return(STATUS_INSUFFICIENT_RESOURCES);
140 /* Zero the new sector */
141 memset(FsInfo, 0, BootSector->BytesPerSector);
143 FsInfo->LeadSig = 0x41615252;
144 FsInfo->StrucSig = 0x61417272;
145 FsInfo->FreeCount = 0xffffffff;
146 FsInfo->NextFree = 0xffffffff;
147 FsInfo->TrailSig = 0xaa550000;
150 FileOffset.QuadPart = BootSector->FSInfoSector * BootSector->BytesPerSector;
151 Status = NtWriteFile(FileHandle,
157 BootSector->BytesPerSector,
160 if (!NT_SUCCESS(Status))
162 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
163 RtlFreeHeap(RtlGetProcessHeap(), 0, FsInfo);
167 /* Free the new sector buffer */
168 RtlFreeHeap(RtlGetProcessHeap(), 0, FsInfo);
175 Fat32WriteFAT(IN HANDLE FileHandle,
177 IN PFAT32_BOOT_SECTOR BootSector)
179 IO_STATUS_BLOCK IoStatusBlock;
182 LARGE_INTEGER FileOffset;
187 /* Allocate buffer */
188 Buffer = (PUCHAR)RtlAllocateHeap(RtlGetProcessHeap(),
192 return(STATUS_INSUFFICIENT_RESOURCES);
194 /* Zero the buffer */
195 memset(Buffer, 0, 64 * 1024);
198 Buffer[0] = 0xf8; /* Media type */
203 Buffer[4] = 0xff; /* Clean shutdown, no disk read/write errors, end-of-cluster (EOC) mark */
208 Buffer[8] = 0xff; /* End of root directory */
213 /* Write first sector of the FAT */
214 FileOffset.QuadPart = (SectorOffset + BootSector->ReservedSectors) * BootSector->BytesPerSector;
215 Status = NtWriteFile(FileHandle,
221 BootSector->BytesPerSector,
224 if (!NT_SUCCESS(Status))
226 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
227 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
231 /* Zero the begin of the buffer */
232 memset(Buffer, 0, 12);
234 /* Zero the rest of the FAT */
235 Sectors = 64 * 1024 / BootSector->BytesPerSector;
236 for (i = 1; i < BootSector->FATSectors32; i += Sectors)
238 /* Zero some sectors of the FAT */
239 FileOffset.QuadPart = (SectorOffset + BootSector->ReservedSectors + i) * BootSector->BytesPerSector;
240 Size = BootSector->FATSectors32 - i;
245 Size *= BootSector->BytesPerSector;
246 Status = NtWriteFile(FileHandle,
255 if (!NT_SUCCESS(Status))
257 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
258 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
263 /* Free the buffer */
264 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
271 Fat32WriteRootDirectory(IN HANDLE FileHandle,
272 IN PFAT32_BOOT_SECTOR BootSector)
274 IO_STATUS_BLOCK IoStatusBlock;
277 LARGE_INTEGER FileOffset;
278 ULONGLONG FirstDataSector;
279 ULONGLONG FirstRootDirSector;
281 /* Allocate buffer for the cluster */
282 Buffer = (PUCHAR)RtlAllocateHeap(RtlGetProcessHeap(),
284 BootSector->SectorsPerCluster * BootSector->BytesPerSector);
286 return(STATUS_INSUFFICIENT_RESOURCES);
288 /* Zero the buffer */
289 memset(Buffer, 0, BootSector->SectorsPerCluster * BootSector->BytesPerSector);
291 DPRINT("BootSector->ReservedSectors = %lu\n", BootSector->ReservedSectors);
292 DPRINT("BootSector->FATSectors32 = %lu\n", BootSector->FATSectors32);
293 DPRINT("BootSector->RootCluster = %lu\n", BootSector->RootCluster);
294 DPRINT("BootSector->SectorsPerCluster = %lu\n", BootSector->SectorsPerCluster);
297 FirstDataSector = BootSector->ReservedSectors +
298 (BootSector->FATCount * BootSector->FATSectors32) + 0 /* RootDirSectors */;
300 DPRINT("FirstDataSector = %lu\n", FirstDataSector);
302 FirstRootDirSector = ((BootSector->RootCluster - 2) * BootSector->SectorsPerCluster) + FirstDataSector;
303 FileOffset.QuadPart = FirstRootDirSector * BootSector->BytesPerSector;
305 DPRINT("FirstRootDirSector = %lu\n", FirstRootDirSector);
306 DPRINT("FileOffset = %lu\n", FileOffset.QuadPart);
308 Status = NtWriteFile(FileHandle,
314 BootSector->SectorsPerCluster * BootSector->BytesPerSector,
317 if (!NT_SUCCESS(Status))
319 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
320 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
324 /* Free the buffer */
325 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
332 Fat32Format (HANDLE FileHandle,
333 PPARTITION_INFORMATION PartitionInfo,
334 PDISK_GEOMETRY DiskGeometry,
335 PUNICODE_STRING Label,
338 PFMIFSCALLBACK Callback)
340 FAT32_BOOT_SECTOR BootSector;
341 OEM_STRING VolumeLabel;
342 ULONG RootDirSectors;
347 /* Calculate cluster size */
348 if (ClusterSize == 0)
350 if (PartitionInfo->PartitionLength.QuadPart < 8ULL * 1024ULL * 1024ULL * 1024ULL)
352 /* Partition < 8GB ==> 4KB Cluster */
355 else if (PartitionInfo->PartitionLength.QuadPart < 16ULL * 1024ULL * 1024ULL * 1024ULL)
357 /* Partition 8GB - 16GB ==> 8KB Cluster */
360 else if (PartitionInfo->PartitionLength.QuadPart < 32ULL * 1024ULL * 1024ULL * 1024ULL)
362 /* Partition 16GB - 32GB ==> 16KB Cluster */
367 /* Partition >= 32GB ==> 32KB Cluster */
372 memset(&BootSector, 0, sizeof(FAT32_BOOT_SECTOR));
373 memcpy(&BootSector.OEMName[0], "MSWIN4.1", 8);
374 BootSector.BytesPerSector = DiskGeometry->BytesPerSector;
375 BootSector.SectorsPerCluster = ClusterSize / BootSector.BytesPerSector;
376 BootSector.ReservedSectors = 32;
377 BootSector.FATCount = 2;
378 BootSector.RootEntries = 0;
379 BootSector.Sectors = 0;
380 BootSector.Media = 0xf8;
381 BootSector.FATSectors = 0;
382 BootSector.SectorsPerTrack = DiskGeometry->SectorsPerTrack;
383 BootSector.Heads = DiskGeometry->TracksPerCylinder;
384 BootSector.HiddenSectors = PartitionInfo->HiddenSectors;
385 BootSector.SectorsHuge = PartitionInfo->PartitionLength.QuadPart >>
386 GetShiftCount(BootSector.BytesPerSector); /* Use shifting to avoid 64-bit division */
387 BootSector.FATSectors32 = 0; /* Set later */
388 BootSector.ExtFlag = 0; /* Mirror all FATs */
389 BootSector.FSVersion = 0x0000; /* 0:0 */
390 BootSector.RootCluster = 2;
391 BootSector.FSInfoSector = 1;
392 BootSector.BootBackup = 6;
393 BootSector.Drive = 0xff; /* No BIOS boot drive available */
394 BootSector.ExtBootSignature = 0x29;
395 BootSector.VolumeID = CalcVolumeSerialNumber ();
396 if ((Label == NULL) || (Label->Buffer == NULL))
398 memcpy(&BootSector.VolumeLabel[0], "NO NAME ", 11);
402 RtlUnicodeStringToOemString(&VolumeLabel, Label, TRUE);
403 memset(&BootSector.VolumeLabel[0], ' ', 11);
404 memcpy(&BootSector.VolumeLabel[0], VolumeLabel.Buffer,
405 VolumeLabel.Length < 11 ? VolumeLabel.Length : 11);
406 RtlFreeOemString(&VolumeLabel);
408 memcpy(&BootSector.SysType[0], "FAT32 ", 8);
410 RootDirSectors = ((BootSector.RootEntries * 32) +
411 (BootSector.BytesPerSector - 1)) / BootSector.BytesPerSector;
413 /* Calculate number of FAT sectors */
414 /* (BytesPerSector / 4) FAT entries (32bit) fit into one sector */
415 TmpVal1 = BootSector.SectorsHuge - BootSector.ReservedSectors;
416 TmpVal2 = ((BootSector.BytesPerSector / 4) * BootSector.SectorsPerCluster) + BootSector.FATCount;
417 BootSector.FATSectors32 = (TmpVal1 + (TmpVal2 - 1)) / TmpVal2;
418 DPRINT("FATSectors32 = %lu\n", BootSector.FATSectors32);
420 Status = Fat32WriteBootSector(FileHandle,
422 if (!NT_SUCCESS(Status))
424 DPRINT("Fat32WriteBootSector() failed with status 0x%.08x\n", Status);
428 Status = Fat32WriteFsInfo(FileHandle,
430 if (!NT_SUCCESS(Status))
432 DPRINT("Fat32WriteFsInfo() failed with status 0x%.08x\n", Status);
436 /* Write first FAT copy */
437 Status = Fat32WriteFAT(FileHandle,
440 if (!NT_SUCCESS(Status))
442 DPRINT("Fat32WriteFAT() failed with status 0x%.08x\n", Status);
446 /* Write second FAT copy */
447 Status = Fat32WriteFAT(FileHandle,
448 BootSector.FATSectors32,
450 if (!NT_SUCCESS(Status))
452 DPRINT("Fat32WriteFAT() failed with status 0x%.08x.\n", Status);
456 Status = Fat32WriteRootDirectory(FileHandle,
458 if (!NT_SUCCESS(Status))
460 DPRINT("Fat32WriteRootDirectory() failed with status 0x%.08x\n", Status);