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)
10 /* INCLUDES *******************************************************************/
18 /* FUNCTIONS ******************************************************************/
21 Fat16WriteBootSector(IN HANDLE FileHandle
,
22 IN PFAT16_BOOT_SECTOR BootSector
,
23 IN OUT PFORMAT_CONTEXT Context
)
25 IO_STATUS_BLOCK IoStatusBlock
;
27 PFAT16_BOOT_SECTOR NewBootSector
;
28 LARGE_INTEGER FileOffset
;
30 /* Allocate buffer for new bootsector */
31 NewBootSector
= (PFAT16_BOOT_SECTOR
)RtlAllocateHeap(RtlGetProcessHeap(),
33 BootSector
->BytesPerSector
);
34 if (NewBootSector
== NULL
)
35 return STATUS_INSUFFICIENT_RESOURCES
;
37 /* Zero the new bootsector */
38 RtlZeroMemory(NewBootSector
, BootSector
->BytesPerSector
);
40 /* Copy FAT16 BPB to new bootsector */
41 memcpy(&NewBootSector
->OEMName
[0],
42 &BootSector
->OEMName
[0],
43 FIELD_OFFSET(FAT16_BOOT_SECTOR
, Res2
) - FIELD_OFFSET(FAT16_BOOT_SECTOR
, OEMName
));
44 /* FAT16 BPB length (up to (not including) Res2) */
46 /* Write the boot sector signature */
47 NewBootSector
->Signature1
= 0xAA550000;
50 FileOffset
.QuadPart
= 0ULL;
51 Status
= NtWriteFile(FileHandle
,
57 BootSector
->BytesPerSector
,
60 if (!NT_SUCCESS(Status
))
62 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
66 UpdateProgress(Context
, 1);
70 RtlFreeHeap(RtlGetProcessHeap(), 0, NewBootSector
);
76 Fat16WriteFAT(IN HANDLE FileHandle
,
77 IN ULONG SectorOffset
,
78 IN PFAT16_BOOT_SECTOR BootSector
,
79 IN OUT PFORMAT_CONTEXT Context
)
81 IO_STATUS_BLOCK IoStatusBlock
;
84 LARGE_INTEGER FileOffset
;
89 Buffer
= (PUCHAR
)RtlAllocateHeap(RtlGetProcessHeap(),
93 return STATUS_INSUFFICIENT_RESOURCES
;
96 RtlZeroMemory(Buffer
, 32 * 1024);
99 Buffer
[0] = 0xf8; /* Media type */
103 Buffer
[2] = 0xff; /* Clean shutdown, no disk read/write errors, end-of-cluster (EOC) mark */
106 /* Write first sector of the FAT */
107 FileOffset
.QuadPart
= (SectorOffset
+ BootSector
->ReservedSectors
) * BootSector
->BytesPerSector
;
108 Status
= NtWriteFile(FileHandle
,
114 BootSector
->BytesPerSector
,
117 if (!NT_SUCCESS(Status
))
119 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
123 UpdateProgress(Context
, 1);
125 /* Zero the begin of the buffer */
126 RtlZeroMemory(Buffer
, 4);
128 /* Zero the rest of the FAT */
129 Sectors
= 32 * 1024 / BootSector
->BytesPerSector
;
130 for (i
= 1; i
< (ULONG
)BootSector
->FATSectors
; i
+= Sectors
)
132 /* Zero some sectors of the FAT */
133 FileOffset
.QuadPart
= (SectorOffset
+ BootSector
->ReservedSectors
+ i
) * BootSector
->BytesPerSector
;
135 if (((ULONG
)BootSector
->FATSectors
- i
) <= Sectors
)
137 Sectors
= (ULONG
)BootSector
->FATSectors
- i
;
140 Status
= NtWriteFile(FileHandle
,
146 Sectors
* BootSector
->BytesPerSector
,
149 if (!NT_SUCCESS(Status
))
151 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
155 UpdateProgress(Context
, Sectors
);
159 /* Free the buffer */
160 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
166 Fat16WriteRootDirectory(IN HANDLE FileHandle
,
167 IN PFAT16_BOOT_SECTOR BootSector
,
168 IN OUT PFORMAT_CONTEXT Context
)
170 IO_STATUS_BLOCK IoStatusBlock
;
171 NTSTATUS Status
= STATUS_SUCCESS
;
173 LARGE_INTEGER FileOffset
;
174 ULONG FirstRootDirSector
;
175 ULONG RootDirSectors
;
179 DPRINT("BootSector->ReservedSectors = %hu\n", BootSector
->ReservedSectors
);
180 DPRINT("BootSector->FATSectors = %hu\n", BootSector
->FATSectors
);
181 DPRINT("BootSector->SectorsPerCluster = %u\n", BootSector
->SectorsPerCluster
);
184 RootDirSectors
= ((BootSector
->RootEntries
* 32) +
185 (BootSector
->BytesPerSector
- 1)) / BootSector
->BytesPerSector
;
187 BootSector
->ReservedSectors
+ (BootSector
->FATCount
* BootSector
->FATSectors
);
189 DPRINT("RootDirSectors = %lu\n", RootDirSectors
);
190 DPRINT("FirstRootDirSector = %lu\n", FirstRootDirSector
);
192 /* Allocate buffer for the cluster */
193 Buffer
= (PUCHAR
)RtlAllocateHeap(RtlGetProcessHeap(),
197 return STATUS_INSUFFICIENT_RESOURCES
;
199 /* Zero the buffer */
200 RtlZeroMemory(Buffer
, 32 * 1024);
202 Sectors
= 32 * 1024 / BootSector
->BytesPerSector
;
203 for (i
= 0; i
< RootDirSectors
; i
+= Sectors
)
205 /* Zero some sectors of the root directory */
206 FileOffset
.QuadPart
= (FirstRootDirSector
+ i
) * BootSector
->BytesPerSector
;
208 if ((RootDirSectors
- i
) <= Sectors
)
210 Sectors
= RootDirSectors
- i
;
213 Status
= NtWriteFile(FileHandle
,
219 Sectors
* BootSector
->BytesPerSector
,
222 if (!NT_SUCCESS(Status
))
224 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
228 UpdateProgress(Context
, Sectors
);
232 /* Free the buffer */
233 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
239 Fat16Format(IN HANDLE FileHandle
,
240 IN PPARTITION_INFORMATION PartitionInfo
,
241 IN PDISK_GEOMETRY DiskGeometry
,
242 IN PUNICODE_STRING Label
,
243 IN BOOLEAN QuickFormat
,
244 IN ULONG ClusterSize
,
245 IN OUT PFORMAT_CONTEXT Context
)
247 FAT16_BOOT_SECTOR BootSector
;
248 OEM_STRING VolumeLabel
;
250 ULONG RootDirSectors
;
256 /* Calculate cluster size */
257 if (ClusterSize
== 0)
259 if (PartitionInfo
->PartitionLength
.QuadPart
< 16LL * 1024LL * 1024LL)
261 /* Partition < 16MB ==> 1KB Cluster */
264 else if (PartitionInfo
->PartitionLength
.QuadPart
< 128LL * 1024LL * 1024LL)
266 /* Partition < 128MB ==> 2KB Cluster */
269 else if (PartitionInfo
->PartitionLength
.QuadPart
< 256LL * 1024LL * 1024LL)
271 /* Partition < 256MB ==> 4KB Cluster */
276 /* Partition >= 256MB (< 512MB) ==> 8KB Cluster */
281 SectorCount
= PartitionInfo
->PartitionLength
.QuadPart
>>
282 GetShiftCount(DiskGeometry
->BytesPerSector
); /* Use shifting to avoid 64-bit division */
284 RtlZeroMemory(&BootSector
, sizeof(FAT16_BOOT_SECTOR
));
285 memcpy(&BootSector
.OEMName
[0], "MSWIN4.1", 8);
286 BootSector
.BytesPerSector
= DiskGeometry
->BytesPerSector
;
287 BootSector
.SectorsPerCluster
= ClusterSize
/ BootSector
.BytesPerSector
;
288 BootSector
.ReservedSectors
= 1;
289 BootSector
.FATCount
= 2;
290 BootSector
.RootEntries
= 512;
291 BootSector
.Sectors
= (SectorCount
< 0x10000) ? (unsigned short)SectorCount
: 0;
292 BootSector
.Media
= 0xf8;
293 BootSector
.FATSectors
= 0; /* Set later. See below. */
294 BootSector
.SectorsPerTrack
= DiskGeometry
->SectorsPerTrack
;
295 BootSector
.Heads
= DiskGeometry
->TracksPerCylinder
;
296 BootSector
.HiddenSectors
= PartitionInfo
->HiddenSectors
;
297 BootSector
.SectorsHuge
= (SectorCount
>= 0x10000) ? (unsigned long)SectorCount
: 0;
298 BootSector
.Drive
= (DiskGeometry
->MediaType
== FixedMedia
) ? 0x80 : 0x00;
299 BootSector
.ExtBootSignature
= 0x29;
300 BootSector
.VolumeID
= CalcVolumeSerialNumber();
301 if ((Label
== NULL
) || (Label
->Buffer
== NULL
))
303 memcpy(&BootSector
.VolumeLabel
[0], "NO NAME ", 11);
307 RtlUnicodeStringToOemString(&VolumeLabel
, Label
, TRUE
);
308 RtlFillMemory(&BootSector
.VolumeLabel
[0], 11, ' ');
309 memcpy(&BootSector
.VolumeLabel
[0], VolumeLabel
.Buffer
,
310 VolumeLabel
.Length
< 11 ? VolumeLabel
.Length
: 11);
311 RtlFreeOemString(&VolumeLabel
);
314 memcpy(&BootSector
.SysType
[0], "FAT16 ", 8);
316 DPRINT("BootSector.SectorsHuge = %lx\n", BootSector
.SectorsHuge
);
318 RootDirSectors
= ((BootSector
.RootEntries
* 32) +
319 (BootSector
.BytesPerSector
- 1)) / BootSector
.BytesPerSector
;
321 /* Calculate number of FAT sectors */
322 /* (BootSector.BytesPerSector / 2) FAT entries (16bit) fit into one sector */
323 TmpVal1
= SectorCount
- (BootSector
.ReservedSectors
+ RootDirSectors
);
324 TmpVal2
= ((BootSector
.BytesPerSector
/ 2) * BootSector
.SectorsPerCluster
) + BootSector
.FATCount
;
325 TmpVal3
= (TmpVal1
+ (TmpVal2
- 1)) / TmpVal2
;
326 BootSector
.FATSectors
= (unsigned short)(TmpVal3
& 0xffff);
327 DPRINT("BootSector.FATSectors = %hu\n", BootSector
.FATSectors
);
329 /* Init context data */
330 Context
->TotalSectorCount
=
331 1 + (BootSector
.FATSectors
* 2) + RootDirSectors
;
335 Context
->TotalSectorCount
+= SectorCount
;
337 Status
= FatWipeSectors(FileHandle
,
339 (ULONG
)BootSector
.SectorsPerCluster
,
340 (ULONG
)BootSector
.BytesPerSector
,
342 if (!NT_SUCCESS(Status
))
344 DPRINT("FatWipeSectors() failed with status 0x%.08x\n", Status
);
349 Status
= Fat16WriteBootSector(FileHandle
,
352 if (!NT_SUCCESS(Status
))
354 DPRINT("Fat16WriteBootSector() failed with status 0x%.08x\n", Status
);
358 /* Write first FAT copy */
359 Status
= Fat16WriteFAT(FileHandle
,
363 if (!NT_SUCCESS(Status
))
365 DPRINT("Fat16WriteFAT() failed with status 0x%.08x\n", Status
);
369 /* Write second FAT copy */
370 Status
= Fat16WriteFAT(FileHandle
,
371 (ULONG
)BootSector
.FATSectors
,
374 if (!NT_SUCCESS(Status
))
376 DPRINT("Fat16WriteFAT() failed with status 0x%.08x.\n", Status
);
380 Status
= Fat16WriteRootDirectory(FileHandle
,
383 if (!NT_SUCCESS(Status
))
385 DPRINT("Fat16WriteRootDirectory() failed with status 0x%.08x\n", Status
);