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