Moved FAT32 code to a sepatate file.
[reactos.git] / reactos / lib / fslib / vfatlib / fat32.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS VFAT filesystem library
4 * FILE: fat16.c
5 * PURPOSE: Fat16 support
6 * PROGRAMMERS: Eric Kohl (ekohl@rz-online.de)
7 * REVISIONS:
8 * EK 05/04-2003 Created
9 */
10 #define NDEBUG
11 #include <debug.h>
12 #define NTOS_MODE_USER
13 #include <ntos.h>
14 #include <ddk/ntddscsi.h>
15 #include "vfatlib.h"
16
17
18 static ULONG
19 GetShiftCount(ULONG Value)
20 {
21 ULONG i = 1;
22 while (Value > 0)
23 {
24 i++;
25 Value /= 2;
26 }
27 return i - 2;
28 }
29
30
31 static NTSTATUS
32 Fat32WriteBootSector(IN HANDLE FileHandle,
33 IN PFAT32_BOOT_SECTOR BootSector)
34 {
35 OBJECT_ATTRIBUTES ObjectAttributes;
36 IO_STATUS_BLOCK IoStatusBlock;
37 UNICODE_STRING Name;
38 NTSTATUS Status;
39 PUCHAR NewBootSector;
40 LARGE_INTEGER FileOffset;
41
42 /* Allocate buffer for new bootsector */
43 NewBootSector = (PUCHAR)RtlAllocateHeap(RtlGetProcessHeap(),
44 0,
45 SECTORSIZE);
46 if (NewBootSector == NULL)
47 return(STATUS_INSUFFICIENT_RESOURCES);
48
49 /* Zero the new bootsector */
50 memset(NewBootSector, 0, SECTORSIZE);
51
52 /* Copy FAT32 BPB to new bootsector */
53 memcpy((NewBootSector + 3),
54 &BootSector->OEMName[0],
55 87); /* FAT32 BPB length (up to (not including) Res2) */
56
57 /* Write sector 0 */
58 FileOffset.QuadPart = 0ULL;
59 Status = NtWriteFile(FileHandle,
60 NULL,
61 NULL,
62 NULL,
63 &IoStatusBlock,
64 NewBootSector,
65 SECTORSIZE,
66 &FileOffset,
67 NULL);
68 if (!NT_SUCCESS(Status))
69 {
70 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
71 RtlFreeHeap(RtlGetProcessHeap(), 0, NewBootSector);
72 return(Status);
73 }
74
75 /* Write backup boot sector */
76 if (BootSector->BootBackup != 0x0000)
77 {
78 FileOffset.QuadPart = (ULONGLONG)((ULONG) BootSector->BootBackup * SECTORSIZE);
79 Status = NtWriteFile(FileHandle,
80 NULL,
81 NULL,
82 NULL,
83 &IoStatusBlock,
84 NewBootSector,
85 SECTORSIZE,
86 &FileOffset,
87 NULL);
88 if (!NT_SUCCESS(Status))
89 {
90 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
91 RtlFreeHeap(RtlGetProcessHeap(), 0, NewBootSector);
92 return(Status);
93 }
94 }
95
96 /* Free the new boot sector */
97 RtlFreeHeap(RtlGetProcessHeap(), 0, NewBootSector);
98
99 return(Status);
100 }
101
102
103 static NTSTATUS
104 Fat32WriteFsInfo(IN HANDLE FileHandle,
105 IN PFAT32_BOOT_SECTOR BootSector)
106 {
107 OBJECT_ATTRIBUTES ObjectAttributes;
108 IO_STATUS_BLOCK IoStatusBlock;
109 UNICODE_STRING Name;
110 NTSTATUS Status;
111 PFAT32_FSINFO FsInfo;
112 LARGE_INTEGER FileOffset;
113
114 /* Allocate buffer for new sector */
115 FsInfo = (PFAT32_FSINFO)RtlAllocateHeap(RtlGetProcessHeap(),
116 0,
117 BootSector->BytesPerSector);
118 if (FsInfo == NULL)
119 return(STATUS_INSUFFICIENT_RESOURCES);
120
121 /* Zero the new sector */
122 memset(FsInfo, 0, BootSector->BytesPerSector);
123
124 FsInfo->LeadSig = 0x41615252;
125 FsInfo->StrucSig = 0x61417272;
126 FsInfo->FreeCount = 0xffffffff;
127 FsInfo->NextFree = 0xffffffff;
128 FsInfo->TrailSig = 0xaa550000;
129
130 /* Write sector */
131 FileOffset.QuadPart = BootSector->FSInfoSector * BootSector->BytesPerSector;
132 Status = NtWriteFile(FileHandle,
133 NULL,
134 NULL,
135 NULL,
136 &IoStatusBlock,
137 FsInfo,
138 BootSector->BytesPerSector,
139 &FileOffset,
140 NULL);
141 if (!NT_SUCCESS(Status))
142 {
143 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
144 RtlFreeHeap(RtlGetProcessHeap(), 0, FsInfo);
145 return(Status);
146 }
147
148 /* Free the new sector buffer */
149 RtlFreeHeap(RtlGetProcessHeap(), 0, FsInfo);
150
151 return(Status);
152 }
153
154
155 static NTSTATUS
156 Fat32WriteFAT(IN HANDLE FileHandle,
157 ULONG SectorOffset,
158 IN PFAT32_BOOT_SECTOR BootSector)
159 {
160 OBJECT_ATTRIBUTES ObjectAttributes;
161 IO_STATUS_BLOCK IoStatusBlock;
162 UNICODE_STRING Name;
163 NTSTATUS Status;
164 PUCHAR Buffer;
165 LARGE_INTEGER FileOffset;
166 ULONG i;
167 ULONG Size;
168 ULONG Sectors;
169
170 /* Allocate buffer */
171 Buffer = (PUCHAR)RtlAllocateHeap(RtlGetProcessHeap(),
172 0,
173 64 * 1024);
174 if (Buffer == NULL)
175 return(STATUS_INSUFFICIENT_RESOURCES);
176
177 /* Zero the buffer */
178 memset(Buffer, 0, 64 * 1024);
179
180 /* FAT cluster 0 */
181 Buffer[0] = 0xf8; /* Media type */
182 Buffer[1] = 0xff;
183 Buffer[2] = 0xff;
184 Buffer[3] = 0x0f;
185 /* FAT cluster 1 */
186 Buffer[4] = 0xff; /* Clean shutdown, no disk read/write errors, end-of-cluster (EOC) mark */
187 Buffer[5] = 0xff;
188 Buffer[6] = 0xff;
189 Buffer[7] = 0x0f;
190 /* FAT cluster 2 */
191 Buffer[8] = 0xff; /* End of root directory */
192 Buffer[9] = 0xff;
193 Buffer[10] = 0xff;
194 Buffer[11] = 0x0f;
195
196 /* Write first sector of the FAT */
197 FileOffset.QuadPart = (SectorOffset + BootSector->ReservedSectors) * BootSector->BytesPerSector;
198 Status = NtWriteFile(FileHandle,
199 NULL,
200 NULL,
201 NULL,
202 &IoStatusBlock,
203 Buffer,
204 BootSector->BytesPerSector,
205 &FileOffset,
206 NULL);
207 if (!NT_SUCCESS(Status))
208 {
209 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
210 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
211 return(Status);
212 }
213
214 /* Zero the begin of the buffer */
215 memset(Buffer, 0, 12);
216
217 /* Zero the rest of the FAT */
218 Sectors = 64 * 1024 / BootSector->BytesPerSector;
219 for (i = 1; i < BootSector->FATSectors32; i += Sectors)
220 {
221 /* Zero some sectors of the FAT */
222 FileOffset.QuadPart = (SectorOffset + BootSector->ReservedSectors + i) * BootSector->BytesPerSector;
223 Size = BootSector->FATSectors32 - i;
224 if (Size > Sectors)
225 {
226 Size = Sectors;
227 }
228 Size *= BootSector->BytesPerSector;
229 Status = NtWriteFile(FileHandle,
230 NULL,
231 NULL,
232 NULL,
233 &IoStatusBlock,
234 Buffer,
235 Size,
236 &FileOffset,
237 NULL);
238 if (!NT_SUCCESS(Status))
239 {
240 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
241 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
242 return(Status);
243 }
244 }
245
246 /* Free the buffer */
247 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
248
249 return(Status);
250 }
251
252
253 static NTSTATUS
254 Fat32WriteRootDirectory(IN HANDLE FileHandle,
255 IN PFAT32_BOOT_SECTOR BootSector)
256 {
257 OBJECT_ATTRIBUTES ObjectAttributes;
258 IO_STATUS_BLOCK IoStatusBlock;
259 NTSTATUS Status;
260 PUCHAR Buffer;
261 LARGE_INTEGER FileOffset;
262 ULONGLONG FirstDataSector;
263 ULONGLONG FirstRootDirSector;
264
265 /* Allocate buffer for the cluster */
266 Buffer = (PUCHAR)RtlAllocateHeap(RtlGetProcessHeap(),
267 0,
268 BootSector->SectorsPerCluster * BootSector->BytesPerSector);
269 if (Buffer == NULL)
270 return(STATUS_INSUFFICIENT_RESOURCES);
271
272 /* Zero the buffer */
273 memset(Buffer, 0, BootSector->SectorsPerCluster * BootSector->BytesPerSector);
274
275 DPRINT("BootSector->ReservedSectors = %lu\n", BootSector->ReservedSectors);
276 DPRINT("BootSector->FATSectors32 = %lu\n", BootSector->FATSectors32);
277 DPRINT("BootSector->RootCluster = %lu\n", BootSector->RootCluster);
278 DPRINT("BootSector->SectorsPerCluster = %lu\n", BootSector->SectorsPerCluster);
279
280 /* Write cluster */
281 FirstDataSector = BootSector->ReservedSectors +
282 (BootSector->FATCount * BootSector->FATSectors32) + 0 /* RootDirSectors */;
283
284 DPRINT("FirstDataSector = %lu\n", FirstDataSector);
285
286 FirstRootDirSector = ((BootSector->RootCluster - 2) * BootSector->SectorsPerCluster) + FirstDataSector;
287 FileOffset.QuadPart = FirstRootDirSector * BootSector->BytesPerSector;
288
289 DPRINT("FirstRootDirSector = %lu\n", FirstRootDirSector);
290 DPRINT("FileOffset = %lu\n", FileOffset.QuadPart);
291
292 Status = NtWriteFile(FileHandle,
293 NULL,
294 NULL,
295 NULL,
296 &IoStatusBlock,
297 Buffer,
298 BootSector->SectorsPerCluster * BootSector->BytesPerSector,
299 &FileOffset,
300 NULL);
301 if (!NT_SUCCESS(Status))
302 {
303 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
304 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
305 return(Status);
306 }
307
308 /* Free the buffer */
309 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
310
311 return(Status);
312 }
313
314
315 NTSTATUS
316 Fat32Format (HANDLE FileHandle,
317 PPARTITION_INFORMATION PartitionInfo,
318 PDISK_GEOMETRY DiskGeometry,
319 PUNICODE_STRING Label,
320 BOOL QuickFormat,
321 DWORD ClusterSize,
322 PFMIFSCALLBACK Callback)
323 {
324 FAT32_BOOT_SECTOR BootSector;
325 ANSI_STRING VolumeLabel;
326 ULONG RootDirSectors;
327 ULONG TmpVal1;
328 ULONG TmpVal2;
329 ULONG TmpVal3;
330 NTSTATUS Status;
331
332 /* Calculate cluster size */
333 if (ClusterSize == 0)
334 {
335 if (PartitionInfo->PartitionLength.QuadPart < 8ULL * 1024ULL * 1024ULL * 1024ULL)
336 {
337 /* Partition < 8GB ==> 4KB Cluster */
338 ClusterSize = 4096;
339 }
340 else if (PartitionInfo->PartitionLength.QuadPart < 16ULL * 1024ULL * 1024ULL * 1024ULL)
341 {
342 /* Partition 8GB - 16GB ==> 8KB Cluster */
343 ClusterSize = 8192;
344 }
345 else if (PartitionInfo->PartitionLength.QuadPart < 32ULL * 1024ULL * 1024ULL * 1024ULL)
346 {
347 /* Partition 16GB - 32GB ==> 16KB Cluster */
348 ClusterSize = 16384;
349 }
350 else
351 {
352 /* Partition >= 32GB ==> 32KB Cluster */
353 ClusterSize = 32768;
354 }
355 }
356
357 memset(&BootSector, 0, sizeof(FAT32_BOOT_SECTOR));
358 memcpy(&BootSector.OEMName[0], "MSWIN4.1", 8);
359 BootSector.BytesPerSector = DiskGeometry->BytesPerSector;
360 BootSector.SectorsPerCluster = ClusterSize / BootSector.BytesPerSector;
361 BootSector.ReservedSectors = 32;
362 BootSector.FATCount = 2;
363 BootSector.RootEntries = 0;
364 BootSector.Sectors = 0;
365 BootSector.Media = 0xf8;
366 BootSector.FATSectors = 0;
367 BootSector.SectorsPerTrack = DiskGeometry->SectorsPerTrack;
368 BootSector.Heads = DiskGeometry->TracksPerCylinder;
369 BootSector.HiddenSectors = DiskGeometry->SectorsPerTrack; //PartitionInfo->HiddenSectors; /* FIXME: Hack! */
370 BootSector.SectorsHuge = PartitionInfo->PartitionLength.QuadPart >>
371 GetShiftCount(BootSector.BytesPerSector); /* Use shifting to avoid 64-bit division */
372 BootSector.FATSectors32 = 0; /* Set later */
373 BootSector.ExtFlag = 0; /* Mirror all FATs */
374 BootSector.FSVersion = 0x0000; /* 0:0 */
375 BootSector.RootCluster = 2;
376 BootSector.FSInfoSector = 1;
377 BootSector.BootBackup = 6;
378 BootSector.Drive = 0xff; /* No BIOS boot drive available */
379 BootSector.ExtBootSignature = 0x29;
380 BootSector.VolumeID = 0x45768798; /* FIXME: */
381 if ((Label == NULL) || (Label->Buffer == NULL))
382 {
383 memcpy(&BootSector.VolumeLabel[0], "NO NAME ", 11);
384 }
385 else
386 {
387 RtlUnicodeStringToAnsiString(&VolumeLabel, Label, TRUE);
388 memset(&BootSector.VolumeLabel[0], ' ', 11);
389 memcpy(&BootSector.VolumeLabel[0], VolumeLabel.Buffer,
390 VolumeLabel.Length < 11 ? VolumeLabel.Length : 11);
391 RtlFreeAnsiString(&VolumeLabel);
392 }
393 memcpy(&BootSector.SysType[0], "FAT32 ", 8);
394
395 RootDirSectors = ((BootSector.RootEntries * 32) +
396 (BootSector.BytesPerSector - 1)) / BootSector.BytesPerSector;
397 TmpVal1 = BootSector.SectorsHuge - (BootSector.ReservedSectors + RootDirSectors);
398 TmpVal2 = (256 * BootSector.SectorsPerCluster) + BootSector.FATCount;
399 if (TRUE /* FAT32 */)
400 {
401 TmpVal2 = 0;
402 do
403 {
404 if (TmpVal2 == 0)
405 {
406 TmpVal3 = 0xffffffff;
407 }
408 else
409 {
410 TmpVal3 = TmpVal2;
411 }
412 TmpVal2 = ((TmpVal1 - TmpVal2 * BootSector.FATCount) / BootSector.SectorsPerCluster) + 2;
413 TmpVal2 = (sizeof(ULONG) * TmpVal2 + BootSector.BytesPerSector - 1) / BootSector.BytesPerSector;
414 }
415 while (TmpVal3 > TmpVal2);
416 BootSector.FATSectors32 = TmpVal2;
417 }
418
419 Status = Fat32WriteBootSector(FileHandle,
420 &BootSector);
421 if (!NT_SUCCESS(Status))
422 {
423 DPRINT("Fat32WriteBootSector() failed with status 0x%.08x\n", Status);
424 return Status;
425 }
426
427 Status = Fat32WriteFsInfo(FileHandle,
428 &BootSector);
429 if (!NT_SUCCESS(Status))
430 {
431 DPRINT("Fat32WriteFsInfo() failed with status 0x%.08x\n", Status);
432 return Status;
433 }
434
435 /* Write first FAT copy */
436 Status = Fat32WriteFAT(FileHandle,
437 0,
438 &BootSector);
439 if (!NT_SUCCESS(Status))
440 {
441 DPRINT("Fat32WriteFAT() failed with status 0x%.08x\n", Status);
442 return Status;
443 }
444
445 /* Write second FAT copy */
446 Status = Fat32WriteFAT(FileHandle,
447 BootSector.FATSectors32,
448 &BootSector);
449 if (!NT_SUCCESS(Status))
450 {
451 DPRINT("Fat32WriteFAT() failed with status 0x%.08x.\n", Status);
452 return Status;
453 }
454
455 Status = Fat32WriteRootDirectory(FileHandle,
456 &BootSector);
457 if (!NT_SUCCESS(Status))
458 {
459 DPRINT("Fat32WriteRootDirectory() failed with status 0x%.08x\n", Status);
460 }
461
462 return Status;
463 }