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