2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS VFAT filesystem library
5 * PURPOSE: Fat12 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 Fat12WriteBootSector(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 Fat12WriteFAT(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);
126 /* FAT cluster 0 & 1*/
127 Buffer[0] = 0xf8; /* Media type */
131 /* Write first sector of the FAT */
132 FileOffset.QuadPart = (SectorOffset + BootSector->ReservedSectors) * BootSector->BytesPerSector;
133 Status = NtWriteFile(FileHandle,
139 BootSector->BytesPerSector,
142 if (!NT_SUCCESS(Status))
144 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
145 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
149 /* Zero the begin of the buffer */
150 memset(Buffer, 0, 3);
152 /* Zero the rest of the FAT */
153 Sectors = 32 * 1024 / BootSector->BytesPerSector;
154 for (i = 1; i < (ULONG)BootSector->FATSectors; i += Sectors)
156 /* Zero some sectors of the FAT */
157 FileOffset.QuadPart = (SectorOffset + BootSector->ReservedSectors + i) * BootSector->BytesPerSector;
158 Size = (ULONG)BootSector->FATSectors - i;
163 Size *= BootSector->BytesPerSector;
164 Status = NtWriteFile(FileHandle,
173 if (!NT_SUCCESS(Status))
175 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
176 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
181 /* Free the buffer */
182 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
189 Fat12WriteRootDirectory(IN HANDLE FileHandle,
190 IN PFAT16_BOOT_SECTOR BootSector)
192 IO_STATUS_BLOCK IoStatusBlock;
195 LARGE_INTEGER FileOffset;
196 ULONG FirstRootDirSector;
197 ULONG RootDirSectors;
202 DPRINT("BootSector->ReservedSectors = %hu\n", BootSector->ReservedSectors);
203 DPRINT("BootSector->FATSectors = %hu\n", BootSector->FATSectors);
204 DPRINT("BootSector->SectorsPerCluster = %u\n", BootSector->SectorsPerCluster);
207 RootDirSectors = ((BootSector->RootEntries * 32) +
208 (BootSector->BytesPerSector - 1)) / BootSector->BytesPerSector;
210 BootSector->ReservedSectors + (BootSector->FATCount * BootSector->FATSectors);
212 DPRINT("RootDirSectors = %lu\n", RootDirSectors);
213 DPRINT("FirstRootDirSector = %lu\n", FirstRootDirSector);
215 /* Allocate buffer for the cluster */
216 Buffer = (PUCHAR)RtlAllocateHeap(RtlGetProcessHeap(),
220 return(STATUS_INSUFFICIENT_RESOURCES);
222 /* Zero the buffer */
223 memset(Buffer, 0, 32 * 1024);
225 Sectors = 32 * 1024 / BootSector->BytesPerSector;
226 for (i = 1; i < RootDirSectors; i += Sectors)
228 /* Zero some sectors of the root directory */
229 FileOffset.QuadPart = (FirstRootDirSector + i) * BootSector->BytesPerSector;
230 Size = RootDirSectors - i;
235 Size *= BootSector->BytesPerSector;
237 Status = NtWriteFile(FileHandle,
246 if (!NT_SUCCESS(Status))
248 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
249 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
254 /* Free the buffer */
255 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
262 Fat12Format (HANDLE FileHandle,
263 PPARTITION_INFORMATION PartitionInfo,
264 PDISK_GEOMETRY DiskGeometry,
265 PUNICODE_STRING Label,
268 PFMIFSCALLBACK Callback)
270 FAT16_BOOT_SECTOR BootSector;
271 OEM_STRING VolumeLabel;
273 ULONG RootDirSectors;
279 /* Calculate cluster size */
280 if (ClusterSize == 0)
282 /* 4KB Cluster (Harddisk only) */
286 SectorCount = PartitionInfo->PartitionLength.QuadPart >>
287 GetShiftCount(DiskGeometry->BytesPerSector); /* Use shifting to avoid 64-bit division */
289 DPRINT("SectorCount = %lu\n", SectorCount);
291 memset(&BootSector, 0, sizeof(FAT16_BOOT_SECTOR));
292 memcpy(&BootSector.OEMName[0], "MSWIN4.1", 8);
293 BootSector.BytesPerSector = DiskGeometry->BytesPerSector;
294 BootSector.SectorsPerCluster = ClusterSize / BootSector.BytesPerSector;
295 BootSector.ReservedSectors = 1;
296 BootSector.FATCount = 2;
297 BootSector.RootEntries = 512;
298 BootSector.Sectors = (SectorCount < 0x10000) ? (unsigned short)SectorCount : 0;
299 BootSector.Media = 0xf8;
300 BootSector.FATSectors = 0; /* Set later. See below. */
301 BootSector.SectorsPerTrack = DiskGeometry->SectorsPerTrack;
302 BootSector.Heads = DiskGeometry->TracksPerCylinder;
303 BootSector.HiddenSectors = PartitionInfo->HiddenSectors;
304 BootSector.SectorsHuge = (SectorCount >= 0x10000) ? (unsigned long)SectorCount : 0;
305 BootSector.Drive = 0xff; /* No BIOS boot drive available */
306 BootSector.ExtBootSignature = 0x29;
307 BootSector.VolumeID = CalcVolumeSerialNumber();
308 if ((Label == NULL) || (Label->Buffer == NULL))
310 memcpy(&BootSector.VolumeLabel[0], "NO NAME ", 11);
314 RtlUnicodeStringToOemString(&VolumeLabel, Label, TRUE);
315 memset(&BootSector.VolumeLabel[0], ' ', 11);
316 memcpy(&BootSector.VolumeLabel[0], VolumeLabel.Buffer,
317 VolumeLabel.Length < 11 ? VolumeLabel.Length : 11);
318 RtlFreeOemString(&VolumeLabel);
320 memcpy(&BootSector.SysType[0], "FAT12 ", 8);
322 RootDirSectors = ((BootSector.RootEntries * 32) +
323 (BootSector.BytesPerSector - 1)) / BootSector.BytesPerSector;
325 /* Calculate number of FAT sectors */
326 /* ((BootSector.BytesPerSector * 2) / 3) FAT entries (12bit) fit into one sector */
327 TmpVal1 = SectorCount - (BootSector.ReservedSectors + RootDirSectors);
328 TmpVal2 = (((BootSector.BytesPerSector * 2) / 3) * BootSector.SectorsPerCluster) + BootSector.FATCount;
329 TmpVal3 = (TmpVal1 + (TmpVal2 - 1)) / TmpVal2;
330 BootSector.FATSectors = (unsigned short)(TmpVal3 & 0xffff);
332 DPRINT("BootSector.FATSectors = %hx\n", BootSector.FATSectors);
334 Status = Fat12WriteBootSector(FileHandle,
336 if (!NT_SUCCESS(Status))
338 DPRINT("Fat12WriteBootSector() failed with status 0x%.08x\n", Status);
342 /* Write first FAT copy */
343 Status = Fat12WriteFAT(FileHandle,
346 if (!NT_SUCCESS(Status))
348 DPRINT("Fat12WriteFAT() failed with status 0x%.08x\n", Status);
352 /* Write second FAT copy */
353 Status = Fat12WriteFAT(FileHandle,
354 (ULONG)BootSector.FATSectors,
356 if (!NT_SUCCESS(Status))
358 DPRINT("Fat12WriteFAT() failed with status 0x%.08x.\n", Status);
362 Status = Fat12WriteRootDirectory(FileHandle,
364 if (!NT_SUCCESS(Status))
366 DPRINT("Fat12WriteRootDirectory() failed with status 0x%.08x\n", Status);