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