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 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 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 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 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