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(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 Fat16WriteBootSector (IN HANDLE FileHandle
,
52 IN PFAT16_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 FAT16 BPB to new bootsector */
71 memcpy((NewBootSector
+ 3),
72 &BootSector
->OEMName
[0],
73 59); /* FAT16 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 /* Free the new boot sector */
96 RtlFreeHeap(RtlGetProcessHeap(), 0, NewBootSector
);
103 Fat16WriteFAT (IN HANDLE FileHandle
,
104 IN ULONG SectorOffset
,
105 IN PFAT16_BOOT_SECTOR BootSector
,
106 IN OUT PFORMAT_CONTEXT Context
)
108 IO_STATUS_BLOCK IoStatusBlock
;
111 LARGE_INTEGER FileOffset
;
115 /* Allocate buffer */
116 Buffer
= (PUCHAR
)RtlAllocateHeap(RtlGetProcessHeap(),
120 return(STATUS_INSUFFICIENT_RESOURCES
);
122 /* Zero the buffer */
123 memset(Buffer
, 0, 32 * 1024);
126 Buffer
[0] = 0xf8; /* Media type */
130 Buffer
[2] = 0xff; /* Clean shutdown, no disk read/write errors, end-of-cluster (EOC) mark */
133 /* Write first sector of the FAT */
134 FileOffset
.QuadPart
= (SectorOffset
+ BootSector
->ReservedSectors
) * BootSector
->BytesPerSector
;
135 Status
= NtWriteFile(FileHandle
,
141 BootSector
->BytesPerSector
,
144 if (!NT_SUCCESS(Status
))
146 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
147 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
151 UpdateProgress (Context
, 1);
153 /* Zero the begin of the buffer */
154 memset(Buffer
, 0, 4);
156 /* Zero the rest of the FAT */
157 Sectors
= 32 * 1024 / BootSector
->BytesPerSector
;
158 for (i
= 1; i
< (ULONG
)BootSector
->FATSectors
; i
+= Sectors
)
160 /* Zero some sectors of the FAT */
161 FileOffset
.QuadPart
= (SectorOffset
+ BootSector
->ReservedSectors
+ i
) * BootSector
->BytesPerSector
;
163 if (((ULONG
)BootSector
->FATSectors
- i
) <= Sectors
)
165 Sectors
= (ULONG
)BootSector
->FATSectors
- i
;
168 Status
= NtWriteFile(FileHandle
,
174 Sectors
* BootSector
->BytesPerSector
,
177 if (!NT_SUCCESS(Status
))
179 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
180 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
184 UpdateProgress (Context
, Sectors
);
187 /* Free the buffer */
188 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
195 Fat16WriteRootDirectory (IN HANDLE FileHandle
,
196 IN PFAT16_BOOT_SECTOR BootSector
,
197 IN OUT PFORMAT_CONTEXT Context
)
199 IO_STATUS_BLOCK IoStatusBlock
;
200 NTSTATUS Status
= STATUS_SUCCESS
;
202 LARGE_INTEGER FileOffset
;
203 ULONG FirstRootDirSector
;
204 ULONG RootDirSectors
;
208 DPRINT("BootSector->ReservedSectors = %hu\n", BootSector
->ReservedSectors
);
209 DPRINT("BootSector->FATSectors = %hu\n", BootSector
->FATSectors
);
210 DPRINT("BootSector->SectorsPerCluster = %u\n", BootSector
->SectorsPerCluster
);
213 RootDirSectors
= ((BootSector
->RootEntries
* 32) +
214 (BootSector
->BytesPerSector
- 1)) / BootSector
->BytesPerSector
;
216 BootSector
->ReservedSectors
+ (BootSector
->FATCount
* BootSector
->FATSectors
);
218 DPRINT("RootDirSectors = %lu\n", RootDirSectors
);
219 DPRINT("FirstRootDirSector = %lu\n", FirstRootDirSector
);
221 /* Allocate buffer for the cluster */
222 Buffer
= (PUCHAR
)RtlAllocateHeap(RtlGetProcessHeap(),
226 return(STATUS_INSUFFICIENT_RESOURCES
);
228 /* Zero the buffer */
229 memset(Buffer
, 0, 32 * 1024);
231 Sectors
= 32 * 1024 / BootSector
->BytesPerSector
;
232 for (i
= 0; i
< RootDirSectors
; i
+= Sectors
)
234 /* Zero some sectors of the root directory */
235 FileOffset
.QuadPart
= (FirstRootDirSector
+ i
) * BootSector
->BytesPerSector
;
237 if ((RootDirSectors
- i
) <= Sectors
)
239 Sectors
= RootDirSectors
- i
;
242 Status
= NtWriteFile(FileHandle
,
248 Sectors
* BootSector
->BytesPerSector
,
251 if (!NT_SUCCESS(Status
))
253 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
254 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
258 UpdateProgress (Context
, Sectors
);
261 /* Free the buffer */
262 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
269 Fat16Format (HANDLE FileHandle
,
270 PPARTITION_INFORMATION PartitionInfo
,
271 PDISK_GEOMETRY DiskGeometry
,
272 PUNICODE_STRING Label
,
275 PFORMAT_CONTEXT Context
)
277 FAT16_BOOT_SECTOR BootSector
;
278 OEM_STRING VolumeLabel
;
280 ULONG RootDirSectors
;
286 /* Calculate cluster size */
287 if (ClusterSize
== 0)
289 if (PartitionInfo
->PartitionLength
.QuadPart
< 16LL * 1024LL * 1024LL)
291 /* Partition < 16MB ==> 1KB Cluster */
294 else if (PartitionInfo
->PartitionLength
.QuadPart
< 128LL * 1024LL * 1024LL)
296 /* Partition < 128MB ==> 2KB Cluster */
299 else if (PartitionInfo
->PartitionLength
.QuadPart
< 256LL * 1024LL * 1024LL)
301 /* Partition < 256MB ==> 4KB Cluster */
306 /* Partition >= 256MB (< 512MB) ==> 8KB Cluster */
311 SectorCount
= PartitionInfo
->PartitionLength
.QuadPart
>>
312 GetShiftCount(DiskGeometry
->BytesPerSector
); /* Use shifting to avoid 64-bit division */
314 memset(&BootSector
, 0, sizeof(FAT16_BOOT_SECTOR
));
315 memcpy(&BootSector
.OEMName
[0], "MSWIN4.1", 8);
316 BootSector
.BytesPerSector
= DiskGeometry
->BytesPerSector
;
317 BootSector
.SectorsPerCluster
= ClusterSize
/ BootSector
.BytesPerSector
;
318 BootSector
.ReservedSectors
= 1;
319 BootSector
.FATCount
= 2;
320 BootSector
.RootEntries
= 512;
321 BootSector
.Sectors
= (SectorCount
< 0x10000) ? (unsigned short)SectorCount
: 0;
322 BootSector
.Media
= 0xf8;
323 BootSector
.FATSectors
= 0; /* Set later. See below. */
324 BootSector
.SectorsPerTrack
= DiskGeometry
->SectorsPerTrack
;
325 BootSector
.Heads
= DiskGeometry
->TracksPerCylinder
;
326 BootSector
.HiddenSectors
= PartitionInfo
->HiddenSectors
;
327 BootSector
.SectorsHuge
= (SectorCount
>= 0x10000) ? (unsigned long)SectorCount
: 0;
328 BootSector
.Drive
= 0xff; /* No BIOS boot drive available */
329 BootSector
.ExtBootSignature
= 0x29;
330 BootSector
.VolumeID
= CalcVolumeSerialNumber();
331 if ((Label
== NULL
) || (Label
->Buffer
== NULL
))
333 memcpy(&BootSector
.VolumeLabel
[0], "NO NAME ", 11);
337 RtlUnicodeStringToOemString(&VolumeLabel
, Label
, TRUE
);
338 memset(&BootSector
.VolumeLabel
[0], ' ', 11);
339 memcpy(&BootSector
.VolumeLabel
[0], VolumeLabel
.Buffer
,
340 VolumeLabel
.Length
< 11 ? VolumeLabel
.Length
: 11);
341 RtlFreeOemString(&VolumeLabel
);
343 memcpy(&BootSector
.SysType
[0], "FAT16 ", 8);
345 DPRINT("BootSector.SectorsHuge = %lx\n", BootSector
.SectorsHuge
);
347 RootDirSectors
= ((BootSector
.RootEntries
* 32) +
348 (BootSector
.BytesPerSector
- 1)) / BootSector
.BytesPerSector
;
350 /* Calculate number of FAT sectors */
351 /* (BootSector.BytesPerSector / 2) FAT entries (16bit) fit into one sector */
352 TmpVal1
= SectorCount
- (BootSector
.ReservedSectors
+ RootDirSectors
);
353 TmpVal2
= ((BootSector
.BytesPerSector
/ 2) * BootSector
.SectorsPerCluster
) + BootSector
.FATCount
;
354 TmpVal3
= (TmpVal1
+ (TmpVal2
- 1)) / TmpVal2
;
355 BootSector
.FATSectors
= (unsigned short)(TmpVal3
& 0xffff);
356 DPRINT("BootSector.FATSectors = %hu\n", BootSector
.FATSectors
);
358 /* Init context data */
359 Context
->TotalSectorCount
=
360 1 + (BootSector
.FATSectors
* 2) + RootDirSectors
;
362 Status
= Fat16WriteBootSector (FileHandle
,
365 if (!NT_SUCCESS(Status
))
367 DPRINT("Fat16WriteBootSector() failed with status 0x%.08x\n", Status
);
371 /* Write first FAT copy */
372 Status
= Fat16WriteFAT (FileHandle
,
376 if (!NT_SUCCESS(Status
))
378 DPRINT("Fat16WriteFAT() failed with status 0x%.08x\n", Status
);
382 /* Write second FAT copy */
383 Status
= Fat16WriteFAT (FileHandle
,
384 (ULONG
)BootSector
.FATSectors
,
387 if (!NT_SUCCESS(Status
))
389 DPRINT("Fat16WriteFAT() failed with status 0x%.08x.\n", Status
);
393 Status
= Fat16WriteRootDirectory (FileHandle
,
396 if (!NT_SUCCESS(Status
))
398 DPRINT("Fat16WriteRootDirectory() failed with status 0x%.08x\n", Status
);
403 /* FIXME: Fill remaining sectors */