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 if (fatbits == 0) { 232 //auto determine fat type 233 if (isRawDevice && size <= FLOPPY_MAX_SIZE 234 && (size / FAT12_CLUSTER_MAX_SIZE) < FAT12_MAX_CLUSTER_COUNT) { 235 fatbits = 12; 236 } else if ((size / CLUSTER_MAX_SIZE) < FAT16_MAX_CLUSTER_COUNT) { 237 fatbits = 16; 238 } else if ((size / CLUSTER_MAX_SIZE) < FAT32_MAX_CLUSTER_COUNT) { 239 fatbits = 32; 240 } 241 } 242 243 if (fatbits == 0) { 244 dprintf("dosfs Error: device too large for 32 bit fat\n"); 245 return B_ERROR; 246 } 247 248 int sectorPerCluster; 249 250 sectorPerCluster = 0; 251 if (fatbits == 12) { 252 sectorPerCluster = 0; 253 if (size < 16777216LL) 254 sectorPerCluster = 8; 255 if (size <= 2949120) 256 sectorPerCluster = 2; 257 if (size <= 1474560) 258 sectorPerCluster = 1; 259 if (size <= 737280) { 260 // We follow Microsoft guidance in increasing cluster size for the smallest disks. 261 // The idea was probably to keep the FAT from taking up a too much of a small disk. 262 sectorPerCluster = 2; 263 } 264 } else if (fatbits == 16) { 265 sectorPerCluster = 0; //larger than 2 GB must fail 266 if (size <= (2048 * 1024 * 1024LL)) // up to 2GB, use 32k clusters 267 sectorPerCluster = 64; 268 if (size <= (1024 * 1024 * 1024LL)) // up to 1GB, use 16k clusters 269 sectorPerCluster = 32; 270 if (size <= (512 * 1024 * 1024LL)) // up to 512MB, use 8k clusters 271 sectorPerCluster = 16; 272 if (size <= (256 * 1024 * 1024LL)) // up to 256MB, use 4k clusters 273 sectorPerCluster = 8; 274 if (size <= (128 * 1024 * 1024LL)) // up to 128MB, use 2k clusters 275 sectorPerCluster = 4; 276 if (size <= (16 * 1024 * 1024LL)) // up to 16MB, use 1k clusters 277 sectorPerCluster = 2; 278 if (size <= 4182016LL) // smaller than 4.1 MB must fail 279 sectorPerCluster = 0; 280 } else if (fatbits == 32) { 281 sectorPerCluster = 64; // default is 32k clusters 282 if (size <= (32 * 1024 * 1024 * 1024LL)) { 283 // up to 32GB, use 16k clusters 284 sectorPerCluster = 32; 285 } 286 if (size <= (16 * 1024 * 1024 * 1024LL)) { 287 // up to 16GB, use 8k clusters 288 sectorPerCluster = 16; 289 } 290 if (size <= (8 * 1024 * 1024 * 1024LL)) { 291 // up to 8GB, use 4k clusters 292 sectorPerCluster = 8; 293 } 294 if (size <= (532480 * 512LL)) { 295 // up to 260 MB, use 0.5k clusters 296 sectorPerCluster = 1; 297 } 298 if (size <= (66600 * 512LL)) { 299 // smaller than 32.5 MB must fail 300 sectorPerCluster = 0; 301 } 302 } 303 304 if (sectorPerCluster == 0) { 305 dprintf("dosfs Error: failed to determine sector per cluster value, " 306 "partition too large for %d bit fat\n",fatbits); 307 return B_ERROR; 308 } 309 310 int reservedSectorCount = 0; // avoid compiler warning 311 int rootEntryCount = 0; // avoid compiler warning 312 int numFATs; 313 int sectorSize; 314 uint8 biosDriveId; 315 316 // get bios drive-id, or use 0x80 317 if (B_OK != ioctl(fd, B_GET_BIOS_DRIVE_ID, &biosDriveId, 318 sizeof(biosDriveId))) { 319 biosDriveId = 0x80; 320 } else { 321 dprintf("dosfs: bios drive id: 0x%02x\n", (int)biosDriveId); 322 } 323 324 // default parameters for the bootsector 325 numFATs = 2; 326 sectorSize = 512; 327 if (fatbits == 12 || fatbits == 16) 328 reservedSectorCount = 1; 329 if (fatbits == 32) 330 reservedSectorCount = 32; 331 if (fatbits == 12) 332 rootEntryCount = 512; 333 if (fatbits == 16) 334 rootEntryCount = 512; 335 if (fatbits == 32) 336 rootEntryCount = 0; 337 338 // Determine FATSize 339 // calculation done as MS recommends 340 uint64 dskSize = size / sectorSize; 341 uint32 rootDirSectors = ((rootEntryCount * 32) + (sectorSize - 1)) 342 / sectorSize; 343 uint64 tmpVal1 = dskSize - (reservedSectorCount + rootDirSectors); 344 uint64 tmpVal2 = (256 * sectorPerCluster) + numFATs; 345 if (fatbits == 32) 346 tmpVal2 = tmpVal2 / 2; 347 uint32 FATSize = (tmpVal1 + (tmpVal2 - 1)) / tmpVal2; 348 // FATSize should now contain the size of *one* FAT, measured in sectors 349 // RootDirSectors should now contain the size of the fat12/16 root 350 // directory, measured in sectors 351 352 // Now that clusters can be counted, verify cluster count is compatible with the FAT type 353 uint64 sectorCount = size / 512; 354 uint64 dataSec = sectorCount - (reservedSectorCount + (numFATs * FATSize) + rootDirSectors); 355 uint64 clusterCount = dataSec / sectorPerCluster; 356 if (fatbits == 12 && clusterCount > FAT12_MAX_CLUSTER_COUNT) { 357 dprintf("dosfs Error: cluster count (%" B_PRIu64 ") exceeds FAT12 limit.\n", clusterCount); 358 return B_BAD_VALUE; 359 } 360 if (fatbits == 16 && clusterCount > FAT16_MAX_CLUSTER_COUNT) { 361 dprintf("dosfs Error: cluster count (%" B_PRIu64 ") exceeds FAT16 limit.\n", clusterCount); 362 return B_BAD_VALUE; 363 } 364 if (fatbits == 32 && clusterCount > FAT32_MAX_CLUSTER_COUNT) { 365 dprintf("dosfs Error: cluster count (%" B_PRIu64 ") exceeds FAT32 limit.\n", clusterCount); 366 return B_BAD_VALUE; 367 } 368 369 dprintf("dosfs: fatbits = %d, clustersize = %d\n", fatbits, sectorPerCluster * 512); 370 dprintf("dosfs: FAT size is %" B_PRIu32 " sectors\n", FATSize); 371 dprintf("dosfs: disk label: %s\n", label); 372 373 374 375 if (status < B_OK) { 376 dprintf("dosfs: Initializing volume failed: %s\n", strerror(status)); 377 return status; 378 } 379 380 char bootsector[512]; 381 memset(bootsector,0x00,512); 382 memcpy(bootsector + BOOTJMP_START_OFFSET, bootjmp, sizeof(bootjmp)); 383 memcpy(bootsector + BOOTCODE_START_OFFSET, bootcode, sizeof(bootcode)); 384 385 if (fatbits == 32) { 386 bootsector32 *bs = (bootsector32 *)bootsector; 387 uint16 temp16; 388 uint32 temp32; 389 memcpy(bs->BS_OEMName,"Haiku ",8); 390 bs->BPB_BytsPerSec = B_HOST_TO_LENDIAN_INT16(sectorSize); 391 bs->BPB_SecPerClus = sectorPerCluster; 392 bs->BPB_RsvdSecCnt = B_HOST_TO_LENDIAN_INT16(reservedSectorCount); 393 bs->BPB_NumFATs = numFATs; 394 bs->BPB_RootEntCnt = B_HOST_TO_LENDIAN_INT16(rootEntryCount); 395 bs->BPB_TotSec16 = B_HOST_TO_LENDIAN_INT16(0); 396 bs->BPB_Media = hasDeviceGeometry && deviceGeometry.removable ? 0xF0 : 0xF8; 397 bs->BPB_FATSz16 = B_HOST_TO_LENDIAN_INT16(0); 398 temp16 = hasBiosGeometry ? biosGeometry.sectors_per_track : 63; 399 bs->BPB_SecPerTrk = B_HOST_TO_LENDIAN_INT16(temp16); 400 temp16 = hasBiosGeometry ? biosGeometry.head_count : 255; 401 bs->BPB_NumHeads = B_HOST_TO_LENDIAN_INT16(temp16); 402 temp32 = hasPartitionInfo ? (partitionInfo.size / 512) : 0; 403 bs->BPB_HiddSec = B_HOST_TO_LENDIAN_INT32(temp32); 404 bs->BPB_TotSec32 = B_HOST_TO_LENDIAN_INT32(sectorCount); 405 bs->BPB_FATSz32 = B_HOST_TO_LENDIAN_INT32(FATSize); 406 bs->BPB_ExtFlags = B_HOST_TO_LENDIAN_INT16(0); 407 bs->BPB_FSVer = B_HOST_TO_LENDIAN_INT16(0); 408 bs->BPB_RootClus = B_HOST_TO_LENDIAN_INT32(FAT32_ROOT_CLUSTER); 409 bs->BPB_FSInfo = B_HOST_TO_LENDIAN_INT16(FSINFO_SECTOR_NUM); 410 bs->BPB_BkBootSec = B_HOST_TO_LENDIAN_INT16(BACKUP_SECTOR_NUM); 411 memset(bs->BPB_Reserved,0,12); 412 bs->BS_DrvNum = biosDriveId; 413 bs->BS_Reserved1 = 0x00; 414 bs->BS_BootSig = 0x29; 415 uint32 volID = B_HOST_TO_LENDIAN_INT32(system_time()); 416 memcpy(bs->BS_VolID, &volID, 4); 417 memset(bs->BS_VolLab, 0x20, 11); 418 memcpy(bs->BS_VolLab, label, min_c(11, strlen(label))); 419 memcpy(bs->BS_FilSysType,"FAT32 ",8); 420 bs->signature = B_HOST_TO_LENDIAN_INT16(0xAA55); 421 } else { 422 bootsector1216 *bs = (bootsector1216 *)bootsector; 423 uint16 temp16; 424 uint32 temp32; 425 memcpy(bs->BS_OEMName, "Haiku ", 8); 426 bs->BPB_BytsPerSec = B_HOST_TO_LENDIAN_INT16(sectorSize); 427 bs->BPB_SecPerClus = sectorPerCluster; 428 bs->BPB_RsvdSecCnt = B_HOST_TO_LENDIAN_INT16(reservedSectorCount); 429 bs->BPB_NumFATs = numFATs; 430 bs->BPB_RootEntCnt = B_HOST_TO_LENDIAN_INT16(rootEntryCount); 431 temp16 = (sectorCount <= 65535) ? sectorCount : 0; 432 bs->BPB_TotSec16 = B_HOST_TO_LENDIAN_INT16(temp16); 433 bs->BPB_Media = hasDeviceGeometry && deviceGeometry.removable ? 0xF0 : 0xF8; 434 bs->BPB_FATSz16 = B_HOST_TO_LENDIAN_INT16(FATSize); 435 temp16 = hasBiosGeometry ? biosGeometry.sectors_per_track : 63; 436 bs->BPB_SecPerTrk = B_HOST_TO_LENDIAN_INT16(temp16); 437 temp16 = hasBiosGeometry ? biosGeometry.head_count : 255; 438 bs->BPB_NumHeads = B_HOST_TO_LENDIAN_INT16(temp16); 439 temp32 = hasPartitionInfo ? (partitionInfo.size / 512) : 0; 440 bs->BPB_HiddSec = B_HOST_TO_LENDIAN_INT32(temp32); 441 temp32 = (sectorCount <= 65535) ? 0 : sectorCount; 442 bs->BPB_TotSec32 = B_HOST_TO_LENDIAN_INT32(temp32); 443 bs->BS_DrvNum = biosDriveId; 444 bs->BS_Reserved1 = 0x00; 445 bs->BS_BootSig = 0x29; 446 uint32 volID = B_HOST_TO_LENDIAN_INT32(system_time()); 447 memcpy(bs->BS_VolID, &volID, 4); 448 memset(bs->BS_VolLab, 0x20, 11); 449 memcpy(bs->BS_VolLab, label, min_c(11, strlen(label))); 450 memcpy(bs->BS_FilSysType,(fatbits == 12) ? "FAT12 " : "FAT16 ",8); 451 bs->signature = B_HOST_TO_LENDIAN_INT16(0xAA55); 452 } 453 454 // Disk layout: 455 // 0) reserved sectors, this includes the bootsector, fsinfosector and 456 // bootsector backup 457 // 1) FAT 458 // 2) root directory (not on fat32) 459 // 3) file & directory data 460 461 ssize_t written; 462 463 // initialize everything with zero first 464 // avoid doing 512 byte writes here, they are slow 465 dprintf("dosfs: Writing FAT\n"); 466 char * zerobuffer = (char *)malloc(65536); 467 memset(zerobuffer,0,65536); 468 int64 bytes_to_write = 512LL * (reservedSectorCount + (numFATs * FATSize) 469 + rootDirSectors); 470 int64 pos = 0; 471 while (bytes_to_write > 0) { 472 ssize_t writesize = min_c(bytes_to_write, 65536); 473 written = write_pos(fd, pos, zerobuffer, writesize); 474 if (written != writesize) { 475 dprintf("dosfs Error: write error near sector %" B_PRId64 "\n", pos / 512); 476 free(zerobuffer); 477 return B_ERROR; 478 } 479 bytes_to_write -= writesize; 480 pos += writesize; 481 } 482 free(zerobuffer); 483 484 //write boot sector 485 dprintf("dosfs: Writing boot block\n"); 486 written = write_pos(fd, BOOT_SECTOR_NUM * 512, bootsector, 512); 487 if (written != 512) { 488 dprintf("dosfs Error: write error at sector %d\n", BOOT_SECTOR_NUM); 489 return B_ERROR; 490 } 491 492 if (fatbits == 32) { 493 written = write_pos(fd, BACKUP_SECTOR_NUM * 512, bootsector, 512); 494 if (written != 512) { 495 dprintf("dosfs Error: write error at sector %d\n", BACKUP_SECTOR_NUM); 496 return B_ERROR; 497 } 498 } 499 500 //write first fat sector 501 dprintf("dosfs: Writing first FAT sector\n"); 502 uint8 sec[512]; 503 memset(sec,0,512); 504 if (fatbits == 12) { 505 //FAT[0] contains media byte in lower 8 bits, all other bits set to 1 506 //FAT[1] contains EOF marker 507 sec[0] = hasDeviceGeometry && deviceGeometry.removable ? 0xF0 : 0xF8; 508 sec[1] = 0xFF; 509 sec[2] = 0xFF; 510 } else if (fatbits == 16) { 511 //FAT[0] contains media byte in lower 8 bits, all other bits set to 1 512 sec[0] = hasDeviceGeometry && deviceGeometry.removable ? 0xF0 : 0xF8; 513 sec[1] = 0xFF; 514 //FAT[1] contains EOF marker 515 sec[2] = 0xFF; 516 sec[3] = 0xFF; 517 } else if (fatbits == 32) { 518 //FAT[0] contains media byte in lower 8 bits, all other bits set to 1 519 sec[0] = hasDeviceGeometry && deviceGeometry.removable ? 0xF0 : 0xF8; 520 sec[1] = 0xFF; 521 sec[2] = 0xFF; 522 sec[3] = 0xFF; 523 //FAT[1] contains EOF marker 524 sec[4] = 0xFF; 525 sec[5] = 0xFF; 526 sec[6] = 0xFF; 527 sec[7] = 0x0F; 528 //FAT[2] contains EOF marker, used to terminate root directory 529 sec[8] = 0xFF; 530 sec[9] = 0xFF; 531 sec[10] = 0xFF; 532 sec[11] = 0x0F; 533 } 534 written = write_pos(fd, reservedSectorCount * 512, sec, 512); 535 if (written != 512) { 536 dprintf("dosfs Error: write error at sector %d\n", reservedSectorCount); 537 return B_ERROR; 538 } 539 if (numFATs > 1) { 540 written = write_pos(fd, (reservedSectorCount + FATSize) * 512,sec,512); 541 if (written != 512) { 542 dprintf("dosfs Error: write error at sector %" B_PRIu32 "\n", 543 reservedSectorCount + FATSize); 544 return B_ERROR; 545 } 546 } 547 548 //write fsinfo sector 549 if (fatbits == 32) { 550 dprintf("dosfs: Writing boot info\n"); 551 // account for 1 already used cluster of root directory 552 uint64 free_count = clusterCount - 1; 553 fsinfosector32 fsinfosector; 554 memset(&fsinfosector,0x00,512); 555 fsinfosector.FSI_LeadSig = B_HOST_TO_LENDIAN_INT32(0x41615252); 556 fsinfosector.FSI_StrucSig = B_HOST_TO_LENDIAN_INT32(0x61417272); 557 fsinfosector.FSI_Free_Count 558 = B_HOST_TO_LENDIAN_INT32((uint32)free_count); 559 fsinfosector.FSI_Nxt_Free = B_HOST_TO_LENDIAN_INT32(3); 560 fsinfosector.FSI_TrailSig = B_HOST_TO_LENDIAN_INT32(0xAA550000); 561 written = write_pos(fd, FSINFO_SECTOR_NUM * 512, &fsinfosector, 512); 562 if (written != 512) { 563 dprintf("dosfs Error: write error at sector %d\n", FSINFO_SECTOR_NUM); 564 return B_ERROR; 565 } 566 } 567 568 //write volume label into root directory 569 dprintf("dosfs: Writing root directory\n"); 570 if (fatbits == 12 || fatbits == 16) { 571 uint8 data[512]; 572 memset(data, 0, 512); 573 create_volume_label_sector(data, label); 574 uint32 rootDirSector = reservedSectorCount + (numFATs * FATSize); 575 written = write_pos(fd, rootDirSector * 512, data, 512); 576 if (written != 512) { 577 dprintf("dosfs Error: write error at sector %" B_PRIu32 "\n", 578 rootDirSector); 579 return B_ERROR; 580 } 581 } else if (fatbits == 32) { 582 int size = 512 * sectorPerCluster; 583 uint8 *cluster = (uint8*)malloc(size); 584 memset(cluster, 0, size); 585 create_volume_label_sector(cluster, label); 586 uint32 rootDirSector = reservedSectorCount + (numFATs * FATSize) 587 + rootDirSectors; 588 written = write_pos(fd, rootDirSector * 512, cluster, size); 589 free(cluster); 590 if (written != size) { 591 dprintf("dosfs Error: write error at sector %" B_PRIu32 "\n", rootDirSector); 592 return B_ERROR; 593 } 594 } 595 596 ioctl(fd, B_FLUSH_DRIVE_CACHE); 597 598 599 600 // rescan partition 601 status = scan_partition(partitionID); 602 if (status != B_OK) 603 return status; 604 605 update_disk_device_job_progress(job, 1); 606 607 // print some info, if desired 608 if (parameters.verbose) { 609 610 dprintf("dosfs: Disk was initialized successfully.\n"); 611 } 612 613 return B_OK; 614 } 615 616 617 status_t 618 _dosfs_uninitialize(int fd, partition_id partitionID, off_t partitionSize, uint32 blockSize, 619 disk_job_id job) 620 { 621 if (blockSize == 0) 622 return B_BAD_VALUE; 623 624 update_disk_device_job_progress(job, 0.0); 625 626 // just overwrite the superblock 627 // XXX: we might want to keep the loader part ? 628 char bootsector[512]; 629 memset(bootsector,0x00,512); 630 631 if (write_pos(fd, 512, bootsector, sizeof(bootsector)) < 0) 632 return errno; 633 634 update_disk_device_job_progress(job, 1.0); 635 636 return B_OK; 637 } 638