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 return B_ERROR; 436 } 437 bytes_to_write -= writesize; 438 pos += writesize; 439 } 440 free(zerobuffer); 441 442 //write boot sector 443 dprintf("dosfs: Writing boot block\n"); 444 written = write_pos(fd, BOOT_SECTOR_NUM * 512, bootsector, 512); 445 if (written != 512) { 446 dprintf("dosfs Error: write error at sector %d\n", BOOT_SECTOR_NUM); 447 return B_ERROR; 448 } 449 450 if (fatbits == 32) { 451 written = write_pos(fd, BACKUP_SECTOR_NUM * 512, bootsector, 512); 452 if (written != 512) { 453 dprintf("dosfs Error: write error at sector %d\n", BACKUP_SECTOR_NUM); 454 return B_ERROR; 455 } 456 } 457 458 //write first fat sector 459 dprintf("dosfs: Writing first FAT sector\n"); 460 uint8 sec[512]; 461 memset(sec,0,512); 462 if (fatbits == 12) { 463 //FAT[0] contains media byte in lower 8 bits, all other bits set to 1 464 //FAT[1] contains EOF marker 465 sec[0] = 0xF8; 466 sec[1] = 0xFF; 467 sec[2] = 0xFF; 468 } else if (fatbits == 16) { 469 //FAT[0] contains media byte in lower 8 bits, all other bits set to 1 470 sec[0] = 0xF8; 471 sec[1] = 0xFF; 472 //FAT[1] contains EOF marker 473 sec[2] = 0xFF; 474 sec[3] = 0xFF; 475 } else if (fatbits == 32) { 476 //FAT[0] contains media byte in lower 8 bits, all other bits set to 1 477 sec[0] = 0xF8; 478 sec[1] = 0xFF; 479 sec[2] = 0xFF; 480 sec[3] = 0xFF; 481 //FAT[1] contains EOF marker 482 sec[4] = 0xFF; 483 sec[5] = 0xFF; 484 sec[6] = 0xFF; 485 sec[7] = 0x0F; 486 //FAT[2] contains EOF marker, used to terminate root directory 487 sec[8] = 0xFF; 488 sec[9] = 0xFF; 489 sec[10] = 0xFF; 490 sec[11] = 0x0F; 491 } 492 written = write_pos(fd, reservedSectorCount * 512, sec, 512); 493 if (written != 512) { 494 dprintf("dosfs Error: write error at sector %d\n", reservedSectorCount); 495 return B_ERROR; 496 } 497 if (numFATs > 1) { 498 written = write_pos(fd, (reservedSectorCount + FATSize) * 512,sec,512); 499 if (written != 512) { 500 dprintf("dosfs Error: write error at sector %ld\n", reservedSectorCount + FATSize); 501 return B_ERROR; 502 } 503 } 504 505 //write fsinfo sector 506 if (fatbits == 32) { 507 dprintf("dosfs: Writing boot info\n"); 508 //calculate total sector count first 509 uint64 free_count = size / 512; 510 //now account for already by metadata used sectors 511 free_count -= reservedSectorCount + (numFATs * FATSize) + rootDirSectors; 512 //convert from sector to clustercount 513 free_count /= sectorPerCluster; 514 //and account for 1 already used cluster of root directory 515 free_count -= 1; 516 fsinfosector32 fsinfosector; 517 memset(&fsinfosector,0x00,512); 518 fsinfosector.FSI_LeadSig = B_HOST_TO_LENDIAN_INT32(0x41615252); 519 fsinfosector.FSI_StrucSig = B_HOST_TO_LENDIAN_INT32(0x61417272); 520 fsinfosector.FSI_Free_Count = B_HOST_TO_LENDIAN_INT32((uint32)free_count); 521 fsinfosector.FSI_Nxt_Free = B_HOST_TO_LENDIAN_INT32(3); 522 fsinfosector.FSI_TrailSig = B_HOST_TO_LENDIAN_INT32(0xAA550000); 523 written = write_pos(fd, FSINFO_SECTOR_NUM * 512, &fsinfosector, 512); 524 if (written != 512) { 525 dprintf("dosfs Error: write error at sector %d\n", FSINFO_SECTOR_NUM); 526 return B_ERROR; 527 } 528 } 529 530 //write volume label into root directory 531 dprintf("dosfs: Writing root directory\n"); 532 if (fatbits == 12 || fatbits == 16) { 533 uint8 data[512]; 534 memset(data, 0, 512); 535 CreateVolumeLabel(data, label); 536 uint32 rootDirSector = reservedSectorCount + (numFATs * FATSize); 537 written = write_pos(fd, rootDirSector * 512, data, 512); 538 if (written != 512) { 539 dprintf("dosfs Error: write error at sector %ld\n", rootDirSector); 540 return B_ERROR; 541 } 542 } else if (fatbits == 32) { 543 int size = 512 * sectorPerCluster; 544 uint8 *cluster = (uint8*)malloc(size); 545 memset(cluster, 0, size); 546 CreateVolumeLabel(cluster, label); 547 uint32 rootDirSector = reservedSectorCount + (numFATs * FATSize) + rootDirSectors; 548 written = write_pos(fd, rootDirSector * 512, cluster, size); 549 free(cluster); 550 if (written != size) { 551 dprintf("dosfs Error: write error at sector %ld\n", rootDirSector); 552 return B_ERROR; 553 } 554 } 555 556 ioctl(fd, B_FLUSH_DRIVE_CACHE); 557 558 559 560 // rescan partition 561 status = scan_partition(partitionID); 562 if (status != B_OK) 563 return status; 564 565 update_disk_device_job_progress(job, 1); 566 567 // print some info, if desired 568 if (parameters.verbose) { 569 // disk_super_block super = volume.SuperBlock(); 570 571 dprintf("dosfs: Disk was initialized successfully.\n"); 572 /* 573 dprintf("\tname: \"%s\"\n", super.name); 574 dprintf("\tnum blocks: %" B_PRIdOFF "\n", super.NumBlocks()); 575 dprintf("\tused blocks: %" B_PRIdOFF "\n", super.UsedBlocks()); 576 dprintf("\tblock size: %u bytes\n", (unsigned)super.BlockSize()); 577 dprintf("\tnum allocation groups: %d\n", 578 (int)super.AllocationGroups()); 579 dprintf("\tallocation group size: %ld blocks\n", 580 1L << super.AllocationGroupShift()); 581 dprintf("\tlog size: %u blocks\n", super.log_blocks.Length()); 582 */ 583 } 584 585 return B_OK; 586 } 587 588 589 status_t 590 dosfs_uninitialize(int fd, partition_id partitionID, off_t partitionSize, 591 uint32 blockSize, disk_job_id job) 592 { 593 if (blockSize == 0) 594 return B_BAD_VALUE; 595 596 update_disk_device_job_progress(job, 0.0); 597 598 // just overwrite the superblock 599 // XXX: we might want to keep the loader part ? 600 char bootsector[512]; 601 memset(bootsector,0x00,512); 602 603 if (write_pos(fd, 512, bootsector, sizeof(512)) < 0) 604 return errno; 605 606 update_disk_device_job_progress(job, 1.0); 607 608 return B_OK; 609 } 610 611 612 // #pragma mark - 613 614 615 #if 0 616 int 617 main(int argc, char *argv[]) 618 { 619 if (sizeof(bootsector1216) != 512 || sizeof(bootsector32) != 512 || sizeof(fsinfosector32) != 512) { 620 dprintf("compilation error: struct alignment wrong\n"); 621 return 1; 622 } 623 624 const char *device = NULL; 625 const char *label = NULL; 626 bool noprompt = false; 627 bool test = false; 628 int fat = 0; 629 630 while (1) { 631 int c; 632 int option_index = 0; 633 static struct option long_options[] = 634 { 635 {"noprompt", no_argument, 0, 'n'}, 636 {"test", no_argument, 0, 't'}, 637 {"fat", required_argument, 0, 'f'}, 638 {0, 0, 0, 0} 639 }; 640 641 c = getopt_long (argc, argv, "ntf:", long_options, &option_index); 642 if (c == -1) 643 break; 644 645 switch (c) { 646 case 'n': 647 noprompt = true; 648 break; 649 650 case 't': 651 test = true; 652 break; 653 654 case 'f': 655 fat = strtol(optarg, NULL, 10); 656 if (fat == 0) 657 fat = -1; 658 break; 659 660 default: 661 printf("\n"); 662 PrintUsage(); 663 return 1; 664 } 665 } 666 667 if (optind < argc) 668 device = argv[optind]; 669 if ((optind + 1) < argc) 670 label = argv[optind + 1]; 671 672 if (fat != 0 && fat != 12 && fat != 16 && fat != 32) { 673 printf("mkdos error: fat must be 12, 16, or 32 bits\n"); 674 PrintUsage(); 675 return 1; 676 } 677 678 if (device == NULL) { 679 printf("mkdos error: you must specify a device or partition or image\n"); 680 printf(" such as /dev/disk/ide/ata/1/master/0/0_0\n"); 681 PrintUsage(); 682 return 1; 683 } 684 685 if (label == NULL) { 686 label = "no name"; 687 } 688 689 if (noprompt) 690 printf("will not prompt for confirmation\n"); 691 692 if (test) 693 printf("test mode enabled (no writes will occur)\n"); 694 695 status_t s; 696 s = Initialize(fat, device, label, noprompt, test); 697 698 if (s != 0) { 699 printf("Initializing failed!\n"); 700 } 701 702 return (s == B_OK) ? 0 : 1; 703 } 704 #endif 705 706 707 void CreateVolumeLabel(void *sector, const char *label) 708 { 709 // create a volume name directory entry in the 512 byte sector 710 // XXX convert from UTF8, and check for valid characters 711 // XXX this could be changed to use long file name entrys, 712 // XXX but the dosfs would have to be updated, too 713 714 dirent *d = (dirent *)sector; 715 memset(d, 0, sizeof(*d)); 716 memset(d->Name, 0x20, 11); 717 memcpy(d->Name, label, min_c(11, strlen(label))); 718 d->Attr = 0x08; 719 } 720