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