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