Ticket #4602: dosfs_volume.diff
File dosfs_volume.diff, 15.7 KB (added by , 15 years ago) |
---|
-
dosfs.c
160 160 } 161 161 } 162 162 163 163 164 static bool 164 165 dosfs_read_label(bool fat32, uint8 *buffer, char *label) 165 166 { … … 177 178 } 178 179 179 180 180 static int 181 lock_removable_device(int fd, bool state) 181 static nspace* 182 volume_init(int fd, uint8* buf, 183 const int flags, int fs_flags, 184 device_geometry *geo) 182 185 { 183 return ioctl(fd, B_SCSI_PREVENT_ALLOW, &state, sizeof(state));184 }185 186 187 static status_t188 mount_fat_disk(const char *path, fs_volume *_vol, const int flags,189 nspace** newVol, int fs_flags, int op_sync_mode)190 {191 186 nspace *vol = NULL; 192 uint8 buf[512];187 uint8 media_buf[512]; 193 188 int i; 194 device_geometry geo;195 189 status_t err; 196 197 *newVol = NULL; 190 198 191 if ((vol = (nspace *)calloc(sizeof(nspace), 1)) == NULL) { 199 192 dprintf("dosfs error: out of memory\n"); 200 return B_NO_MEMORY;193 return NULL; 201 194 } 202 195 203 vol->flags = B_FS_IS_PERSISTENT | B_FS_HAS_MIME;196 vol->flags = flags; 204 197 vol->fs_flags = fs_flags; 198 vol->fd = fd; 205 199 206 // open read-only for now207 if ((err = (vol->fd = open(path, O_RDONLY | O_NOCACHE))) < 0) {208 dprintf("dosfs error: unable to open %s (%s)\n", path, strerror(err));209 goto error0;210 }211 212 // get device characteristics213 if (ioctl(vol->fd, B_GET_GEOMETRY, &geo) < 0) {214 struct stat st;215 if (fstat(vol->fd, &st) >= 0 && S_ISREG(st.st_mode)) {216 /* support mounting disk images */217 geo.bytes_per_sector = 0x200;218 geo.sectors_per_track = 1;219 geo.cylinder_count = st.st_size / 0x200;220 geo.head_count = 1;221 geo.read_only = !(st.st_mode & S_IWUSR);222 geo.removable = true;223 } else {224 dprintf("dosfs error: error getting device geometry\n");225 goto error0;226 }227 }228 229 if (geo.bytes_per_sector != 0x200 && geo.bytes_per_sector != 0x400230 && geo.bytes_per_sector != 0x800 && geo.bytes_per_sector != 0x1000) {231 dprintf("dosfs error: unsupported device block size (%lu)\n",232 geo.bytes_per_sector);233 goto error0;234 }235 236 if (geo.removable) {237 DPRINTF(0, ("%s is removable\n", path));238 vol->flags |= B_FS_IS_REMOVABLE;239 }240 241 if (geo.read_only || (flags & B_MOUNT_READ_ONLY)) {242 DPRINTF(0, ("%s is read-only\n", path));243 vol->flags |= B_FS_IS_READONLY;244 } else {245 // reopen it with read/write permissions246 close(vol->fd);247 if ((err = (vol->fd = open(path, O_RDWR | O_NOCACHE))) < 0) {248 dprintf("dosfs error: unable to open %s (%s)\n", path,249 strerror(err));250 goto error0;251 }252 253 if ((vol->flags & B_FS_IS_REMOVABLE)254 && (vol->fs_flags & FS_FLAGS_LOCK_DOOR))255 lock_removable_device(vol->fd, true);256 }257 258 // see if we need to go into op sync mode259 vol->fs_flags &= ~FS_FLAGS_OP_SYNC;260 switch (op_sync_mode) {261 case 1:262 if ((vol->flags & B_FS_IS_REMOVABLE) == 0) {263 // we're not removable, so skip op_sync264 break;265 }266 // supposed to fall through267 268 case 2:269 dprintf("dosfs: mounted with op_sync enabled\n");270 vol->fs_flags |= FS_FLAGS_OP_SYNC;271 break;272 273 case 0:274 default:275 break;276 }277 278 // read in the boot sector279 if ((err = read_pos(vol->fd, 0, (void *)buf, 512)) != 512) {280 dprintf("dosfs error: error reading boot sector\n");281 goto error;282 }283 284 200 // only check boot signature on hard disks to account for broken mtools 285 201 // behavior 286 202 if ((buf[0x1fe] != 0x55 || buf[0x1ff] != 0xaa) && buf[0x15] == 0xf8) … … 376 292 if (vol->total_sectors == 0) 377 293 vol->total_sectors = read32(buf, 0x20); 378 294 379 {295 if (geo != NULL) { 380 296 /* 381 382 383 384 297 Zip disks that were formatted at iomega have an incorrect number 298 of sectors. They say that they have 196576 sectors but they 299 really only have 196192. This check is a work-around for their 300 brain-deadness. 385 301 */ 386 302 unsigned char bogus_zip_data[] = { 387 303 0x00, 0x02, 0x04, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 388 304 0xf8, 0xc0, 0x00, 0x20, 0x00, 0x40, 0x00, 0x20, 0x00, 0x00 389 305 }; 390 306 391 307 if (memcmp(buf + 0x0b, bogus_zip_data, sizeof(bogus_zip_data)) == 0 392 308 && vol->total_sectors == 196576 393 && ((off_t)geo .sectors_per_track * (off_t)geo.cylinder_count394 * (off_t)geo .head_count) == 196192) {309 && ((off_t)geo->sectors_per_track * (off_t)geo->cylinder_count 310 * (off_t)geo->head_count) == 196192) { 395 311 vol->total_sectors = 196192; 396 312 } 397 313 } … … 422 338 vol->vol_entry = -1; 423 339 } 424 340 425 /* check that the partition is large enough to contain the file system */426 if (vol->total_sectors > geo.sectors_per_track * geo.cylinder_count427 * geo.head_count) {428 dprintf("dosfs: volume extends past end of partition\n");429 err = B_PARTITION_TOO_SMALL;430 goto error;431 }432 433 341 // perform sanity checks on the FAT 434 342 435 343 // the media descriptor in active FAT should match the one in the BPB 436 344 if ((err = read_pos(vol->fd, vol->bytes_per_sector * (vol->reserved_sectors 437 345 + vol->active_fat * vol->sectors_per_fat), 438 (void *) buf, 0x200)) != 0x200) {346 (void *)media_buf, 0x200)) != 0x200) { 439 347 dprintf("dosfs error: error reading FAT\n"); 440 348 goto error; 441 349 } 442 350 443 if ( buf[0] != vol->media_descriptor) {444 dprintf("dosfs error: media descriptor mismatch (%x != %x)\n", buf[0],351 if (media_buf[0] != vol->media_descriptor) { 352 dprintf("dosfs error: media descriptor mismatch (%x != %x)\n", media_buf[0], 445 353 vol->media_descriptor); 446 354 goto error; 447 355 } 448 356 449 357 if (vol->fat_mirrored) { 450 358 uint32 i; 451 uint8 buf2[512];359 uint8 mirror_media_buf[512]; 452 360 for (i = 0; i < vol->fat_count; i++) { 453 361 if (i != vol->active_fat) { 454 362 DPRINTF(1, ("checking fat #%ld\n", i)); 455 buf2[0] = ~buf[0];363 mirror_media_buf[0] = ~media_buf[0]; 456 364 if ((err = read_pos(vol->fd, vol->bytes_per_sector 457 365 * (vol->reserved_sectors + vol->sectors_per_fat * i), 458 (void *) buf2, 0x200)) != 0x200) {366 (void *)mirror_media_buf, 0x200)) != 0x200) { 459 367 dprintf("dosfs error: error reading FAT %ld\n", i); 460 368 goto error; 461 369 } 462 370 463 if ( buf2[0] != vol->media_descriptor) {371 if (mirror_media_buf[0] != vol->media_descriptor) { 464 372 dprintf("dosfs error: media descriptor mismatch in fat # " 465 "%ld (%x != %x)\n", i, buf2[0], vol->media_descriptor);373 "%ld (%x != %x)\n", i, mirror_media_buf[0], vol->media_descriptor); 466 374 goto error; 467 375 } 468 376 #if 0 469 377 // checking for exact matches of fats is too 470 378 // restrictive; allow these to go through in 471 379 // case the fat is corrupted for some reason 472 if (memcmp( buf, buf2, 0x200)) {380 if (memcmp(media_buf, mirror_media_buf, 0x200)) { 473 381 dprintf("dosfs error: fat %d doesn't match active fat " 474 382 "(%d)\n", i, vol->active_fat); 475 383 goto error; … … 479 387 } 480 388 } 481 389 390 482 391 // now we are convinced of the drive's validity 483 392 484 vol->volume = _vol;485 vol->id = _vol->id;486 strncpy(vol->device, path, sizeof(vol->device));487 488 393 // this will be updated later if fsinfo exists 489 394 vol->last_allocated = 2; 490 491 395 vol->beos_vnid = INVALID_VNID_BITS_MASK; 492 {493 void *handle;494 handle = load_driver_settings("fat");495 vol->respect_disk_image =496 get_driver_boolean_parameter(handle, "respect", true, true);497 unload_driver_settings(handle);498 }499 396 500 397 // initialize block cache 501 398 vol->fBlockCache = block_cache_create(vol->fd, vol->total_sectors, … … 505 402 goto error; 506 403 } 507 404 508 // as well as the vnode cache 509 if (init_vcache(vol) != B_OK) { 510 dprintf("dosfs error: error initializing vnode cache\n"); 511 goto error1; 512 } 405 // find volume label (supercedes any label in the bpb) 406 { 407 struct diri diri; 408 uint8 *buffer; 409 buffer = diri_init(vol, vol->root_vnode.cluster, 0, &diri); 410 for (; buffer; buffer = diri_next_entry(&diri)) { 411 if ((buffer[0x0b] & FAT_VOLUME) && (buffer[0x0b] != 0xf) 412 && (buffer[0] != 0xe5)) { 413 vol->vol_entry = diri.current_index; 414 memcpy(vol->vol_label, buffer, 11); 415 dosfs_trim_spaces(vol->vol_label); 416 break; 417 } 418 } 513 419 514 // and the dlist cache 515 if (dlist_init(vol) != B_OK) { 516 dprintf("dosfs error: error initializing dlist cache\n"); 517 goto error2; 420 diri_free(&diri); 518 421 } 519 422 423 DPRINTF(0, ("root vnode id = %Lx\n", vol->root_vnode.vnid)); 424 DPRINTF(0, ("volume label [%s] (%lx)\n", vol->vol_label, vol->vol_entry)); 425 426 // steal a trick from bfs 427 if (!memcmp(vol->vol_label, "__RO__ ", 11)) 428 vol->flags |= B_FS_IS_READONLY; 429 430 return vol; 431 432 error: 433 free(vol); 434 return NULL; 435 } 436 437 438 static void 439 volume_uninit(nspace *vol) 440 { 441 block_cache_delete(vol->fBlockCache, false); 442 free(vol); 443 } 444 445 446 static void 447 volume_count_free_cluster(nspace *vol) 448 { 449 status_t err; 450 520 451 if (vol->flags & B_FS_IS_READONLY) 521 452 vol->free_clusters = 0; 522 453 else { … … 539 470 if ((err = count_free_clusters(vol)) < 0) { 540 471 dprintf("dosfs error: error counting free clusters (%s)\n", 541 472 strerror(err)); 542 goto error3;473 return; 543 474 } 544 475 vol->free_clusters = err; 545 476 } 546 477 } 478 } 547 479 480 481 static int 482 lock_removable_device(int fd, bool state) 483 { 484 return ioctl(fd, B_SCSI_PREVENT_ALLOW, &state, sizeof(state)); 485 } 486 487 488 static status_t 489 mount_fat_disk(const char *path, fs_volume *_vol, const int flags, 490 nspace** newVol, int fs_flags, int op_sync_mode) 491 { 492 nspace *vol = NULL; 493 uint8 buf[512]; 494 device_geometry geo; 495 status_t err; 496 int fd; 497 int vol_flags; 498 499 vol_flags = B_FS_IS_PERSISTENT | B_FS_HAS_MIME; 500 501 // open read-only for now 502 if ((err = (fd = open(path, O_RDONLY | O_NOCACHE))) < 0) { 503 dprintf("dosfs error: unable to open %s (%s)\n", path, strerror(err)); 504 goto error0; 505 } 506 507 // get device characteristics 508 if (ioctl(fd, B_GET_GEOMETRY, &geo) < 0) { 509 struct stat st; 510 if (fstat(fd, &st) >= 0 && S_ISREG(st.st_mode)) { 511 /* support mounting disk images */ 512 geo.bytes_per_sector = 0x200; 513 geo.sectors_per_track = 1; 514 geo.cylinder_count = st.st_size / 0x200; 515 geo.head_count = 1; 516 geo.read_only = !(st.st_mode & S_IWUSR); 517 geo.removable = true; 518 } else { 519 dprintf("dosfs error: error getting device geometry\n"); 520 goto error1; 521 } 522 } 523 524 if (geo.bytes_per_sector != 0x200 && geo.bytes_per_sector != 0x400 525 && geo.bytes_per_sector != 0x800 && geo.bytes_per_sector != 0x1000) { 526 dprintf("dosfs error: unsupported device block size (%lu)\n", 527 geo.bytes_per_sector); 528 goto error1; 529 } 530 531 if (geo.removable) { 532 DPRINTF(0, ("%s is removable\n", path)); 533 vol_flags |= B_FS_IS_REMOVABLE; 534 } 535 536 if (geo.read_only || (flags & B_MOUNT_READ_ONLY)) { 537 DPRINTF(0, ("%s is read-only\n", path)); 538 vol_flags |= B_FS_IS_READONLY; 539 } else { 540 // reopen it with read/write permissions 541 close(fd); 542 if ((err = (fd = open(path, O_RDWR | O_NOCACHE))) < 0) { 543 dprintf("dosfs error: unable to open %s (%s)\n", path, 544 strerror(err)); 545 goto error0; 546 } 547 548 if ((vol_flags & B_FS_IS_REMOVABLE) 549 && (fs_flags & FS_FLAGS_LOCK_DOOR)) 550 lock_removable_device(fd, true); 551 } 552 553 // see if we need to go into op sync mode 554 fs_flags &= ~FS_FLAGS_OP_SYNC; 555 switch (op_sync_mode) { 556 case 1: 557 if ((vol_flags & B_FS_IS_REMOVABLE) == 0) { 558 // we're not removable, so skip op_sync 559 break; 560 } 561 // supposed to fall through 562 563 case 2: 564 dprintf("dosfs: mounted with op_sync enabled\n"); 565 fs_flags |= FS_FLAGS_OP_SYNC; 566 break; 567 568 case 0: 569 default: 570 break; 571 } 572 573 // read in the boot sector 574 if ((err = read_pos(fd, 0, (void *)buf, 512)) != 512) { 575 dprintf("dosfs error: error reading boot sector\n"); 576 goto error1; 577 } 578 579 vol = volume_init(fd, buf, vol_flags, fs_flags, &geo); 580 581 /* check that the partition is large enough to contain the file system */ 582 if (vol->total_sectors > geo.sectors_per_track * geo.cylinder_count 583 * geo.head_count) { 584 dprintf("dosfs: volume extends past end of partition\n"); 585 err = B_PARTITION_TOO_SMALL; 586 goto error2; 587 } 588 589 vol->volume = _vol; 590 vol->id = _vol->id; 591 strncpy(vol->device, path, sizeof(vol->device)); 592 593 { 594 void *handle; 595 handle = load_driver_settings("fat"); 596 vol->respect_disk_image = 597 get_driver_boolean_parameter(handle, "respect", true, true); 598 unload_driver_settings(handle); 599 } 600 601 // Initialize the vnode cache 602 if (init_vcache(vol) != B_OK) { 603 dprintf("dosfs error: error initializing vnode cache\n"); 604 goto error2; 605 } 606 607 // and the dlist cache 608 if (dlist_init(vol) != B_OK) { 609 dprintf("dosfs error: error initializing dlist cache\n"); 610 goto error3; 611 } 612 613 volume_count_free_cluster(vol); 614 548 615 DPRINTF(0, ("built at %s on %s\n", build_time, build_date)); 549 DPRINTF(0, ("mounting %s (id %lx, device %x, media descriptor %x)\n", vol->device, vol->id, vol->fd, vol->media_descriptor)); 550 DPRINTF(0, ("%lx bytes/sector, %lx sectors/cluster\n", vol->bytes_per_sector, vol->sectors_per_cluster)); 551 DPRINTF(0, ("%lx reserved sectors, %lx total sectors\n", vol->reserved_sectors, vol->total_sectors)); 552 DPRINTF(0, ("%lx %d-bit fats, %lx sectors/fat, %lx root entries\n", vol->fat_count, vol->fat_bits, vol->sectors_per_fat, vol->root_entries_count)); 553 DPRINTF(0, ("root directory starts at sector %lx (cluster %lx), data at sector %lx\n", vol->root_start, vol->root_vnode.cluster, vol->data_start)); 554 DPRINTF(0, ("%lx total clusters, %lx free\n", vol->total_clusters, vol->free_clusters)); 555 DPRINTF(0, ("fat mirroring is %s, fs info sector at sector %x\n", (vol->fat_mirrored) ? "on" : "off", vol->fsinfo_sector)); 616 DPRINTF(0, ("mounting %s (id %lx, device %x, media descriptor %x)\n", 617 vol->device, vol->id, vol->fd, vol->media_descriptor)); 618 DPRINTF(0, ("%lx bytes/sector, %lx sectors/cluster\n", 619 vol->bytes_per_sector, vol->sectors_per_cluster)); 620 DPRINTF(0, ("%lx reserved sectors, %lx total sectors\n", 621 vol->reserved_sectors, vol->total_sectors)); 622 DPRINTF(0, ("%lx %d-bit fats, %lx sectors/fat, %lx root entries\n", 623 vol->fat_count, vol->fat_bits, vol->sectors_per_fat, 624 vol->root_entries_count)); 625 DPRINTF(0, ("root directory starts at sector %lx (cluster %lx), data at sector %lx\n", 626 vol->root_start, vol->root_vnode.cluster, vol->data_start)); 627 DPRINTF(0, ("%lx total clusters, %lx free\n", 628 vol->total_clusters, vol->free_clusters)); 629 DPRINTF(0, ("fat mirroring is %s, fs info sector at sector %x\n", 630 (vol->fat_mirrored) ? "on" : "off", vol->fsinfo_sector)); 556 631 DPRINTF(0, ("last allocated cluster = %lx\n", vol->last_allocated)); 557 632 558 633 if (vol->fat_bits == 32) { … … 575 650 vol->root_vnode.dirty = false; 576 651 dlist_add(vol, vol->root_vnode.vnid); 577 652 578 // find volume label (supercedes any label in the bpb)579 {580 struct diri diri;581 uint8 *buffer;582 buffer = diri_init(vol, vol->root_vnode.cluster, 0, &diri);583 for (; buffer; buffer = diri_next_entry(&diri)) {584 if ((buffer[0x0b] & FAT_VOLUME) && (buffer[0x0b] != 0xf)585 && (buffer[0] != 0xe5)) {586 vol->vol_entry = diri.current_index;587 memcpy(vol->vol_label, buffer, 11);588 dosfs_trim_spaces(vol->vol_label);589 break;590 }591 }592 653 593 diri_free(&diri);594 }595 596 654 DPRINTF(0, ("root vnode id = %Lx\n", vol->root_vnode.vnid)); 597 655 DPRINTF(0, ("volume label [%s] (%lx)\n", vol->vol_label, vol->vol_entry)); 598 656 … … 604 662 return B_NO_ERROR; 605 663 606 664 error3: 607 dlist_uninit(vol);665 uninit_vcache(vol); 608 666 error2: 609 uninit_vcache(vol);667 volume_uninit(vol); 610 668 error1: 611 block_cache_delete(vol->fBlockCache, false);612 error:613 669 if (!(vol->flags & B_FS_IS_READONLY) && (vol->flags & B_FS_IS_REMOVABLE) 614 670 && (vol->fs_flags & FS_FLAGS_LOCK_DOOR)) { 615 lock_removable_device( vol->fd, false);671 lock_removable_device(fd, false); 616 672 } 673 close(fd); 617 674 error0: 618 close(vol->fd);619 free(vol);620 675 return err >= B_NO_ERROR ? EINVAL : err; 621 676 } 622 677 … … 693 748 dosfs_read_label(false, buf, name); 694 749 } 695 750 751 // find volume label (supercedes any label in the bpb) 752 { 753 nspace *vol; 754 vol = volume_init(fd, buf, 0, 0, NULL); 755 if (vol != NULL) 756 { 757 strlcpy(name, vol->vol_label, 12); 758 volume_uninit(vol); 759 } 760 } 761 696 762 cookie = (identify_cookie *)malloc(sizeof(identify_cookie)); 697 763 if (!cookie) 698 764 return -1;