1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS VFAT filesystem library
4 * FILE: fat12.c
5 * PURPOSE: Fat12 support
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * Eric Kohl
8 */
9
10 /* INCLUDES *******************************************************************/
11
12 #include "vfatlib.h"
13
14 #define NDEBUG
15 #include <debug.h>
16
17
18 /* FUNCTIONS ******************************************************************/
19
20 static NTSTATUS
Fat12WriteBootSector(IN HANDLE FileHandle,IN PFAT16_BOOT_SECTOR BootSector,IN OUT PFORMAT_CONTEXT Context)21 Fat12WriteBootSector(IN HANDLE FileHandle,
22 IN PFAT16_BOOT_SECTOR BootSector,
23 IN OUT PFORMAT_CONTEXT Context)
24 {
25 IO_STATUS_BLOCK IoStatusBlock;
26 NTSTATUS Status;
27 PFAT16_BOOT_SECTOR NewBootSector;
28 LARGE_INTEGER FileOffset;
29
30 /* Allocate buffer for new bootsector */
31 NewBootSector = (PFAT16_BOOT_SECTOR)RtlAllocateHeap(RtlGetProcessHeap (),
32 0,
33 BootSector->BytesPerSector);
34 if (NewBootSector == NULL)
35 return STATUS_INSUFFICIENT_RESOURCES;
36
37 /* Zero the new bootsector */
38 RtlZeroMemory(NewBootSector, BootSector->BytesPerSector);
39
40 /* Copy FAT16 BPB to new bootsector */
41 memcpy(NewBootSector, BootSector,
42 FIELD_OFFSET(FAT16_BOOT_SECTOR, Res2) - FIELD_OFFSET(FAT16_BOOT_SECTOR, Jump));
43 /* FAT16 BPB length (up to (not including) Res2) */
44
45 /* Write the boot sector signature */
46 NewBootSector->Signature1 = 0xAA550000;
47
48 /* Write sector 0 */
49 FileOffset.QuadPart = 0ULL;
50 Status = NtWriteFile(FileHandle,
51 NULL,
52 NULL,
53 NULL,
54 &IoStatusBlock,
55 NewBootSector,
56 BootSector->BytesPerSector,
57 &FileOffset,
58 NULL);
59 if (!NT_SUCCESS(Status))
60 {
61 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
62 goto done;
63 }
64
65 UpdateProgress(Context, 1);
66
67 done:
68 /* Free the buffer */
69 RtlFreeHeap(RtlGetProcessHeap(), 0, NewBootSector);
70 return Status;
71 }
72
73
74 static NTSTATUS
Fat12WriteFAT(IN HANDLE FileHandle,IN ULONG SectorOffset,IN PFAT16_BOOT_SECTOR BootSector,IN OUT PFORMAT_CONTEXT Context)75 Fat12WriteFAT(IN HANDLE FileHandle,
76 IN ULONG SectorOffset,
77 IN PFAT16_BOOT_SECTOR BootSector,
78 IN OUT PFORMAT_CONTEXT Context)
79 {
80 IO_STATUS_BLOCK IoStatusBlock;
81 NTSTATUS Status;
82 PUCHAR Buffer;
83 LARGE_INTEGER FileOffset;
84 ULONG i;
85 ULONG Size;
86 ULONG Sectors;
87
88 /* Allocate buffer */
89 Buffer = (PUCHAR)RtlAllocateHeap(RtlGetProcessHeap(),
90 0,
91 32 * 1024);
92 if (Buffer == NULL)
93 return STATUS_INSUFFICIENT_RESOURCES;
94
95 /* Zero the buffer */
96 RtlZeroMemory(Buffer, 32 * 1024);
97
98 /* FAT cluster 0 & 1*/
99 Buffer[0] = 0xf8; /* Media type */
100 Buffer[1] = 0xff;
101 Buffer[2] = 0xff;
102
103 /* Write first sector of the FAT */
104 FileOffset.QuadPart = (SectorOffset + BootSector->ReservedSectors) * BootSector->BytesPerSector;
105 Status = NtWriteFile(FileHandle,
106 NULL,
107 NULL,
108 NULL,
109 &IoStatusBlock,
110 Buffer,
111 BootSector->BytesPerSector,
112 &FileOffset,
113 NULL);
114 if (!NT_SUCCESS(Status))
115 {
116 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
117 goto done;
118 }
119
120 UpdateProgress(Context, 1);
121
122 /* Zero the begin of the buffer */
123 RtlZeroMemory(Buffer, 3);
124
125 /* Zero the rest of the FAT */
126 Sectors = 32 * 1024 / BootSector->BytesPerSector;
127 for (i = 1; i < (ULONG)BootSector->FATSectors; i += Sectors)
128 {
129 /* Zero some sectors of the FAT */
130 FileOffset.QuadPart = (SectorOffset + BootSector->ReservedSectors + i) * BootSector->BytesPerSector;
131 if (((ULONG)BootSector->FATSectors - i) <= Sectors)
132 {
133 Sectors = (ULONG)BootSector->FATSectors - i;
134 }
135
136 Size = Sectors * BootSector->BytesPerSector;
137 Status = NtWriteFile(FileHandle,
138 NULL,
139 NULL,
140 NULL,
141 &IoStatusBlock,
142 Buffer,
143 Size,
144 &FileOffset,
145 NULL);
146 if (!NT_SUCCESS(Status))
147 {
148 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
149 goto done;
150 }
151
152 UpdateProgress(Context, Sectors);
153 }
154
155 done:
156 /* Free the buffer */
157 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
158 return Status;
159 }
160
161
162 static NTSTATUS
Fat12WriteRootDirectory(IN HANDLE FileHandle,IN PFAT16_BOOT_SECTOR BootSector,IN OUT PFORMAT_CONTEXT Context)163 Fat12WriteRootDirectory(IN HANDLE FileHandle,
164 IN PFAT16_BOOT_SECTOR BootSector,
165 IN OUT PFORMAT_CONTEXT Context)
166 {
167 IO_STATUS_BLOCK IoStatusBlock;
168 NTSTATUS Status = STATUS_SUCCESS;
169 PUCHAR Buffer;
170 LARGE_INTEGER FileOffset;
171 ULONG FirstRootDirSector;
172 ULONG RootDirSectors;
173 ULONG Sectors;
174 ULONG Size;
175 ULONG i;
176
177 DPRINT("BootSector->ReservedSectors = %hu\n", BootSector->ReservedSectors);
178 DPRINT("BootSector->FATSectors = %hu\n", BootSector->FATSectors);
179 DPRINT("BootSector->SectorsPerCluster = %u\n", BootSector->SectorsPerCluster);
180
181 /* Write cluster */
182 RootDirSectors = ((BootSector->RootEntries * 32) +
183 (BootSector->BytesPerSector - 1)) / BootSector->BytesPerSector;
184 FirstRootDirSector =
185 BootSector->ReservedSectors + (BootSector->FATCount * BootSector->FATSectors);
186
187 DPRINT("RootDirSectors = %lu\n", RootDirSectors);
188 DPRINT("FirstRootDirSector = %lu\n", FirstRootDirSector);
189
190 /* Allocate buffer for the cluster */
191 Buffer = (PUCHAR)RtlAllocateHeap(RtlGetProcessHeap(),
192 0,
193 32 * 1024);
194 if (Buffer == NULL)
195 return STATUS_INSUFFICIENT_RESOURCES;
196
197 /* Zero the buffer */
198 RtlZeroMemory(Buffer, 32 * 1024);
199
200 Sectors = 32 * 1024 / BootSector->BytesPerSector;
201 for (i = 0; i < RootDirSectors; i += Sectors)
202 {
203 /* Zero some sectors of the root directory */
204 FileOffset.QuadPart = (FirstRootDirSector + i) * BootSector->BytesPerSector;
205
206 if ((RootDirSectors - i) <= Sectors)
207 {
208 Sectors = RootDirSectors - i;
209 }
210
211 Size = Sectors * BootSector->BytesPerSector;
212
213 Status = NtWriteFile(FileHandle,
214 NULL,
215 NULL,
216 NULL,
217 &IoStatusBlock,
218 Buffer,
219 Size,
220 &FileOffset,
221 NULL);
222 if (!NT_SUCCESS(Status))
223 {
224 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
225 goto done;
226 }
227
228 UpdateProgress(Context, Sectors);
229 }
230
231 done:
232 /* Free the buffer */
233 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
234 return Status;
235 }
236
237
238 NTSTATUS
Fat12Format(IN HANDLE FileHandle,IN PPARTITION_INFORMATION PartitionInfo,IN PDISK_GEOMETRY DiskGeometry,IN PUNICODE_STRING Label,IN BOOLEAN QuickFormat,IN ULONG ClusterSize,IN OUT PFORMAT_CONTEXT Context)239 Fat12Format(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)
246 {
247 FAT16_BOOT_SECTOR BootSector;
248 OEM_STRING VolumeLabel;
249 ULONG SectorCount;
250 ULONG RootDirSectors;
251 ULONG TmpVal1;
252 ULONG TmpVal2;
253 ULONG TmpVal3;
254 NTSTATUS Status;
255
256 /* Calculate cluster size */
257 if (ClusterSize == 0)
258 {
259 if (DiskGeometry->MediaType == FixedMedia)
260 {
261 /* 4KB Cluster (Harddisk only) */
262 ClusterSize = 4096;
263 }
264 else
265 {
266 /* 512 byte cluster (floppy) */
267 ClusterSize = 512;
268 }
269 }
270
271 SectorCount = PartitionInfo->PartitionLength.QuadPart >>
272 GetShiftCount(DiskGeometry->BytesPerSector); /* Use shifting to avoid 64-bit division */
273
274 DPRINT("SectorCount = %lu\n", SectorCount);
275
276 RtlZeroMemory(&BootSector, sizeof(FAT16_BOOT_SECTOR));
277 memcpy(&BootSector.OEMName[0], "MSWIN4.1", 8);
278 /* FIXME: Add dummy bootloader for real */
279 BootSector.Jump[0] = 0xeb;
280 BootSector.Jump[1] = 0x3c;
281 BootSector.Jump[2] = 0x90;
282 BootSector.BytesPerSector = DiskGeometry->BytesPerSector;
283 BootSector.SectorsPerCluster = ClusterSize / BootSector.BytesPerSector;
284 BootSector.ReservedSectors = 1;
285 BootSector.FATCount = 2;
286 BootSector.RootEntries = 512;
287 BootSector.Sectors = (SectorCount < 0x10000) ? (unsigned short)SectorCount : 0;
288 BootSector.Media = 0xf8;
289 BootSector.FATSectors = 0; /* Set later. See below. */
290 BootSector.SectorsPerTrack = DiskGeometry->SectorsPerTrack;
291 BootSector.Heads = DiskGeometry->TracksPerCylinder;
292 BootSector.HiddenSectors = PartitionInfo->HiddenSectors;
293 BootSector.SectorsHuge = (SectorCount >= 0x10000) ? (unsigned long)SectorCount : 0;
294 BootSector.Drive = (DiskGeometry->MediaType == FixedMedia) ? 0x80 : 0x00;
295 BootSector.ExtBootSignature = 0x29;
296 BootSector.VolumeID = CalcVolumeSerialNumber();
297 if ((Label == NULL) || (Label->Buffer == NULL))
298 {
299 memcpy(&BootSector.VolumeLabel[0], "NO NAME ", 11);
300 }
301 else
302 {
303 RtlUnicodeStringToOemString(&VolumeLabel, Label, TRUE);
304 RtlFillMemory(&BootSector.VolumeLabel[0], 11, ' ');
305 memcpy(&BootSector.VolumeLabel[0], VolumeLabel.Buffer,
306 VolumeLabel.Length < 11 ? VolumeLabel.Length : 11);
307 RtlFreeOemString(&VolumeLabel);
308 }
309
310 memcpy(&BootSector.SysType[0], "FAT12 ", 8);
311
312 RootDirSectors = ((BootSector.RootEntries * 32) +
313 (BootSector.BytesPerSector - 1)) / BootSector.BytesPerSector;
314
315 /* Calculate number of FAT sectors */
316 /* ((BootSector.BytesPerSector * 2) / 3) FAT entries (12bit) fit into one sector */
317 TmpVal1 = SectorCount - (BootSector.ReservedSectors + RootDirSectors);
318 TmpVal2 = (((BootSector.BytesPerSector * 2) / 3) * BootSector.SectorsPerCluster) + BootSector.FATCount;
319 TmpVal3 = (TmpVal1 + (TmpVal2 - 1)) / TmpVal2;
320 BootSector.FATSectors = (unsigned short)(TmpVal3 & 0xffff);
321
322 DPRINT("BootSector.FATSectors = %hx\n", BootSector.FATSectors);
323
324 /* Init context data */
325 Context->TotalSectorCount =
326 1 + (BootSector.FATSectors * 2) + RootDirSectors;
327
328 if (!QuickFormat)
329 {
330 Context->TotalSectorCount += SectorCount;
331
332 Status = FatWipeSectors(FileHandle,
333 SectorCount,
334 (ULONG)BootSector.SectorsPerCluster,
335 (ULONG)BootSector.BytesPerSector,
336 Context);
337 if (!NT_SUCCESS(Status))
338 {
339 DPRINT("FatWipeSectors() failed with status 0x%.08x\n", Status);
340 return Status;
341 }
342 }
343
344 Status = Fat12WriteBootSector(FileHandle,
345 &BootSector,
346 Context);
347 if (!NT_SUCCESS(Status))
348 {
349 DPRINT("Fat12WriteBootSector() failed with status 0x%.08x\n", Status);
350 return Status;
351 }
352
353 /* Write first FAT copy */
354 Status = Fat12WriteFAT(FileHandle,
355 0,
356 &BootSector,
357 Context);
358 if (!NT_SUCCESS(Status))
359 {
360 DPRINT("Fat12WriteFAT() failed with status 0x%.08x\n", Status);
361 return Status;
362 }
363
364 /* Write second FAT copy */
365 Status = Fat12WriteFAT(FileHandle,
366 (ULONG)BootSector.FATSectors,
367 &BootSector,
368 Context);
369 if (!NT_SUCCESS(Status))
370 {
371 DPRINT("Fat12WriteFAT() failed with status 0x%.08x.\n", Status);
372 return Status;
373 }
374
375 Status = Fat12WriteRootDirectory(FileHandle,
376 &BootSector,
377 Context);
378 if (!NT_SUCCESS(Status))
379 {
380 DPRINT("Fat12WriteRootDirectory() failed with status 0x%.08x\n", Status);
381 }
382
383 return Status;
384 }
385