Revert 45697:
[reactos.git] / lib / fslib / vfatxlib / fatx.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS VFATX filesystem library
4 * FILE: fatx.c
5 * PURPOSE: Fatx support
6 * PROGRAMMERS:
7 * REVISIONS:
8 */
9 #include "vfatxlib.h"
10
11 #define NDEBUG
12 #include <debug.h>
13
14 static ULONG
15 GetShiftCount(ULONG Value)
16 {
17 ULONG i = 1;
18 while (Value > 0)
19 {
20 i++;
21 Value /= 2;
22 }
23 return i - 2;
24 }
25
26
27 static ULONG
28 CalcVolumeSerialNumber(VOID)
29 {
30 LARGE_INTEGER SystemTime;
31 TIME_FIELDS TimeFields;
32 ULONG Serial;
33 PUCHAR Buffer;
34
35 NtQuerySystemTime (&SystemTime);
36 RtlTimeToTimeFields (&SystemTime, &TimeFields);
37
38 Buffer = (PUCHAR)&Serial;
39 Buffer[0] = (UCHAR)(TimeFields.Year & 0xFF) + (UCHAR)(TimeFields.Hour & 0xFF);
40 Buffer[1] = (UCHAR)(TimeFields.Year >> 8) + (UCHAR)(TimeFields.Minute & 0xFF);
41 Buffer[2] = (UCHAR)(TimeFields.Month & 0xFF) + (UCHAR)(TimeFields.Second & 0xFF);
42 Buffer[3] = (UCHAR)(TimeFields.Day & 0xFF) + (UCHAR)(TimeFields.Milliseconds & 0xFF);
43
44 return Serial;
45 }
46
47
48 static NTSTATUS
49 FatxWriteBootSector (IN HANDLE FileHandle,
50 IN PFATX_BOOT_SECTOR BootSector,
51 IN OUT PFORMAT_CONTEXT Context)
52 {
53 IO_STATUS_BLOCK IoStatusBlock;
54 NTSTATUS Status;
55 PUCHAR NewBootSector;
56 LARGE_INTEGER FileOffset;
57
58 /* Allocate buffer for new bootsector */
59 NewBootSector = (PUCHAR)RtlAllocateHeap(RtlGetProcessHeap(),
60 0,
61 sizeof(FATX_BOOT_SECTOR));
62 if (NewBootSector == NULL)
63 return(STATUS_INSUFFICIENT_RESOURCES);
64
65 /* Zero the new bootsector */
66 memset(NewBootSector, 0, sizeof(FATX_BOOT_SECTOR));
67
68 /* Copy FAT16 BPB to new bootsector */
69 memcpy(NewBootSector, BootSector, 18); /* FAT16 BPB length (up to (not including) Res2) */
70
71 /* Write sector 0 */
72 FileOffset.QuadPart = 0ULL;
73 Status = NtWriteFile(FileHandle,
74 NULL,
75 NULL,
76 NULL,
77 &IoStatusBlock,
78 NewBootSector,
79 sizeof(FATX_BOOT_SECTOR),
80 &FileOffset,
81 NULL);
82 if (!NT_SUCCESS(Status))
83 {
84 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
85 RtlFreeHeap(RtlGetProcessHeap(), 0, NewBootSector);
86 return Status;
87 }
88
89 VfatxUpdateProgress (Context, 1);
90
91 /* Free the new boot sector */
92 RtlFreeHeap(RtlGetProcessHeap(), 0, NewBootSector);
93
94 return Status;
95 }
96
97
98 static NTSTATUS
99 Fatx16WriteFAT (IN HANDLE FileHandle,
100 IN ULONG SectorOffset,
101 IN ULONG FATSectors,
102 IN OUT PFORMAT_CONTEXT Context)
103 {
104 IO_STATUS_BLOCK IoStatusBlock;
105 NTSTATUS Status;
106 PUCHAR Buffer;
107 LARGE_INTEGER FileOffset;
108 ULONG i;
109 ULONG Sectors;
110
111 /* Allocate buffer */
112 Buffer = (PUCHAR)RtlAllocateHeap(RtlGetProcessHeap(),
113 0,
114 32 * 1024);
115 if (Buffer == NULL)
116 return(STATUS_INSUFFICIENT_RESOURCES);
117
118 /* Zero the buffer */
119 memset(Buffer, 0, 32 * 1024);
120
121 /* FAT cluster 0 */
122 Buffer[0] = 0xf8; /* Media type */
123 Buffer[1] = 0xff;
124
125 /* FAT cluster 1 */
126 Buffer[2] = 0xff; /* Clean shutdown, no disk read/write errors, end-of-cluster (EOC) mark */
127 Buffer[3] = 0xff;
128
129 /* Write first sector of the FAT */
130 FileOffset.QuadPart = (SectorOffset * 512) + sizeof(FATX_BOOT_SECTOR);
131 Status = NtWriteFile(FileHandle,
132 NULL,
133 NULL,
134 NULL,
135 &IoStatusBlock,
136 Buffer,
137 512,
138 &FileOffset,
139 NULL);
140 if (!NT_SUCCESS(Status))
141 {
142 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
143 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
144 return(Status);
145 }
146
147 VfatxUpdateProgress (Context, 1);
148
149 /* Zero the begin of the buffer */
150 memset(Buffer, 0, 4);
151
152 /* Zero the rest of the FAT */
153 Sectors = 32 * 1024 / 512;
154 for (i = 1; i < FATSectors; i += Sectors)
155 {
156 /* Zero some sectors of the FAT */
157 FileOffset.QuadPart = (SectorOffset + i) * 512 + sizeof(FATX_BOOT_SECTOR) ;
158 if ((FATSectors - i) <= Sectors)
159 {
160 Sectors = FATSectors - i;
161 }
162
163 Status = NtWriteFile(FileHandle,
164 NULL,
165 NULL,
166 NULL,
167 &IoStatusBlock,
168 Buffer,
169 Sectors * 512,
170 &FileOffset,
171 NULL);
172 if (!NT_SUCCESS(Status))
173 {
174 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
175 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
176 return(Status);
177 }
178
179 VfatxUpdateProgress (Context, Sectors);
180 }
181
182 /* Free the buffer */
183 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
184
185 return(Status);
186 }
187
188 static NTSTATUS
189 Fatx32WriteFAT (IN HANDLE FileHandle,
190 IN ULONG SectorOffset,
191 IN ULONG FATSectors,
192 IN OUT PFORMAT_CONTEXT Context)
193 {
194 IO_STATUS_BLOCK IoStatusBlock;
195 NTSTATUS Status;
196 PUCHAR Buffer;
197 LARGE_INTEGER FileOffset;
198 ULONG i;
199 ULONG Sectors;
200
201 /* Allocate buffer */
202 Buffer = (PUCHAR)RtlAllocateHeap(RtlGetProcessHeap(),
203 0,
204 64 * 1024);
205 if (Buffer == NULL)
206 return(STATUS_INSUFFICIENT_RESOURCES);
207
208 /* Zero the buffer */
209 memset(Buffer, 0, 64 * 1024);
210
211 /* FAT cluster 0 */
212 Buffer[0] = 0xf8; /* Media type */
213 Buffer[1] = 0xff;
214 Buffer[2] = 0xff;
215 Buffer[3] = 0x0f;
216 /* FAT cluster 1 */
217 Buffer[4] = 0xff; /* Clean shutdown, no disk read/write errors, end-of-cluster (EOC) mark */
218 Buffer[5] = 0xff;
219 Buffer[6] = 0xff;
220 Buffer[7] = 0x0f;
221
222 /* Write first sector of the FAT */
223 FileOffset.QuadPart = (SectorOffset * 512) + sizeof(FATX_BOOT_SECTOR);
224 Status = NtWriteFile(FileHandle,
225 NULL,
226 NULL,
227 NULL,
228 &IoStatusBlock,
229 Buffer,
230 512,
231 &FileOffset,
232 NULL);
233 if (!NT_SUCCESS(Status))
234 {
235 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
236 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
237 return(Status);
238 }
239
240 VfatxUpdateProgress (Context, 1);
241
242 /* Zero the begin of the buffer */
243 memset(Buffer, 0, 8);
244
245 /* Zero the rest of the FAT */
246 Sectors = 64 * 1024 / 512;
247 for (i = 1; i < FATSectors; i += Sectors)
248 {
249 /* Zero some sectors of the FAT */
250 FileOffset.QuadPart = (SectorOffset + i) * 512 + sizeof(FATX_BOOT_SECTOR);
251
252 if ((FATSectors - i) <= Sectors)
253 {
254 Sectors = FATSectors - i;
255 }
256
257 Status = NtWriteFile(FileHandle,
258 NULL,
259 NULL,
260 NULL,
261 &IoStatusBlock,
262 Buffer,
263 Sectors * 512,
264 &FileOffset,
265 NULL);
266 if (!NT_SUCCESS(Status))
267 {
268 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
269 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
270 return(Status);
271 }
272
273 VfatxUpdateProgress (Context, Sectors);
274 }
275
276 /* Free the buffer */
277 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
278
279 return(Status);
280 }
281
282 static NTSTATUS
283 FatxWriteRootDirectory (IN HANDLE FileHandle,
284 IN ULONG FATSectors,
285 IN OUT PFORMAT_CONTEXT Context)
286 {
287 IO_STATUS_BLOCK IoStatusBlock;
288 NTSTATUS Status = STATUS_SUCCESS;
289 PUCHAR Buffer;
290 LARGE_INTEGER FileOffset;
291 ULONG FirstRootDirSector;
292 ULONG RootDirSectors;
293
294 /* Write cluster */
295 RootDirSectors = 256 * 64 / 512;
296 FirstRootDirSector = sizeof(FATX_BOOT_SECTOR) / 512 + FATSectors;
297
298 DPRINT("RootDirSectors = %lu\n", RootDirSectors);
299 DPRINT("FirstRootDirSector = %lu\n", FirstRootDirSector);
300
301 /* Allocate buffer for the cluster */
302 Buffer = (PUCHAR)RtlAllocateHeap(RtlGetProcessHeap(),
303 0,
304 RootDirSectors * 512);
305 if (Buffer == NULL)
306 return(STATUS_INSUFFICIENT_RESOURCES);
307
308 /* Zero the buffer */
309 memset(Buffer, 0xff, RootDirSectors * 512);
310
311 /* Zero some sectors of the root directory */
312 FileOffset.QuadPart = FirstRootDirSector * 512;
313
314 Status = NtWriteFile(FileHandle,
315 NULL,
316 NULL,
317 NULL,
318 &IoStatusBlock,
319 Buffer,
320 RootDirSectors * 512,
321 &FileOffset,
322 NULL);
323 if (!NT_SUCCESS(Status))
324 {
325 DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
326 }
327
328 /* Free the buffer */
329 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
330
331 return(Status);
332 }
333
334
335 NTSTATUS
336 FatxFormat (HANDLE FileHandle,
337 PPARTITION_INFORMATION PartitionInfo,
338 PDISK_GEOMETRY DiskGeometry,
339 BOOLEAN QuickFormat,
340 PFORMAT_CONTEXT Context)
341 {
342 FATX_BOOT_SECTOR BootSector;
343 ULONGLONG SectorCount;
344 ULONG ClusterCount;
345 ULONG RootDirSectors;
346 ULONG FATSectors;
347
348 NTSTATUS Status;
349
350 SectorCount = PartitionInfo->PartitionLength.QuadPart >> GetShiftCount(512); /* Use shifting to avoid 64-bit division */
351
352 memset(&BootSector, 0, sizeof(FATX_BOOT_SECTOR));
353 memcpy(&BootSector.SysType[0], "FATX", 4);
354 BootSector.SectorsPerCluster = 32;
355 BootSector.FATCount = 1;
356 BootSector.VolumeID = CalcVolumeSerialNumber();
357 RootDirSectors = 256 * 64 / 512;
358
359 /* Calculate number of FAT sectors */
360 ClusterCount = SectorCount >> GetShiftCount(32);
361
362 if (ClusterCount > 65525)
363 {
364 FATSectors = (((ClusterCount * 4) + 4095) & ~4095) >> GetShiftCount(512);
365 }
366 else
367 {
368 FATSectors = (((ClusterCount * 2) + 4095) & ~4095) >> GetShiftCount(512);
369 }
370 DPRINT("FATSectors = %hu\n", FATSectors);
371
372 /* Init context data */
373 if (QuickFormat)
374 {
375 Context->TotalSectorCount =
376 1 + FATSectors + RootDirSectors;
377 }
378 else
379 {
380 Context->TotalSectorCount = SectorCount;
381 }
382
383 Status = FatxWriteBootSector (FileHandle,
384 &BootSector,
385 Context);
386 if (!NT_SUCCESS(Status))
387 {
388 DPRINT("FatxWriteBootSector() failed with status 0x%.08x\n", Status);
389 return Status;
390 }
391
392 /* Write first FAT copy */
393 if (ClusterCount > 65525)
394 {
395 Status = Fatx32WriteFAT (FileHandle,
396 0,
397 FATSectors,
398 Context);
399 }
400 else
401 {
402 Status = Fatx16WriteFAT (FileHandle,
403 0,
404 FATSectors,
405 Context);
406 }
407 if (!NT_SUCCESS(Status))
408 {
409 DPRINT("FatxWriteFAT() failed with status 0x%.08x\n", Status);
410 return Status;
411 }
412
413 Status = FatxWriteRootDirectory (FileHandle,
414 FATSectors,
415 Context);
416 if (!NT_SUCCESS(Status))
417 {
418 DPRINT("FatxWriteRootDirectory() failed with status 0x%.08x\n", Status);
419 }
420
421 if (!QuickFormat)
422 {
423 /* FIXME: Fill remaining sectors */
424 }
425
426 return Status;
427 }