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