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)
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 Fat16WriteBootSector(IN HANDLE FileHandle
,
54 IN PFAT16_BOOT_SECTOR BootSector
,
55 IN OUT PFORMAT_CONTEXT Context
)
57 IO_STATUS_BLOCK IoStatusBlock
;
60 LARGE_INTEGER FileOffset
;
62 /* Allocate buffer for new bootsector */
63 NewBootSector
= (PUCHAR
)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 FAT16 BPB to new bootsector */
73 memcpy((NewBootSector
+ 3),
74 &BootSector
->OEMName
[0],
75 59); /* FAT16 BPB length (up to (not including) Res2) */
78 FileOffset
.QuadPart
= 0ULL;
79 Status
= NtWriteFile(FileHandle
,
85 BootSector
->BytesPerSector
,
88 if (!NT_SUCCESS(Status
))
90 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
91 RtlFreeHeap(RtlGetProcessHeap(), 0, NewBootSector
);
95 UpdateProgress(Context
, 1);
97 /* Free the new boot sector */
98 RtlFreeHeap(RtlGetProcessHeap(), 0, NewBootSector
);
105 Fat16WriteFAT(IN HANDLE FileHandle
,
106 IN ULONG SectorOffset
,
107 IN PFAT16_BOOT_SECTOR BootSector
,
108 IN OUT PFORMAT_CONTEXT Context
)
110 IO_STATUS_BLOCK IoStatusBlock
;
113 LARGE_INTEGER FileOffset
;
117 /* Allocate buffer */
118 Buffer
= (PUCHAR
)RtlAllocateHeap(RtlGetProcessHeap(),
122 return STATUS_INSUFFICIENT_RESOURCES
;
124 /* Zero the buffer */
125 memset(Buffer
, 0, 32 * 1024);
128 Buffer
[0] = 0xf8; /* Media type */
132 Buffer
[2] = 0xff; /* Clean shutdown, no disk read/write errors, end-of-cluster (EOC) mark */
135 /* Write first sector of the FAT */
136 FileOffset
.QuadPart
= (SectorOffset
+ BootSector
->ReservedSectors
) * BootSector
->BytesPerSector
;
137 Status
= NtWriteFile(FileHandle
,
143 BootSector
->BytesPerSector
,
146 if (!NT_SUCCESS(Status
))
148 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
149 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
153 UpdateProgress(Context
, 1);
155 /* Zero the begin of the buffer */
156 memset(Buffer
, 0, 4);
158 /* Zero the rest of the FAT */
159 Sectors
= 32 * 1024 / BootSector
->BytesPerSector
;
160 for (i
= 1; i
< (ULONG
)BootSector
->FATSectors
; i
+= Sectors
)
162 /* Zero some sectors of the FAT */
163 FileOffset
.QuadPart
= (SectorOffset
+ BootSector
->ReservedSectors
+ i
) * BootSector
->BytesPerSector
;
165 if (((ULONG
)BootSector
->FATSectors
- i
) <= Sectors
)
167 Sectors
= (ULONG
)BootSector
->FATSectors
- i
;
170 Status
= NtWriteFile(FileHandle
,
176 Sectors
* BootSector
->BytesPerSector
,
179 if (!NT_SUCCESS(Status
))
181 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
182 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
186 UpdateProgress(Context
, Sectors
);
189 /* Free the buffer */
190 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
197 Fat16WriteRootDirectory(IN HANDLE FileHandle
,
198 IN PFAT16_BOOT_SECTOR BootSector
,
199 IN OUT PFORMAT_CONTEXT Context
)
201 IO_STATUS_BLOCK IoStatusBlock
;
202 NTSTATUS Status
= STATUS_SUCCESS
;
204 LARGE_INTEGER FileOffset
;
205 ULONG FirstRootDirSector
;
206 ULONG RootDirSectors
;
210 DPRINT("BootSector->ReservedSectors = %hu\n", BootSector
->ReservedSectors
);
211 DPRINT("BootSector->FATSectors = %hu\n", BootSector
->FATSectors
);
212 DPRINT("BootSector->SectorsPerCluster = %u\n", BootSector
->SectorsPerCluster
);
215 RootDirSectors
= ((BootSector
->RootEntries
* 32) +
216 (BootSector
->BytesPerSector
- 1)) / BootSector
->BytesPerSector
;
218 BootSector
->ReservedSectors
+ (BootSector
->FATCount
* BootSector
->FATSectors
);
220 DPRINT("RootDirSectors = %lu\n", RootDirSectors
);
221 DPRINT("FirstRootDirSector = %lu\n", FirstRootDirSector
);
223 /* Allocate buffer for the cluster */
224 Buffer
= (PUCHAR
)RtlAllocateHeap(RtlGetProcessHeap(),
228 return STATUS_INSUFFICIENT_RESOURCES
;
230 /* Zero the buffer */
231 memset(Buffer
, 0, 32 * 1024);
233 Sectors
= 32 * 1024 / BootSector
->BytesPerSector
;
234 for (i
= 0; i
< RootDirSectors
; i
+= Sectors
)
236 /* Zero some sectors of the root directory */
237 FileOffset
.QuadPart
= (FirstRootDirSector
+ i
) * BootSector
->BytesPerSector
;
239 if ((RootDirSectors
- i
) <= Sectors
)
241 Sectors
= RootDirSectors
- i
;
244 Status
= NtWriteFile(FileHandle
,
250 Sectors
* BootSector
->BytesPerSector
,
253 if (!NT_SUCCESS(Status
))
255 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
256 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
260 UpdateProgress(Context
, Sectors
);
263 /* Free the buffer */
264 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
271 Fat16Format(IN HANDLE FileHandle
,
272 IN PPARTITION_INFORMATION PartitionInfo
,
273 IN PDISK_GEOMETRY DiskGeometry
,
274 IN PUNICODE_STRING Label
,
275 IN BOOLEAN QuickFormat
,
276 IN ULONG ClusterSize
,
277 IN OUT PFORMAT_CONTEXT Context
)
279 FAT16_BOOT_SECTOR BootSector
;
280 OEM_STRING VolumeLabel
;
282 ULONG RootDirSectors
;
288 /* Calculate cluster size */
289 if (ClusterSize
== 0)
291 if (PartitionInfo
->PartitionLength
.QuadPart
< 16LL * 1024LL * 1024LL)
293 /* Partition < 16MB ==> 1KB Cluster */
296 else if (PartitionInfo
->PartitionLength
.QuadPart
< 128LL * 1024LL * 1024LL)
298 /* Partition < 128MB ==> 2KB Cluster */
301 else if (PartitionInfo
->PartitionLength
.QuadPart
< 256LL * 1024LL * 1024LL)
303 /* Partition < 256MB ==> 4KB Cluster */
308 /* Partition >= 256MB (< 512MB) ==> 8KB Cluster */
313 SectorCount
= PartitionInfo
->PartitionLength
.QuadPart
>>
314 GetShiftCount(DiskGeometry
->BytesPerSector
); /* Use shifting to avoid 64-bit division */
316 memset(&BootSector
, 0, sizeof(FAT16_BOOT_SECTOR
));
317 memcpy(&BootSector
.OEMName
[0], "MSWIN4.1", 8);
318 BootSector
.BytesPerSector
= DiskGeometry
->BytesPerSector
;
319 BootSector
.SectorsPerCluster
= ClusterSize
/ BootSector
.BytesPerSector
;
320 BootSector
.ReservedSectors
= 1;
321 BootSector
.FATCount
= 2;
322 BootSector
.RootEntries
= 512;
323 BootSector
.Sectors
= (SectorCount
< 0x10000) ? (unsigned short)SectorCount
: 0;
324 BootSector
.Media
= 0xf8;
325 BootSector
.FATSectors
= 0; /* Set later. See below. */
326 BootSector
.SectorsPerTrack
= DiskGeometry
->SectorsPerTrack
;
327 BootSector
.Heads
= DiskGeometry
->TracksPerCylinder
;
328 BootSector
.HiddenSectors
= PartitionInfo
->HiddenSectors
;
329 BootSector
.SectorsHuge
= (SectorCount
>= 0x10000) ? (unsigned long)SectorCount
: 0;
330 BootSector
.Drive
= 0xff; /* No BIOS boot drive available */
331 BootSector
.ExtBootSignature
= 0x29;
332 BootSector
.VolumeID
= CalcVolumeSerialNumber();
333 if ((Label
== NULL
) || (Label
->Buffer
== NULL
))
335 memcpy(&BootSector
.VolumeLabel
[0], "NO NAME ", 11);
339 RtlUnicodeStringToOemString(&VolumeLabel
, Label
, TRUE
);
340 memset(&BootSector
.VolumeLabel
[0], ' ', 11);
341 memcpy(&BootSector
.VolumeLabel
[0], VolumeLabel
.Buffer
,
342 VolumeLabel
.Length
< 11 ? VolumeLabel
.Length
: 11);
343 RtlFreeOemString(&VolumeLabel
);
346 memcpy(&BootSector
.SysType
[0], "FAT16 ", 8);
348 DPRINT("BootSector.SectorsHuge = %lx\n", BootSector
.SectorsHuge
);
350 RootDirSectors
= ((BootSector
.RootEntries
* 32) +
351 (BootSector
.BytesPerSector
- 1)) / BootSector
.BytesPerSector
;
353 /* Calculate number of FAT sectors */
354 /* (BootSector.BytesPerSector / 2) FAT entries (16bit) fit into one sector */
355 TmpVal1
= SectorCount
- (BootSector
.ReservedSectors
+ RootDirSectors
);
356 TmpVal2
= ((BootSector
.BytesPerSector
/ 2) * BootSector
.SectorsPerCluster
) + BootSector
.FATCount
;
357 TmpVal3
= (TmpVal1
+ (TmpVal2
- 1)) / TmpVal2
;
358 BootSector
.FATSectors
= (unsigned short)(TmpVal3
& 0xffff);
359 DPRINT("BootSector.FATSectors = %hu\n", BootSector
.FATSectors
);
361 /* Init context data */
362 Context
->TotalSectorCount
=
363 1 + (BootSector
.FATSectors
* 2) + RootDirSectors
;
365 Status
= Fat16WriteBootSector(FileHandle
,
368 if (!NT_SUCCESS(Status
))
370 DPRINT("Fat16WriteBootSector() failed with status 0x%.08x\n", Status
);
374 /* Write first FAT copy */
375 Status
= Fat16WriteFAT(FileHandle
,
379 if (!NT_SUCCESS(Status
))
381 DPRINT("Fat16WriteFAT() failed with status 0x%.08x\n", Status
);
385 /* Write second FAT copy */
386 Status
= Fat16WriteFAT(FileHandle
,
387 (ULONG
)BootSector
.FATSectors
,
390 if (!NT_SUCCESS(Status
))
392 DPRINT("Fat16WriteFAT() failed with status 0x%.08x.\n", Status
);
396 Status
= Fat16WriteRootDirectory(FileHandle
,
399 if (!NT_SUCCESS(Status
))
401 DPRINT("Fat16WriteRootDirectory() failed with status 0x%.08x\n", Status
);
406 /* FIXME: Fill remaining sectors */