1 /*
2 * Copyright 2015, François Revol <revol@free.fr>
3 * Copyright (c) 2002 Marcus Overhagen <marcus@overhagen.de>, Haiku project
4 * Copyright 2024, Haiku, Inc. All rights reserved.
5 *
6 * Distributed under the terms of the MIT License.
7 */
8
9
10 #define MKDOS
11 #include "mkdos.h"
12
13 #ifdef FS_SHELL
14 #include "fssh_api_wrapper.h"
15 #else
16 #include <stdlib.h>
17
18 #include <ByteOrder.h>
19 #include <KernelExport.h>
20 #include <driver_settings.h>
21 #endif // !FS_SHELL
22
23 #include "dosfs.h"
24 #include "support.h"
25
26 #ifdef USER
27 #define dprintf(x...) ;
28 #endif
29 #define WITH_FLOPPY_SUPPORT
30
31
32 static void
create_volume_label_sector(void * sector,const char * label)33 create_volume_label_sector(void *sector, const char *label)
34 {
35 // create a volume name directory entry in the 512 byte sector
36 // XXX convert from UTF8, and check for valid characters
37 // XXX this could be changed to use long file name entrys,
38 // XXX but the dosfs would have to be updated, too
39
40 struct direntry* d = (struct direntry*)sector;
41 memset(d, 0, sizeof(*d));
42 memset(d->deName, 0x20, 11);
43 memcpy(d->deName, label, min_c(11, strlen(label)));
44 d->deAttributes = 0x08;
45 }
46
47
48 status_t
parse_initialize_parameters(const char * parameterString,initialize_parameters & parameters)49 parse_initialize_parameters(const char* parameterString,
50 initialize_parameters& parameters)
51 {
52 parameters.flags = 0;
53 parameters.verbose = false;
54
55 void *handle = parse_driver_settings_string(parameterString);
56 if (handle == NULL)
57 return B_ERROR;
58
59 if (get_driver_boolean_parameter(handle, "verbose", false, true))
60 parameters.verbose = true;
61
62 const char *string = get_driver_parameter(handle, "fat",
63 NULL, NULL);
64 uint32 fatBits = 0;
65 if (string != NULL)
66 fatBits = strtoul(string, NULL, 0);
67
68 unload_driver_settings(handle);
69
70 if (fatBits != 0 && fatBits != 12 && fatBits != 16 && fatBits != 32) {
71 dprintf("mkdos error: fat must be 12, 16, or 32 bits\n");
72 return B_BAD_VALUE;
73 }
74
75 parameters.fatBits = fatBits;
76
77 return B_OK;
78 }
79
80
81 status_t
_dosfs_initialize(int fd,partition_id partitionID,const char * name,const char * parameterString,off_t partitionSize,disk_job_id job)82 _dosfs_initialize(int fd, partition_id partitionID, const char* name, const char* parameterString,
83 off_t partitionSize, disk_job_id job)
84 {
85 dprintf("dosfs_initialize(%d, , '%s', '%s', %" B_PRIdOFF ")\n", fd, name, parameterString,
86 partitionSize);
87 if (sizeof(bootsector1216) != 512 || sizeof(bootsector32) != 512
88 || sizeof(fsinfosector32) != 512) {
89 dprintf("dosfs: compilation error: struct alignment wrong\n");
90 return B_BAD_VALUE;
91 }
92
93 // parse parameters
94 initialize_parameters parameters;
95 status_t status = parse_initialize_parameters(parameterString, parameters);
96 if (status != B_OK)
97 return status;
98
99 update_disk_device_job_progress(job, 0);
100
101 int fatbits = parameters.fatBits;
102 char label[LABEL_CSTRING];
103 strlcpy(label, name, LABEL_CSTRING);
104 status = label_to_fat(label);
105 if (status != B_OK)
106 return status;
107
108 if (fatbits != 0 && fatbits != 12 && fatbits != 16 && fatbits != 32) {
109 dprintf("dosfs Error: don't know how to create a %d bit fat\n", fatbits);
110 return B_ERROR;
111 }
112
113 // initialize the volume
114 bool isRawDevice;
115 bool hasBiosGeometry;
116 bool hasDeviceGeometry;
117 bool hasPartitionInfo;
118 device_geometry biosGeometry;
119 device_geometry deviceGeometry;
120 partition_info partitionInfo;
121
122 isRawDevice = 0;//0 != strstr(device, "/raw");
123 hasBiosGeometry = B_OK == ioctl(fd, B_GET_BIOS_GEOMETRY, &biosGeometry,
124 sizeof(biosGeometry));
125 hasDeviceGeometry = B_OK == ioctl(fd, B_GET_GEOMETRY, &deviceGeometry,
126 sizeof(deviceGeometry));
127 hasPartitionInfo = B_OK == ioctl(fd, B_GET_PARTITION_INFO, &partitionInfo,
128 sizeof(partitionInfo));
129
130 if (!isRawDevice && !hasBiosGeometry && !hasDeviceGeometry
131 && !hasPartitionInfo) {
132 isRawDevice = true;
133 }
134
135 if (hasBiosGeometry) {
136 dprintf("dosfs: bios geometry: %" B_PRIu32 " heads, "
137 "%" B_PRIu32 " cylinders, "
138 "%" B_PRIu32 " sectors/track, "
139 "%" B_PRIu32 " bytes/sector\n",
140 biosGeometry.head_count,
141 biosGeometry.cylinder_count,
142 biosGeometry.sectors_per_track,
143 biosGeometry.bytes_per_sector);
144 }
145 if (hasDeviceGeometry) {
146 dprintf("dosfs: device geometry: %" B_PRIu32 " heads, "
147 "%" B_PRIu32 " cylinders, "
148 "%" B_PRIu32 " sectors/track, "
149 "%" B_PRIu32 " bytes/sector\n",
150 deviceGeometry.head_count,
151 deviceGeometry.cylinder_count,
152 deviceGeometry.sectors_per_track,
153 deviceGeometry.bytes_per_sector);
154 }
155 if (hasPartitionInfo) {
156 dprintf("dosfs: partition info: start at %" B_PRIdOFF " bytes "
157 "(%" B_PRIdOFF " sectors), "
158 "%" B_PRIdOFF " KB, "
159 "%" B_PRIdOFF " MB, "
160 "%" B_PRIdOFF " GB\n",
161 partitionInfo.offset,
162 partitionInfo.offset / 512,
163 partitionInfo.offset / 1024,
164 partitionInfo.offset / (1024 * 1024),
165 partitionInfo.offset / (1024 * 1024 * 1024));
166 dprintf("dosfs: partition info: size %" B_PRIdOFF " bytes, "
167 "%" B_PRIdOFF " KB, "
168 "%" B_PRIdOFF " MB, "
169 "%" B_PRIdOFF " GB\n",
170 partitionInfo.size,
171 partitionInfo.size / 1024,
172 partitionInfo.size / (1024 * 1024),
173 partitionInfo.size / (1024 * 1024 * 1024));
174 }
175
176 if (!isRawDevice && !hasPartitionInfo)
177 dprintf("dosfs Warning: couldn't get partition information\n");
178
179 if ((hasBiosGeometry && biosGeometry.bytes_per_sector != 512)
180 || (hasDeviceGeometry && deviceGeometry.bytes_per_sector != 512)) {
181 dprintf("dosfs Error: geometry block size not 512 bytes\n");
182 return B_ERROR;
183 } else if (hasPartitionInfo && partitionInfo.logical_block_size != 512) {
184 dprintf("dosfs: partition logical block size is not 512, "
185 "it's %" B_PRId32 " bytes\n",
186 partitionInfo.logical_block_size);
187 }
188
189 if (hasDeviceGeometry && deviceGeometry.read_only) {
190 dprintf("dosfs Error: this is a read-only device\n");
191 return B_ERROR;
192 }
193 if (hasDeviceGeometry && deviceGeometry.write_once) {
194 dprintf("dosfs Error: this is a write-once device\n");
195 return B_ERROR;
196 }
197 uint64 size = 0;
198
199 if (hasPartitionInfo) {
200 size = partitionInfo.size;
201 } else if (hasDeviceGeometry) {
202 size = uint64(deviceGeometry.bytes_per_sector)
203 * deviceGeometry.sectors_per_track * deviceGeometry.cylinder_count
204 * deviceGeometry.head_count;
205 } else if (hasBiosGeometry) {
206 size = uint64(biosGeometry.bytes_per_sector)
207 * biosGeometry.sectors_per_track * biosGeometry.cylinder_count
208 * biosGeometry.head_count;
209 } else {
210 // maybe it's just a file
211 struct stat stat;
212 if (fstat(fd, &stat) < 0) {
213 dprintf("dosfs Error: couldn't get device partition or geometry "
214 "information, nor size\n");
215 return B_ERROR;
216 }
217 size = stat.st_size;
218 }
219
220 dprintf("dosfs: size = %" B_PRIu64 " bytes "
221 "(%" B_PRIu64 " sectors), "
222 "%" B_PRIu64 " KB, "
223 "%" B_PRIu64 " MB, "
224 "%" B_PRIu64 " GB\n",
225 size,
226 size / 512,
227 size / 1024,
228 size / (1024 * 1024),
229 size / (1024 * 1024 * 1024));
230
231 uint64 sectorCount = size / 512;
232 if (sectorCount > UINT_MAX) {
233 // The FAT spec only provides 32 bits to store the sector count on disk.
234 dprintf("dosfs Warning: sector count %" B_PRIu64 " won't fit in the FAT BPB. Only the "
235 "first %u sectors will be used\n", sectorCount, UINT_MAX);
236 sectorCount = UINT_MAX;
237 size = sectorCount * 512;
238 }
239
240 if (fatbits == 0) {
241 //auto determine fat type
242 if (isRawDevice && size <= FLOPPY_MAX_SIZE
243 && (size / FAT12_CLUSTER_MAX_SIZE) < FAT12_MAX_CLUSTER_COUNT) {
244 fatbits = 12;
245 } else if ((size / CLUSTER_MAX_SIZE) < FAT16_MAX_CLUSTER_COUNT) {
246 fatbits = 16;
247 } else if ((size / CLUSTER_MAX_SIZE) < FAT32_MAX_CLUSTER_COUNT) {
248 fatbits = 32;
249 }
250 }
251
252 if (fatbits == 0) {
253 dprintf("dosfs Error: device too large for 32 bit fat\n");
254 return B_ERROR;
255 }
256
257 int sectorPerCluster;
258
259 sectorPerCluster = 0;
260 if (fatbits == 12) {
261 sectorPerCluster = 0;
262 if (size < 16777216LL)
263 sectorPerCluster = 8;
264 if (size <= 2949120)
265 sectorPerCluster = 2;
266 if (size <= 1474560)
267 sectorPerCluster = 1;
268 if (size <= 737280) {
269 // We follow Microsoft guidance in increasing cluster size for the smallest disks.
270 // The idea was probably to keep the FAT from taking up a too much of a small disk.
271 sectorPerCluster = 2;
272 }
273 } else if (fatbits == 16) {
274 sectorPerCluster = 0; //larger than 2 GB must fail
275 if (size <= (2048 * 1024 * 1024LL)) // up to 2GB, use 32k clusters
276 sectorPerCluster = 64;
277 if (size <= (1024 * 1024 * 1024LL)) // up to 1GB, use 16k clusters
278 sectorPerCluster = 32;
279 if (size <= (512 * 1024 * 1024LL)) // up to 512MB, use 8k clusters
280 sectorPerCluster = 16;
281 if (size <= (256 * 1024 * 1024LL)) // up to 256MB, use 4k clusters
282 sectorPerCluster = 8;
283 if (size <= (128 * 1024 * 1024LL)) // up to 128MB, use 2k clusters
284 sectorPerCluster = 4;
285 if (size <= (16 * 1024 * 1024LL)) // up to 16MB, use 1k clusters
286 sectorPerCluster = 2;
287 if (size <= 4182016LL) // smaller than 4.1 MB must fail
288 sectorPerCluster = 0;
289 } else if (fatbits == 32) {
290 sectorPerCluster = 64; // default is 32k clusters
291 if (size <= (32 * 1024 * 1024 * 1024LL)) {
292 // up to 32GB, use 16k clusters
293 sectorPerCluster = 32;
294 }
295 if (size <= (16 * 1024 * 1024 * 1024LL)) {
296 // up to 16GB, use 8k clusters
297 sectorPerCluster = 16;
298 }
299 if (size <= (8 * 1024 * 1024 * 1024LL)) {
300 // up to 8GB, use 4k clusters
301 sectorPerCluster = 8;
302 }
303 if (size <= (532480 * 512LL)) {
304 // up to 260 MB, use 0.5k clusters
305 sectorPerCluster = 1;
306 }
307 if (size <= (66600 * 512LL)) {
308 // smaller than 32.5 MB must fail
309 sectorPerCluster = 0;
310 }
311 }
312
313 if (sectorPerCluster == 0) {
314 dprintf("dosfs Error: failed to determine sector per cluster value, "
315 "partition too large for %d bit fat\n",fatbits);
316 return B_ERROR;
317 }
318
319 int reservedSectorCount = 0; // avoid compiler warning
320 int rootEntryCount = 0; // avoid compiler warning
321 int numFATs;
322 int sectorSize;
323 uint8 biosDriveId;
324
325 // get bios drive-id, or use 0x80
326 if (B_OK != ioctl(fd, B_GET_BIOS_DRIVE_ID, &biosDriveId,
327 sizeof(biosDriveId))) {
328 biosDriveId = 0x80;
329 } else {
330 dprintf("dosfs: bios drive id: 0x%02x\n", (int)biosDriveId);
331 }
332
333 // default parameters for the bootsector
334 numFATs = 2;
335 sectorSize = 512;
336 if (fatbits == 12 || fatbits == 16)
337 reservedSectorCount = 1;
338 if (fatbits == 32)
339 reservedSectorCount = 32;
340 if (fatbits == 12)
341 rootEntryCount = 512;
342 if (fatbits == 16)
343 rootEntryCount = 512;
344 if (fatbits == 32)
345 rootEntryCount = 0;
346
347 // Determine FATSize
348 // calculation done as MS recommends
349 uint64 dskSize = size / sectorSize;
350 uint32 rootDirSectors = ((rootEntryCount * 32) + (sectorSize - 1))
351 / sectorSize;
352 uint64 tmpVal1 = dskSize - (reservedSectorCount + rootDirSectors);
353 uint64 tmpVal2 = (256 * sectorPerCluster) + numFATs;
354 if (fatbits == 32)
355 tmpVal2 = tmpVal2 / 2;
356 uint32 FATSize = (tmpVal1 + (tmpVal2 - 1)) / tmpVal2;
357 // FATSize should now contain the size of *one* FAT, measured in sectors
358 // RootDirSectors should now contain the size of the fat12/16 root
359 // directory, measured in sectors
360
361 // Now that clusters can be counted, verify cluster count is compatible with the FAT type
362 uint64 dataSec = sectorCount - (reservedSectorCount + (numFATs * FATSize) + rootDirSectors);
363 uint64 clusterCount = dataSec / sectorPerCluster;
364 if (fatbits == 12 && clusterCount > FAT12_MAX_CLUSTER_COUNT) {
365 dprintf("dosfs Error: cluster count (%" B_PRIu64 ") exceeds FAT12 limit.\n", clusterCount);
366 return B_BAD_VALUE;
367 }
368 if (fatbits == 16 && clusterCount > FAT16_MAX_CLUSTER_COUNT) {
369 dprintf("dosfs Error: cluster count (%" B_PRIu64 ") exceeds FAT16 limit.\n", clusterCount);
370 return B_BAD_VALUE;
371 }
372 if (fatbits == 32 && clusterCount > FAT32_MAX_CLUSTER_COUNT) {
373 dprintf("dosfs Error: cluster count (%" B_PRIu64 ") exceeds FAT32 limit.\n", clusterCount);
374 return B_BAD_VALUE;
375 }
376
377 dprintf("dosfs: fatbits = %d, clustersize = %d\n", fatbits, sectorPerCluster * 512);
378 dprintf("dosfs: FAT size is %" B_PRIu32 " sectors\n", FATSize);
379 dprintf("dosfs: disk label: %s\n", label);
380
381
382
383 if (status < B_OK) {
384 dprintf("dosfs: Initializing volume failed: %s\n", strerror(status));
385 return status;
386 }
387
388 char bootsector[512];
389 memset(bootsector,0x00,512);
390 memcpy(bootsector + BOOTJMP_START_OFFSET, bootjmp, sizeof(bootjmp));
391 memcpy(bootsector + BOOTCODE_START_OFFSET, bootcode, sizeof(bootcode));
392
393 if (fatbits == 32) {
394 bootsector32 *bs = (bootsector32 *)bootsector;
395 uint16 temp16;
396 uint32 temp32;
397 memcpy(bs->BS_OEMName,"Haiku ",8);
398 bs->BPB_BytsPerSec = B_HOST_TO_LENDIAN_INT16(sectorSize);
399 bs->BPB_SecPerClus = sectorPerCluster;
400 bs->BPB_RsvdSecCnt = B_HOST_TO_LENDIAN_INT16(reservedSectorCount);
401 bs->BPB_NumFATs = numFATs;
402 bs->BPB_RootEntCnt = B_HOST_TO_LENDIAN_INT16(rootEntryCount);
403 bs->BPB_TotSec16 = B_HOST_TO_LENDIAN_INT16(0);
404 bs->BPB_Media = hasDeviceGeometry && deviceGeometry.removable ? 0xF0 : 0xF8;
405 bs->BPB_FATSz16 = B_HOST_TO_LENDIAN_INT16(0);
406 temp16 = hasBiosGeometry ? biosGeometry.sectors_per_track : 63;
407 bs->BPB_SecPerTrk = B_HOST_TO_LENDIAN_INT16(temp16);
408 temp16 = hasBiosGeometry ? biosGeometry.head_count : 255;
409 bs->BPB_NumHeads = B_HOST_TO_LENDIAN_INT16(temp16);
410 temp32 = hasPartitionInfo ? (partitionInfo.size / 512) : 0;
411 bs->BPB_HiddSec = B_HOST_TO_LENDIAN_INT32(temp32);
412 bs->BPB_TotSec32 = B_HOST_TO_LENDIAN_INT32(sectorCount);
413 bs->BPB_FATSz32 = B_HOST_TO_LENDIAN_INT32(FATSize);
414 bs->BPB_ExtFlags = B_HOST_TO_LENDIAN_INT16(0);
415 bs->BPB_FSVer = B_HOST_TO_LENDIAN_INT16(0);
416 bs->BPB_RootClus = B_HOST_TO_LENDIAN_INT32(FAT32_ROOT_CLUSTER);
417 bs->BPB_FSInfo = B_HOST_TO_LENDIAN_INT16(FSINFO_SECTOR_NUM);
418 bs->BPB_BkBootSec = B_HOST_TO_LENDIAN_INT16(BACKUP_SECTOR_NUM);
419 memset(bs->BPB_Reserved,0,12);
420 bs->BS_DrvNum = biosDriveId;
421 bs->BS_Reserved1 = 0x00;
422 bs->BS_BootSig = 0x29;
423 uint32 volID = B_HOST_TO_LENDIAN_INT32(system_time());
424 memcpy(bs->BS_VolID, &volID, 4);
425 memset(bs->BS_VolLab, 0x20, 11);
426 memcpy(bs->BS_VolLab, label, min_c(11, strlen(label)));
427 memcpy(bs->BS_FilSysType,"FAT32 ",8);
428 bs->signature = B_HOST_TO_LENDIAN_INT16(0xAA55);
429 } else {
430 bootsector1216 *bs = (bootsector1216 *)bootsector;
431 uint16 temp16;
432 uint32 temp32;
433 memcpy(bs->BS_OEMName, "Haiku ", 8);
434 bs->BPB_BytsPerSec = B_HOST_TO_LENDIAN_INT16(sectorSize);
435 bs->BPB_SecPerClus = sectorPerCluster;
436 bs->BPB_RsvdSecCnt = B_HOST_TO_LENDIAN_INT16(reservedSectorCount);
437 bs->BPB_NumFATs = numFATs;
438 bs->BPB_RootEntCnt = B_HOST_TO_LENDIAN_INT16(rootEntryCount);
439 temp16 = (sectorCount <= 65535) ? sectorCount : 0;
440 bs->BPB_TotSec16 = B_HOST_TO_LENDIAN_INT16(temp16);
441 bs->BPB_Media = hasDeviceGeometry && deviceGeometry.removable ? 0xF0 : 0xF8;
442 bs->BPB_FATSz16 = B_HOST_TO_LENDIAN_INT16(FATSize);
443 temp16 = hasBiosGeometry ? biosGeometry.sectors_per_track : 63;
444 bs->BPB_SecPerTrk = B_HOST_TO_LENDIAN_INT16(temp16);
445 temp16 = hasBiosGeometry ? biosGeometry.head_count : 255;
446 bs->BPB_NumHeads = B_HOST_TO_LENDIAN_INT16(temp16);
447 temp32 = hasPartitionInfo ? (partitionInfo.size / 512) : 0;
448 bs->BPB_HiddSec = B_HOST_TO_LENDIAN_INT32(temp32);
449 temp32 = (sectorCount <= 65535) ? 0 : sectorCount;
450 bs->BPB_TotSec32 = B_HOST_TO_LENDIAN_INT32(temp32);
451 bs->BS_DrvNum = biosDriveId;
452 bs->BS_Reserved1 = 0x00;
453 bs->BS_BootSig = 0x29;
454 uint32 volID = B_HOST_TO_LENDIAN_INT32(system_time());
455 memcpy(bs->BS_VolID, &volID, 4);
456 memset(bs->BS_VolLab, 0x20, 11);
457 memcpy(bs->BS_VolLab, label, min_c(11, strlen(label)));
458 memcpy(bs->BS_FilSysType,(fatbits == 12) ? "FAT12 " : "FAT16 ",8);
459 bs->signature = B_HOST_TO_LENDIAN_INT16(0xAA55);
460 }
461
462 // Disk layout:
463 // 0) reserved sectors, this includes the bootsector, fsinfosector and
464 // bootsector backup
465 // 1) FAT
466 // 2) root directory (not on fat32)
467 // 3) file & directory data
468
469 ssize_t written;
470
471 // initialize everything with zero first
472 // avoid doing 512 byte writes here, they are slow
473 dprintf("dosfs: Writing FAT\n");
474 char * zerobuffer = (char *)malloc(65536);
475 memset(zerobuffer,0,65536);
476 int64 bytes_to_write = 512LL * (reservedSectorCount + (numFATs * FATSize)
477 + rootDirSectors);
478 int64 pos = 0;
479 while (bytes_to_write > 0) {
480 ssize_t writesize = min_c(bytes_to_write, 65536);
481 written = write_pos(fd, pos, zerobuffer, writesize);
482 if (written != writesize) {
483 dprintf("dosfs Error: write error near sector %" B_PRId64 "\n", pos / 512);
484 free(zerobuffer);
485 return B_ERROR;
486 }
487 bytes_to_write -= writesize;
488 pos += writesize;
489 }
490 free(zerobuffer);
491
492 //write boot sector
493 dprintf("dosfs: Writing boot block\n");
494 written = write_pos(fd, BOOT_SECTOR_NUM * 512, bootsector, 512);
495 if (written != 512) {
496 dprintf("dosfs Error: write error at sector %d\n", BOOT_SECTOR_NUM);
497 return B_ERROR;
498 }
499
500 if (fatbits == 32) {
501 written = write_pos(fd, BACKUP_SECTOR_NUM * 512, bootsector, 512);
502 if (written != 512) {
503 dprintf("dosfs Error: write error at sector %d\n", BACKUP_SECTOR_NUM);
504 return B_ERROR;
505 }
506 }
507
508 //write first fat sector
509 dprintf("dosfs: Writing first FAT sector\n");
510 uint8 sec[512];
511 memset(sec,0,512);
512 if (fatbits == 12) {
513 //FAT[0] contains media byte in lower 8 bits, all other bits set to 1
514 //FAT[1] contains EOF marker
515 sec[0] = hasDeviceGeometry && deviceGeometry.removable ? 0xF0 : 0xF8;
516 sec[1] = 0xFF;
517 sec[2] = 0xFF;
518 } else if (fatbits == 16) {
519 //FAT[0] contains media byte in lower 8 bits, all other bits set to 1
520 sec[0] = hasDeviceGeometry && deviceGeometry.removable ? 0xF0 : 0xF8;
521 sec[1] = 0xFF;
522 //FAT[1] contains EOF marker
523 sec[2] = 0xFF;
524 sec[3] = 0xFF;
525 } else if (fatbits == 32) {
526 //FAT[0] contains media byte in lower 8 bits, all other bits set to 1
527 sec[0] = hasDeviceGeometry && deviceGeometry.removable ? 0xF0 : 0xF8;
528 sec[1] = 0xFF;
529 sec[2] = 0xFF;
530 sec[3] = 0xFF;
531 //FAT[1] contains EOF marker
532 sec[4] = 0xFF;
533 sec[5] = 0xFF;
534 sec[6] = 0xFF;
535 sec[7] = 0x0F;
536 //FAT[2] contains EOF marker, used to terminate root directory
537 sec[8] = 0xFF;
538 sec[9] = 0xFF;
539 sec[10] = 0xFF;
540 sec[11] = 0x0F;
541 }
542 written = write_pos(fd, reservedSectorCount * 512, sec, 512);
543 if (written != 512) {
544 dprintf("dosfs Error: write error at sector %d\n", reservedSectorCount);
545 return B_ERROR;
546 }
547 if (numFATs > 1) {
548 written = write_pos(fd, (reservedSectorCount + FATSize) * 512,sec,512);
549 if (written != 512) {
550 dprintf("dosfs Error: write error at sector %" B_PRIu32 "\n",
551 reservedSectorCount + FATSize);
552 return B_ERROR;
553 }
554 }
555
556 //write fsinfo sector
557 if (fatbits == 32) {
558 dprintf("dosfs: Writing boot info\n");
559 // account for 1 already used cluster of root directory
560 uint64 free_count = clusterCount - 1;
561 fsinfosector32 fsinfosector;
562 memset(&fsinfosector,0x00,512);
563 fsinfosector.FSI_LeadSig = B_HOST_TO_LENDIAN_INT32(0x41615252);
564 fsinfosector.FSI_StrucSig = B_HOST_TO_LENDIAN_INT32(0x61417272);
565 fsinfosector.FSI_Free_Count
566 = B_HOST_TO_LENDIAN_INT32((uint32)free_count);
567 fsinfosector.FSI_Nxt_Free = B_HOST_TO_LENDIAN_INT32(3);
568 fsinfosector.FSI_TrailSig = B_HOST_TO_LENDIAN_INT32(0xAA550000);
569 written = write_pos(fd, FSINFO_SECTOR_NUM * 512, &fsinfosector, 512);
570 if (written != 512) {
571 dprintf("dosfs Error: write error at sector %d\n", FSINFO_SECTOR_NUM);
572 return B_ERROR;
573 }
574 }
575
576 //write volume label into root directory
577 dprintf("dosfs: Writing root directory\n");
578 if (fatbits == 12 || fatbits == 16) {
579 uint8 data[512];
580 memset(data, 0, 512);
581 create_volume_label_sector(data, label);
582 uint32 rootDirSector = reservedSectorCount + (numFATs * FATSize);
583 written = write_pos(fd, rootDirSector * 512, data, 512);
584 if (written != 512) {
585 dprintf("dosfs Error: write error at sector %" B_PRIu32 "\n",
586 rootDirSector);
587 return B_ERROR;
588 }
589 } else if (fatbits == 32) {
590 int size = 512 * sectorPerCluster;
591 uint8 *cluster = (uint8*)malloc(size);
592 memset(cluster, 0, size);
593 create_volume_label_sector(cluster, label);
594 uint32 rootDirSector = reservedSectorCount + (numFATs * FATSize)
595 + rootDirSectors;
596 written = write_pos(fd, rootDirSector * 512, cluster, size);
597 free(cluster);
598 if (written != size) {
599 dprintf("dosfs Error: write error at sector %" B_PRIu32 "\n", rootDirSector);
600 return B_ERROR;
601 }
602 }
603
604 ioctl(fd, B_FLUSH_DRIVE_CACHE);
605
606
607
608 // rescan partition
609 status = scan_partition(partitionID);
610 if (status != B_OK)
611 return status;
612
613 update_disk_device_job_progress(job, 1);
614
615 // print some info, if desired
616 if (parameters.verbose) {
617
618 dprintf("dosfs: Disk was initialized successfully.\n");
619 }
620
621 return B_OK;
622 }
623
624
625 status_t
_dosfs_uninitialize(int fd,partition_id partitionID,off_t partitionSize,uint32 blockSize,disk_job_id job)626 _dosfs_uninitialize(int fd, partition_id partitionID, off_t partitionSize, uint32 blockSize,
627 disk_job_id job)
628 {
629 if (blockSize == 0)
630 return B_BAD_VALUE;
631
632 update_disk_device_job_progress(job, 0.0);
633
634 // just overwrite the superblock
635 // XXX: we might want to keep the loader part ?
636 char bootsector[512];
637 memset(bootsector,0x00,512);
638
639 if (write_pos(fd, 512, bootsector, sizeof(bootsector)) < 0)
640 return errno;
641
642 update_disk_device_job_progress(job, 1.0);
643
644 return B_OK;
645 }
646