2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS VFAT filesystem library
5 * PURPOSE: Fat16 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 Fat16WriteBootSector(IN HANDLE FileHandle,
56 IN PFAT16_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 FAT16 BPB to new bootsector */
74 memcpy((NewBootSector + 3),
75 &BootSector->OEMName[0],
76 59); /* FAT16 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 /* Free the new boot sector */
97 RtlFreeHeap(RtlGetProcessHeap(), 0, NewBootSector);
104 Fat16WriteFAT(IN HANDLE FileHandle,
106 IN PFAT16_BOOT_SECTOR BootSector)
108 IO_STATUS_BLOCK IoStatusBlock;
111 LARGE_INTEGER FileOffset;
116 /* Allocate buffer */
117 Buffer = (PUCHAR)RtlAllocateHeap(RtlGetProcessHeap(),
121 return(STATUS_INSUFFICIENT_RESOURCES);
123 /* Zero the buffer */
124 memset(Buffer, 0, 32 * 1024);
127 Buffer[0] = 0xf8; /* Media type */
131 Buffer[2] = 0xff; /* Clean shutdown, no disk read/write errors, end-of-cluster (EOC) mark */
134 /* Write first sector of the FAT */
135 FileOffset.QuadPart = (SectorOffset + BootSector->ReservedSectors) * BootSector->BytesPerSector;
136 Status = NtWriteFile(FileHandle,
142 BootSector->BytesPerSector,
145 if (!NT_SUCCESS(Status))
147 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
148 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
152 /* Zero the begin of the buffer */
153 memset(Buffer, 0, 4);
155 /* Zero the rest of the FAT */
156 Sectors = 32 * 1024 / BootSector->BytesPerSector;
157 for (i = 1; i < (ULONG)BootSector->FATSectors; i += Sectors)
159 /* Zero some sectors of the FAT */
160 FileOffset.QuadPart = (SectorOffset + BootSector->ReservedSectors + i) * BootSector->BytesPerSector;
161 Size = (ULONG)BootSector->FATSectors - i;
166 Size *= BootSector->BytesPerSector;
167 Status = NtWriteFile(FileHandle,
176 if (!NT_SUCCESS(Status))
178 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
179 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
184 /* Free the buffer */
185 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
192 Fat16WriteRootDirectory(IN HANDLE FileHandle,
193 IN PFAT16_BOOT_SECTOR BootSector)
195 IO_STATUS_BLOCK IoStatusBlock;
198 LARGE_INTEGER FileOffset;
199 ULONG FirstRootDirSector;
200 ULONG RootDirSectors;
205 DPRINT("BootSector->ReservedSectors = %hu\n", BootSector->ReservedSectors);
206 DPRINT("BootSector->FATSectors = %hu\n", BootSector->FATSectors);
207 DPRINT("BootSector->SectorsPerCluster = %u\n", BootSector->SectorsPerCluster);
210 RootDirSectors = ((BootSector->RootEntries * 32) +
211 (BootSector->BytesPerSector - 1)) / BootSector->BytesPerSector;
213 BootSector->ReservedSectors + (BootSector->FATCount * BootSector->FATSectors);
215 DPRINT("RootDirSectors = %lu\n", RootDirSectors);
216 DPRINT("FirstRootDirSector = %lu\n", FirstRootDirSector);
218 /* Allocate buffer for the cluster */
219 Buffer = (PUCHAR)RtlAllocateHeap(RtlGetProcessHeap(),
223 return(STATUS_INSUFFICIENT_RESOURCES);
225 /* Zero the buffer */
226 memset(Buffer, 0, 32 * 1024);
228 Sectors = 32 * 1024 / BootSector->BytesPerSector;
229 for (i = 1; i < RootDirSectors; i += Sectors)
231 /* Zero some sectors of the root directory */
232 FileOffset.QuadPart = (FirstRootDirSector + i) * BootSector->BytesPerSector;
233 Size = RootDirSectors - i;
238 Size *= BootSector->BytesPerSector;
240 Status = NtWriteFile(FileHandle,
249 if (!NT_SUCCESS(Status))
251 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
252 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
257 /* Free the buffer */
258 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
265 Fat16Format (HANDLE FileHandle,
266 PPARTITION_INFORMATION PartitionInfo,
267 PDISK_GEOMETRY DiskGeometry,
268 PUNICODE_STRING Label,
271 PFMIFSCALLBACK Callback)
273 FAT16_BOOT_SECTOR BootSector;
274 OEM_STRING VolumeLabel;
276 ULONG RootDirSectors;
282 /* Calculate cluster size */
283 if (ClusterSize == 0)
285 if (PartitionInfo->PartitionLength.QuadPart < 16ULL * 1024ULL * 1024ULL)
287 /* Partition < 16MB ==> 1KB Cluster */
290 else if (PartitionInfo->PartitionLength.QuadPart < 128ULL * 1024ULL * 1024ULL)
292 /* Partition < 128MB ==> 2KB Cluster */
295 else if (PartitionInfo->PartitionLength.QuadPart < 256ULL * 1024ULL * 1024ULL)
297 /* Partition < 256MB ==> 4KB Cluster */
302 /* Partition >= 256MB (< 512MB) ==> 8KB Cluster */
307 SectorCount = PartitionInfo->PartitionLength.QuadPart >>
308 GetShiftCount(DiskGeometry->BytesPerSector); /* Use shifting to avoid 64-bit division */
310 memset(&BootSector, 0, sizeof(FAT16_BOOT_SECTOR));
311 memcpy(&BootSector.OEMName[0], "MSWIN4.1", 8);
312 BootSector.BytesPerSector = DiskGeometry->BytesPerSector;
313 BootSector.SectorsPerCluster = ClusterSize / BootSector.BytesPerSector;
314 BootSector.ReservedSectors = 1;
315 BootSector.FATCount = 2;
316 BootSector.RootEntries = 512;
317 BootSector.Sectors = (SectorCount < 0x10000) ? (unsigned short)SectorCount : 0;
318 BootSector.Media = 0xf8;
319 BootSector.FATSectors = 0; /* Set later. See below. */
320 BootSector.SectorsPerTrack = DiskGeometry->SectorsPerTrack;
321 BootSector.Heads = DiskGeometry->TracksPerCylinder;
322 BootSector.HiddenSectors = PartitionInfo->HiddenSectors;
323 BootSector.SectorsHuge = (SectorCount >= 0x10000) ? (unsigned long)SectorCount : 0;
324 BootSector.Drive = 0xff; /* No BIOS boot drive available */
325 BootSector.ExtBootSignature = 0x29;
326 BootSector.VolumeID = CalcVolumeSerialNumber();
327 if ((Label == NULL) || (Label->Buffer == NULL))
329 memcpy(&BootSector.VolumeLabel[0], "NO NAME ", 11);
333 RtlUnicodeStringToOemString(&VolumeLabel, Label, TRUE);
334 memset(&BootSector.VolumeLabel[0], ' ', 11);
335 memcpy(&BootSector.VolumeLabel[0], VolumeLabel.Buffer,
336 VolumeLabel.Length < 11 ? VolumeLabel.Length : 11);
337 RtlFreeOemString(&VolumeLabel);
339 memcpy(&BootSector.SysType[0], "FAT16 ", 8);
341 DPRINT("BootSector.SectorsHuge = %lx\n", BootSector.SectorsHuge);
343 RootDirSectors = ((BootSector.RootEntries * 32) +
344 (BootSector.BytesPerSector - 1)) / BootSector.BytesPerSector;
346 /* Calculate number of FAT sectors */
347 /* (BootSector.BytesPerSector / 2) FAT entries (16bit) fit into one sector */
348 TmpVal1 = SectorCount - (BootSector.ReservedSectors + RootDirSectors);
349 TmpVal2 = ((BootSector.BytesPerSector / 2) * BootSector.SectorsPerCluster) + BootSector.FATCount;
350 TmpVal3 = (TmpVal1 + (TmpVal2 - 1)) / TmpVal2;
351 BootSector.FATSectors = (unsigned short)(TmpVal3 & 0xffff);
352 DPRINT("BootSector.FATSectors = %hu\n", BootSector.FATSectors);
354 Status = Fat16WriteBootSector(FileHandle,
356 if (!NT_SUCCESS(Status))
358 DPRINT("Fat16WriteBootSector() failed with status 0x%.08x\n", Status);
362 /* Write first FAT copy */
363 Status = Fat16WriteFAT(FileHandle,
366 if (!NT_SUCCESS(Status))
368 DPRINT("Fat16WriteFAT() failed with status 0x%.08x\n", Status);
372 /* Write second FAT copy */
373 Status = Fat16WriteFAT(FileHandle,
374 (ULONG)BootSector.FATSectors,
376 if (!NT_SUCCESS(Status))
378 DPRINT("Fat16WriteFAT() failed with status 0x%.08x.\n", Status);
382 Status = Fat16WriteRootDirectory(FileHandle,
384 if (!NT_SUCCESS(Status))
386 DPRINT("Fat16WriteRootDirectory() failed with status 0x%.08x\n", Status);