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)
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 Fat12WriteBootSector(IN HANDLE FileHandle
,
54 IN PFAT16_BOOT_SECTOR BootSector
,
55 IN OUT PFORMAT_CONTEXT Context
)
57 IO_STATUS_BLOCK IoStatusBlock
;
59 PFAT16_BOOT_SECTOR NewBootSector
;
60 LARGE_INTEGER FileOffset
;
62 /* Allocate buffer for new bootsector */
63 NewBootSector
= (PFAT16_BOOT_SECTOR
)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
->OEMName
[0],
74 &BootSector
->OEMName
[0],
75 59); /* FAT16 BPB length (up to (not including) Res2) */
77 /* Write the boot sector signature */
78 NewBootSector
->Signature1
= 0xAA550000;
81 FileOffset
.QuadPart
= 0ULL;
82 Status
= NtWriteFile(FileHandle
,
88 BootSector
->BytesPerSector
,
91 if (!NT_SUCCESS(Status
))
93 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
94 RtlFreeHeap(RtlGetProcessHeap(), 0, NewBootSector
);
98 /* Free the new boot sector */
99 RtlFreeHeap(RtlGetProcessHeap(), 0, NewBootSector
);
101 UpdateProgress(Context
, 1);
108 Fat12WriteFAT(IN HANDLE FileHandle
,
109 IN ULONG SectorOffset
,
110 IN PFAT16_BOOT_SECTOR BootSector
,
111 IN OUT PFORMAT_CONTEXT Context
)
113 IO_STATUS_BLOCK IoStatusBlock
;
116 LARGE_INTEGER FileOffset
;
121 /* Allocate buffer */
122 Buffer
= (PUCHAR
)RtlAllocateHeap(RtlGetProcessHeap(),
126 return STATUS_INSUFFICIENT_RESOURCES
;
128 /* Zero the buffer */
129 memset(Buffer
, 0, 32 * 1024);
131 /* FAT cluster 0 & 1*/
132 Buffer
[0] = 0xf8; /* Media type */
136 /* Write first sector of the FAT */
137 FileOffset
.QuadPart
= (SectorOffset
+ BootSector
->ReservedSectors
) * BootSector
->BytesPerSector
;
138 Status
= NtWriteFile(FileHandle
,
144 BootSector
->BytesPerSector
,
147 if (!NT_SUCCESS(Status
))
149 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
150 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
154 UpdateProgress(Context
, 1);
156 /* Zero the begin of the buffer */
157 memset(Buffer
, 0, 3);
159 /* Zero the rest of the FAT */
160 Sectors
= 32 * 1024 / BootSector
->BytesPerSector
;
161 for (i
= 1; i
< (ULONG
)BootSector
->FATSectors
; i
+= Sectors
)
163 /* Zero some sectors of the FAT */
164 FileOffset
.QuadPart
= (SectorOffset
+ BootSector
->ReservedSectors
+ i
) * BootSector
->BytesPerSector
;
165 if (((ULONG
)BootSector
->FATSectors
- i
) <= Sectors
)
167 Sectors
= (ULONG
)BootSector
->FATSectors
- i
;
170 Size
= Sectors
* BootSector
->BytesPerSector
;
171 Status
= NtWriteFile(FileHandle
,
180 if (!NT_SUCCESS(Status
))
182 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
183 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
187 UpdateProgress(Context
, Sectors
);
190 /* Free the buffer */
191 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
198 Fat12WriteRootDirectory(IN HANDLE FileHandle
,
199 IN PFAT16_BOOT_SECTOR BootSector
,
200 IN OUT PFORMAT_CONTEXT Context
)
202 IO_STATUS_BLOCK IoStatusBlock
;
203 NTSTATUS Status
= STATUS_SUCCESS
;
205 LARGE_INTEGER FileOffset
;
206 ULONG FirstRootDirSector
;
207 ULONG RootDirSectors
;
212 DPRINT("BootSector->ReservedSectors = %hu\n", BootSector
->ReservedSectors
);
213 DPRINT("BootSector->FATSectors = %hu\n", BootSector
->FATSectors
);
214 DPRINT("BootSector->SectorsPerCluster = %u\n", BootSector
->SectorsPerCluster
);
217 RootDirSectors
= ((BootSector
->RootEntries
* 32) +
218 (BootSector
->BytesPerSector
- 1)) / BootSector
->BytesPerSector
;
220 BootSector
->ReservedSectors
+ (BootSector
->FATCount
* BootSector
->FATSectors
);
222 DPRINT("RootDirSectors = %lu\n", RootDirSectors
);
223 DPRINT("FirstRootDirSector = %lu\n", FirstRootDirSector
);
225 /* Allocate buffer for the cluster */
226 Buffer
= (PUCHAR
)RtlAllocateHeap(RtlGetProcessHeap(),
230 return STATUS_INSUFFICIENT_RESOURCES
;
232 /* Zero the buffer */
233 memset(Buffer
, 0, 32 * 1024);
235 Sectors
= 32 * 1024 / BootSector
->BytesPerSector
;
236 for (i
= 0; i
< RootDirSectors
; i
+= Sectors
)
238 /* Zero some sectors of the root directory */
239 FileOffset
.QuadPart
= (FirstRootDirSector
+ i
) * BootSector
->BytesPerSector
;
241 if ((RootDirSectors
- i
) <= Sectors
)
243 Sectors
= RootDirSectors
- i
;
246 Size
= Sectors
* BootSector
->BytesPerSector
;
248 Status
= NtWriteFile(FileHandle
,
257 if (!NT_SUCCESS(Status
))
259 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
260 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
264 UpdateProgress(Context
, Sectors
);
267 /* Free the buffer */
268 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
275 Fat12Format(IN HANDLE FileHandle
,
276 IN PPARTITION_INFORMATION PartitionInfo
,
277 IN PDISK_GEOMETRY DiskGeometry
,
278 IN PUNICODE_STRING Label
,
279 IN BOOLEAN QuickFormat
,
280 IN ULONG ClusterSize
,
281 IN OUT PFORMAT_CONTEXT Context
)
283 FAT16_BOOT_SECTOR BootSector
;
284 OEM_STRING VolumeLabel
;
286 ULONG RootDirSectors
;
292 /* Calculate cluster size */
293 if (ClusterSize
== 0)
295 if (DiskGeometry
->MediaType
== FixedMedia
)
297 /* 4KB Cluster (Harddisk only) */
302 /* 512 byte cluster (floppy) */
307 SectorCount
= PartitionInfo
->PartitionLength
.QuadPart
>>
308 GetShiftCount(DiskGeometry
->BytesPerSector
); /* Use shifting to avoid 64-bit division */
310 DPRINT("SectorCount = %lu\n", SectorCount
);
312 memset(&BootSector
, 0, sizeof(FAT16_BOOT_SECTOR
));
313 memcpy(&BootSector
.OEMName
[0], "MSWIN4.1", 8);
314 BootSector
.BytesPerSector
= DiskGeometry
->BytesPerSector
;
315 BootSector
.SectorsPerCluster
= ClusterSize
/ BootSector
.BytesPerSector
;
316 BootSector
.ReservedSectors
= 1;
317 BootSector
.FATCount
= 2;
318 BootSector
.RootEntries
= 512;
319 BootSector
.Sectors
= (SectorCount
< 0x10000) ? (unsigned short)SectorCount
: 0;
320 BootSector
.Media
= 0xf8;
321 BootSector
.FATSectors
= 0; /* Set later. See below. */
322 BootSector
.SectorsPerTrack
= DiskGeometry
->SectorsPerTrack
;
323 BootSector
.Heads
= DiskGeometry
->TracksPerCylinder
;
324 BootSector
.HiddenSectors
= PartitionInfo
->HiddenSectors
;
325 BootSector
.SectorsHuge
= (SectorCount
>= 0x10000) ? (unsigned long)SectorCount
: 0;
326 BootSector
.Drive
= DiskGeometry
->MediaType
== FixedMedia
? 0x80 : 0x00;
327 BootSector
.ExtBootSignature
= 0x29;
328 BootSector
.VolumeID
= CalcVolumeSerialNumber();
329 if ((Label
== NULL
) || (Label
->Buffer
== NULL
))
331 memcpy(&BootSector
.VolumeLabel
[0], "NO NAME ", 11);
335 RtlUnicodeStringToOemString(&VolumeLabel
, Label
, TRUE
);
336 memset(&BootSector
.VolumeLabel
[0], ' ', 11);
337 memcpy(&BootSector
.VolumeLabel
[0], VolumeLabel
.Buffer
,
338 VolumeLabel
.Length
< 11 ? VolumeLabel
.Length
: 11);
339 RtlFreeOemString(&VolumeLabel
);
342 memcpy(&BootSector
.SysType
[0], "FAT12 ", 8);
344 RootDirSectors
= ((BootSector
.RootEntries
* 32) +
345 (BootSector
.BytesPerSector
- 1)) / BootSector
.BytesPerSector
;
347 /* Calculate number of FAT sectors */
348 /* ((BootSector.BytesPerSector * 2) / 3) FAT entries (12bit) fit into one sector */
349 TmpVal1
= SectorCount
- (BootSector
.ReservedSectors
+ RootDirSectors
);
350 TmpVal2
= (((BootSector
.BytesPerSector
* 2) / 3) * BootSector
.SectorsPerCluster
) + BootSector
.FATCount
;
351 TmpVal3
= (TmpVal1
+ (TmpVal2
- 1)) / TmpVal2
;
352 BootSector
.FATSectors
= (unsigned short)(TmpVal3
& 0xffff);
354 DPRINT("BootSector.FATSectors = %hx\n", BootSector
.FATSectors
);
356 /* Init context data */
357 Context
->TotalSectorCount
=
358 1 + (BootSector
.FATSectors
* 2) + RootDirSectors
;
360 Status
= Fat12WriteBootSector(FileHandle
,
363 if (!NT_SUCCESS(Status
))
365 DPRINT("Fat12WriteBootSector() failed with status 0x%.08x\n", Status
);
369 /* Write first FAT copy */
370 Status
= Fat12WriteFAT(FileHandle
,
374 if (!NT_SUCCESS(Status
))
376 DPRINT("Fat12WriteFAT() failed with status 0x%.08x\n", Status
);
380 /* Write second FAT copy */
381 Status
= Fat12WriteFAT(FileHandle
,
382 (ULONG
)BootSector
.FATSectors
,
385 if (!NT_SUCCESS(Status
))
387 DPRINT("Fat12WriteFAT() failed with status 0x%.08x.\n", Status
);
391 Status
= Fat12WriteRootDirectory(FileHandle
,
394 if (!NT_SUCCESS(Status
))
396 DPRINT("Fat12WriteRootDirectory() failed with status 0x%.08x\n", Status
);
401 /* FIXME: Fill remaining sectors */