1/* 2 Copyright 1999-2001, Be Incorporated. All Rights Reserved. 3 This file may be used under the terms of the Be Sample Code License. 4*/ 5 6 7#include "dosfs.h" 8 9#include "system_dependencies.h" 10 11#include "attr.h" 12#include "dir.h" 13#include "dlist.h" 14#include "fat.h" 15#include "file.h" 16#include "iter.h" 17#include "mkdos.h" 18#include "util.h" 19#include "vcache.h" 20 21 22extern const char *build_time, *build_date; 23 24/* debug levels */ 25int debug_attr = 0, debug_dir = 0, debug_dlist = 0, debug_dosfs = 0, 26 debug_encodings = 0, debug_fat = 0, debug_file = 0, 27 debug_iter = 0, debug_vcache = 0; 28 29#define DPRINTF(a,b) if (debug_dosfs > (a)) dprintf b 30 31static status_t get_fsinfo(nspace *vol, uint32 *free_count, uint32 *last_allocated); 32 33 34#if DEBUG 35 36int32 instances = 0; 37 38static int 39debug_fat_nspace(int argc, char **argv) 40{ 41 int i; 42 for (i = 1; i < argc; i++) { 43 nspace *vol = (nspace *)strtoul(argv[i], NULL, 0); 44 if (vol == NULL) 45 continue; 46 47 kprintf("fat nspace @ %p\n", vol); 48 kprintf("id: %" B_PRIdDEV ", fd: %d, device: %s, flags %" B_PRIu32 "\n", 49 vol->id, vol->fd, vol->device, vol->flags); 50 kprintf("bytes/sector = %" B_PRIu32 ", sectors/cluster = %" B_PRIu32 51 ", reserved sectors = %" B_PRIu32 "\n", vol->bytes_per_sector, 52 vol->sectors_per_cluster, vol->reserved_sectors); 53 kprintf("%" B_PRIu32 " fats, %" B_PRIu32 " root entries, %" B_PRIu32 54 " total sectors, %" B_PRIu32 " sectors/fat\n", vol->fat_count, 55 vol->root_entries_count, vol->total_sectors, vol->sectors_per_fat); 56 kprintf("media descriptor %" B_PRIu8 ", fsinfo sector %" B_PRIu16 57 ", %" B_PRIu32 " clusters, %" B_PRIu32 " free\n", 58 vol->media_descriptor, vol->fsinfo_sector, vol->total_clusters, 59 vol->free_clusters); 60 kprintf("%" B_PRIu8 "-bit fat, mirrored %s, active %" B_PRIu8 "\n", 61 vol->fat_bits, vol->fat_mirrored ? "yes" : "no", vol->active_fat); 62 kprintf("root start %" B_PRIu32 ", %" B_PRIu32 63 " root sectors, root vnode @ %p\n", vol->root_start, 64 vol->root_sectors, &(vol->root_vnode)); 65 kprintf("label entry %" B_PRIu32 ", label %s\n", vol->vol_entry, 66 vol->vol_label); 67 kprintf("data start %" B_PRIu32 ", last allocated %" B_PRIu32 "\n", 68 vol->data_start, vol->last_allocated); 69 kprintf("last fake vnid %" B_PRIdINO ", vnid cache %" B_PRIu32 70 " entries @ (%p %p)\n", vol->vcache.cur_vnid, 71 vol->vcache.cache_size, vol->vcache.by_vnid, vol->vcache.by_loc); 72 kprintf("dlist entries: %" B_PRIu32 "/%" B_PRIu32 " @ %p\n", 73 vol->dlist.entries, vol->dlist.allocated, vol->dlist.vnid_list); 74 75 dump_vcache(vol); 76 dlist_dump(vol); 77 } 78 return B_OK; 79} 80 81 82static int 83debug_dvnode(int argc, char **argv) 84{ 85 int i; 86 87 if (argc < 2) { 88 kprintf("dvnode vnode\n"); 89 return B_OK; 90 } 91 92 for (i = 1; i < argc; i++) { 93 vnode *n = (vnode *)strtoul(argv[i], NULL, 0); 94 if (!n) continue; 95 96 kprintf("vnode @ %p", n); 97 98 kprintf(" (%s)", n->filename); 99 kprintf("\nvnid %" B_PRIdINO ", dir vnid %" B_PRIdINO "\n", n->vnid, 100 n->dir_vnid); 101 kprintf("iteration %" B_PRIu32 ", si=%" B_PRIu32 ", ei=%" B_PRIu32 102 ", cluster=%" B_PRIu32 "\n", n->iteration, n->sindex, n->eindex, 103 n->cluster); 104 kprintf("mode %#" B_PRIx32 ", size %" B_PRIdOFF ", time %" B_PRIdTIME 105 ", crtime %" B_PRIdTIME "\n", n->mode, n->st_size, n->st_time, 106 n->st_crtim); 107 kprintf("end cluster = %" B_PRIu32 "\n", n->end_cluster); 108 if (n->mime) kprintf("mime type %s\n", n->mime); 109 } 110 111 return B_OK; 112} 113 114 115static int 116debug_dc2s(int argc, char **argv) 117{ 118 int i; 119 nspace *vol; 120 121 if (argc < 3) { 122 kprintf("dc2s nspace cluster\n"); 123 return B_OK; 124 } 125 126 vol = (nspace *)strtoul(argv[1], NULL, 0); 127 if (vol == NULL) 128 return B_OK; 129 130 for (i=2;i<argc;i++) { 131 uint32 cluster = strtoul(argv[i], NULL, 0); 132 kprintf("cluster %" B_PRIu32 " = block %" B_PRIdOFF "\n", cluster, 133 vol->data_start + (off_t)(cluster - 2) * vol->sectors_per_cluster); 134 } 135 136 return B_OK; 137} 138 139#endif 140 141 142static void 143dosfs_trim_spaces(char *label) 144{ 145 uint8 index; 146 for (index = 10; index > 0; index--) { 147 if (label[index] == ' ') 148 label[index] = 0; 149 else 150 break; 151 } 152} 153 154 155static bool 156dosfs_read_label(bool fat32, uint8 *buffer, char *label) 157{ 158 uint8 check = fat32 ? 0x42 : 0x29; 159 uint8 offset = fat32 ? 0x47 : 0x2b; 160 161 if (buffer[check] == 0x29 162 && memcmp(buffer + offset, " ", 11) != 0) { 163 memcpy(label, buffer + offset, 11); 164 dosfs_trim_spaces(label); 165 return true; 166 } 167 168 return false; 169} 170 171 172static nspace* 173volume_init(int fd, uint8* buf, 174 const int flags, int fs_flags, 175 device_geometry *geo) 176{ 177 uint8 media_buf[512]; 178 int i; 179 status_t err; 180 181 nspace* vol = (nspace *)calloc(sizeof(nspace), 1); 182 if (vol == NULL) { 183 dprintf("dosfs error: out of memory\n"); 184 return NULL; 185 } 186 187 vol->flags = flags; 188 vol->fs_flags = fs_flags; 189 vol->fd = fd; 190 191 // only check boot signature on hard disks to account for broken mtools 192 // behavior 193 if ((buf[0x1fe] != 0x55 || buf[0x1ff] != 0xaa) && buf[0x15] == 0xf8) 194 goto error; 195 196 if (!memcmp(buf + 3, "NTFS ", 8) || !memcmp(buf + 3, "HPFS ", 8)) { 197 dprintf("dosfs error: %4.4s, not FAT\n", buf + 3); 198 goto error; 199 } 200 201 // first fill in the universal fields from the bpb 202 vol->bytes_per_sector = read16(buf, 0xb); 203 if (vol->bytes_per_sector != 0x200 && vol->bytes_per_sector != 0x400 204 && vol->bytes_per_sector != 0x800 && vol->bytes_per_sector != 0x1000) { 205 dprintf("dosfs error: unsupported bytes per sector (%" B_PRIu32 ")\n", 206 vol->bytes_per_sector); 207 goto error; 208 } 209 210 vol->sectors_per_cluster = i = buf[0xd]; 211 if (i != 1 && i != 2 && i != 4 && i != 8 212 && i != 0x10 && i != 0x20 && i != 0x40 && i != 0x80) { 213 dprintf("dosfs error: unsupported sectors per cluster (%d)\n", i); 214 goto error; 215 } 216 217 vol->reserved_sectors = read16(buf, 0xe); 218 219 vol->fat_count = buf[0x10]; 220 if (vol->fat_count == 0 || vol->fat_count > 8) { 221 dprintf("dosfs error: unreasonable fat count (%" B_PRIu32 ")\n", 222 vol->fat_count); 223 goto error; 224 } 225 226 vol->media_descriptor = buf[0x15]; 227 // check media descriptor versus known types 228 if (buf[0x15] != 0xf0 && buf[0x15] < 0xf8) { 229 dprintf("dosfs error: invalid media descriptor byte\n"); 230 goto error; 231 } 232 233 vol->vol_entry = -2; // for now, assume there is no volume entry 234 strcpy(vol->vol_label, "no name"); 235 236 // now become more discerning citizens 237 vol->sectors_per_fat = read16(buf, 0x16); 238 if (vol->sectors_per_fat == 0) { 239 // fat32 land 240 vol->fat_bits = 32; 241 vol->sectors_per_fat = read32(buf, 0x24); 242 vol->total_sectors = read32(buf, 0x20); 243 244 vol->fsinfo_sector = read16(buf, 0x30); 245 if (vol->fsinfo_sector != 0xffff 246 && vol->fsinfo_sector >= vol->reserved_sectors) { 247 dprintf("dosfs error: fsinfo sector too large (0x%x)\n", 248 vol->fsinfo_sector); 249 goto error; 250 } 251 252 vol->fat_mirrored = !(buf[0x28] & 0x80); 253 vol->active_fat = !vol->fat_mirrored ? (buf[0x28] & 0xf) : 0; 254 255 vol->data_start = vol->reserved_sectors + vol->fat_count 256 * vol->sectors_per_fat; 257 vol->total_clusters = (vol->total_sectors - vol->data_start) 258 / vol->sectors_per_cluster; 259 260 vol->root_vnode.cluster = read32(buf, 0x2c); 261 if (vol->root_vnode.cluster >= vol->total_clusters) { 262 dprintf("dosfs error: root vnode cluster too large (0x%" B_PRIu32 263 ")\n", vol->root_vnode.cluster); 264 goto error; 265 } 266 267 if (dosfs_read_label(true, buf, vol->vol_label)) 268 vol->vol_entry = -1; 269 } else { 270 // fat12 & fat16 271 if (vol->fat_count != 2) { 272 dprintf("dosfs error: claims %" B_PRIu32 " fat tables\n", 273 vol->fat_count); 274 goto error; 275 } 276 277 vol->root_entries_count = read16(buf, 0x11); 278 if (vol->root_entries_count % (vol->bytes_per_sector / 0x20)) { 279 dprintf("dosfs error: invalid number of root entries\n"); 280 goto error; 281 } 282 283 vol->fsinfo_sector = 0xffff; 284 vol->total_sectors = read16(buf, 0x13); // partition size 285 if (vol->total_sectors == 0) 286 vol->total_sectors = read32(buf, 0x20); 287 288 if (geo != NULL) { 289 /* 290 Zip disks that were formatted at iomega have an incorrect number 291 of sectors. They say that they have 196576 sectors but they 292 really only have 196192. This check is a work-around for their 293 brain-deadness. 294 */ 295 unsigned char bogus_zip_data[] = { 296 0x00, 0x02, 0x04, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 297 0xf8, 0xc0, 0x00, 0x20, 0x00, 0x40, 0x00, 0x20, 0x00, 0x00 298 }; 299 300 if (memcmp(buf + 0x0b, bogus_zip_data, sizeof(bogus_zip_data)) == 0 301 && vol->total_sectors == 196576 302 && ((off_t)geo->sectors_per_track * (off_t)geo->cylinder_count 303 * (off_t)geo->head_count) == 196192) { 304 vol->total_sectors = 196192; 305 } 306 } 307 308 vol->fat_mirrored = true; 309 vol->active_fat = 0; 310 311 vol->root_start = vol->reserved_sectors + vol->fat_count 312 * vol->sectors_per_fat; 313 vol->root_sectors = vol->root_entries_count * 0x20 314 / vol->bytes_per_sector; 315 vol->root_vnode.cluster = 1; 316 vol->root_vnode.end_cluster = 1; 317 vol->root_vnode.st_size = vol->root_sectors * vol->bytes_per_sector; 318 319 vol->data_start = vol->root_start + vol->root_sectors; 320 vol->total_clusters = (vol->total_sectors - vol->data_start) 321 / vol->sectors_per_cluster; 322 323 // XXX: uncertain about border cases; win32 sdk says cutoffs are at 324 // at ff6/ff7 (or fff6/fff7), but that doesn't make much sense 325 if (vol->total_clusters > 0xff1) 326 vol->fat_bits = 16; 327 else 328 vol->fat_bits = 12; 329 330 if (dosfs_read_label(false, buf, vol->vol_label)) 331 vol->vol_entry = -1; 332 } 333 334 // perform sanity checks on the FAT 335 336 // the media descriptor in active FAT should match the one in the BPB 337 if ((err = read_pos(vol->fd, vol->bytes_per_sector * (vol->reserved_sectors 338 + vol->active_fat * vol->sectors_per_fat), 339 (void *)media_buf, 0x200)) != 0x200) { 340 dprintf("dosfs error: error reading FAT\n"); 341 goto error; 342 } 343 344 if (media_buf[0] != vol->media_descriptor) { 345 dprintf("dosfs error: media descriptor mismatch (%x != %x)\n", media_buf[0], 346 vol->media_descriptor); 347 goto error; 348 } 349 350 if (vol->fat_mirrored) { 351 uint32 i; 352 uint8 mirror_media_buf[512]; 353 for (i = 0; i < vol->fat_count; i++) { 354 if (i != vol->active_fat) { 355 DPRINTF(1, ("checking fat #%" B_PRIu32 "\n", i)); 356 mirror_media_buf[0] = ~media_buf[0]; 357 if ((err = read_pos(vol->fd, vol->bytes_per_sector 358 * (vol->reserved_sectors + vol->sectors_per_fat * i), 359 (void *)mirror_media_buf, 0x200)) != 0x200) { 360 dprintf("dosfs error: error reading FAT %" B_PRIu32 "\n", 361 i); 362 goto error; 363 } 364 365 if (mirror_media_buf[0] != vol->media_descriptor) { 366 dprintf("dosfs error: media descriptor mismatch in fat # " 367 "%" B_PRIu32 " (%" B_PRIu8 " != %" B_PRIu8 ")\n", i, 368 mirror_media_buf[0], vol->media_descriptor); 369 goto error; 370 } 371#if 0 372 // checking for exact matches of fats is too 373 // restrictive; allow these to go through in 374 // case the fat is corrupted for some reason 375 if (memcmp(media_buf, mirror_media_buf, 0x200)) { 376 dprintf("dosfs error: fat %d doesn't match active fat " 377 "(%d)\n", i, vol->active_fat); 378 goto error; 379 } 380#endif 381 } 382 } 383 } 384 385 /* check that the partition is large enough to contain the file system */ 386 if (geo != NULL 387 && vol->total_sectors > 388 geo->sectors_per_track * geo->cylinder_count 389 * geo->head_count) { 390 dprintf("dosfs: volume extends past end of partition, mounting read-only\n"); 391 vol->flags |= B_FS_IS_READONLY; 392 } 393 394 // now we are convinced of the drive's validity 395 396 // this will be updated later if fsinfo exists 397 vol->last_allocated = 2; 398 vol->beos_vnid = INVALID_VNID_BITS_MASK; 399 400 // initialize block cache 401 vol->fBlockCache = block_cache_create(vol->fd, vol->total_sectors, 402 vol->bytes_per_sector, (vol->flags & B_FS_IS_READONLY) != 0); 403 if (vol->fBlockCache == NULL) { 404 dprintf("dosfs error: error initializing block cache\n"); 405 goto error; 406 } 407 408 // find volume label (supercedes any label in the bpb) 409 { 410 struct diri diri; 411 uint8 *buffer; 412 buffer = diri_init(vol, vol->root_vnode.cluster, 0, &diri); 413 for (; buffer; buffer = diri_next_entry(&diri)) { 414 if ((buffer[0x0b] & FAT_VOLUME) && (buffer[0x0b] != 0xf) 415 && (buffer[0] != 0xe5)) { 416 vol->vol_entry = diri.current_index; 417 memcpy(vol->vol_label, buffer, 11); 418 dosfs_trim_spaces(vol->vol_label); 419 break; 420 } 421 } 422 } 423 424 DPRINTF(0, ("root vnode id = %" B_PRIdINO "\n", vol->root_vnode.vnid)); 425 DPRINTF(0, ("volume label [%s] (%" B_PRIu32 ")\n", vol->vol_label, 426 vol->vol_entry)); 427 428 return vol; 429 430error: 431 free(vol); 432 return NULL; 433} 434 435 436static void 437volume_uninit(nspace *vol) 438{ 439 block_cache_delete(vol->fBlockCache, false); 440 free(vol); 441} 442 443 444static void 445volume_count_free_cluster(nspace *vol) 446{ 447 status_t err; 448 449 if (vol->flags & B_FS_IS_READONLY) 450 vol->free_clusters = 0; 451 else { 452 uint32 free_count = 0, last_allocated = 0; 453 err = get_fsinfo(vol, &free_count, &last_allocated); 454 if (err >= 0) { 455 if (free_count < vol->total_clusters) 456 vol->free_clusters = free_count; 457 else { 458 dprintf("dosfs error: free cluster count from fsinfo block " 459 "invalid %" B_PRIu32 "\n", free_count); 460 err = -1; 461 } 462 463 if (last_allocated < vol->total_clusters) 464 vol->last_allocated = last_allocated; //update to a closer match 465 } 466 467 if (err < 0) { 468 if ((err = count_free_clusters(vol)) < 0) { 469 dprintf("dosfs error: error counting free clusters (%s)\n", 470 strerror(err)); 471 return; 472 } 473 vol->free_clusters = err; 474 } 475 } 476} 477 478 479static status_t 480mount_fat_disk(const char *path, fs_volume *_vol, const int flags, 481 nspace** newVol, int fs_flags, int op_sync_mode) 482{ 483 nspace *vol = NULL; 484 uint8 buf[512]; 485 device_geometry geo; 486 status_t err; 487 int fd; 488 int vol_flags; 489 490 vol_flags = B_FS_IS_PERSISTENT | B_FS_HAS_MIME; 491 492 // open read-only for now 493 if ((err = (fd = open(path, O_RDONLY | O_NOCACHE))) < 0) { 494 dprintf("dosfs error: unable to open %s (%s)\n", path, strerror(err)); 495 goto error0; 496 } 497 498 // get device characteristics 499 if (ioctl(fd, B_GET_GEOMETRY, &geo, sizeof(device_geometry)) < 0) { 500 struct stat st; 501 if (fstat(fd, &st) >= 0 && S_ISREG(st.st_mode)) { 502 /* support mounting disk images */ 503 geo.bytes_per_sector = 0x200; 504 geo.sectors_per_track = 1; 505 geo.cylinder_count = st.st_size / 0x200; 506 geo.head_count = 1; 507 geo.read_only = !(st.st_mode & S_IWUSR); 508 geo.removable = true; 509 } else { 510 dprintf("dosfs error: error getting device geometry\n"); 511 goto error1; 512 } 513 } 514 515 if (geo.bytes_per_sector != 0x200 && geo.bytes_per_sector != 0x400 516 && geo.bytes_per_sector != 0x800 && geo.bytes_per_sector != 0x1000) { 517 dprintf("dosfs error: unsupported device block size (%" B_PRIu32 ")\n", 518 geo.bytes_per_sector); 519 goto error1; 520 } 521 522 if (geo.removable) { 523 DPRINTF(0, ("%s is removable\n", path)); 524 vol_flags |= B_FS_IS_REMOVABLE; 525 } 526 527 if (geo.read_only || (flags & B_MOUNT_READ_ONLY)) { 528 DPRINTF(0, ("%s is read-only\n", path)); 529 vol_flags |= B_FS_IS_READONLY; 530 } else { 531 // reopen it with read/write permissions 532 close(fd); 533 if ((err = (fd = open(path, O_RDWR | O_NOCACHE))) < 0) { 534 dprintf("dosfs error: unable to open %s (%s)\n", path, 535 strerror(err)); 536 goto error0; 537 } 538 } 539 540 // see if we need to go into op sync mode 541 fs_flags &= ~FS_FLAGS_OP_SYNC; 542 switch (op_sync_mode) { 543 case 1: 544 if ((vol_flags & B_FS_IS_REMOVABLE) == 0) { 545 // we're not removable, so skip op_sync 546 break; 547 } 548 // supposed to fall through 549 550 case 2: 551 dprintf("dosfs: mounted with op_sync enabled\n"); 552 fs_flags |= FS_FLAGS_OP_SYNC; 553 break; 554 555 case 0: 556 default: 557 break; 558 } 559 560 // read in the boot sector 561 if ((err = read_pos(fd, 0, (void *)buf, 512)) != 512) { 562 dprintf("dosfs error: error reading boot sector\n"); 563 goto error1; 564 } 565 566 vol = volume_init(fd, buf, vol_flags, fs_flags, &geo); 567 if (vol == NULL) { 568 dprintf("dosfs error: failed to initialize volume\n"); 569 err = B_ERROR; 570 goto error1; 571 } 572 573 vol->volume = _vol; 574 vol->id = _vol->id; 575 strncpy(vol->device, path, sizeof(vol->device)); 576 577 { 578 void *handle; 579 handle = load_driver_settings("fat"); 580 vol->respect_disk_image = 581 get_driver_boolean_parameter(handle, "respect", true, true); 582 unload_driver_settings(handle); 583 } 584 585 // Initialize the vnode cache 586 if (init_vcache(vol) != B_OK) { 587 dprintf("dosfs error: error initializing vnode cache\n"); 588 goto error2; 589 } 590 591 // and the dlist cache 592 if (dlist_init(vol) != B_OK) { 593 dprintf("dosfs error: error initializing dlist cache\n"); 594 goto error3; 595 } 596 597 volume_count_free_cluster(vol); 598 599 DPRINTF(0, ("built at %s on %s\n", build_time, build_date)); 600 DPRINTF(0, ("mounting %s (id %" B_PRIdDEV ", device %u, media descriptor %" 601 B_PRIu8 ")\n", vol->device, vol->id, vol->fd, vol->media_descriptor)); 602 DPRINTF(0, ("%" B_PRIu32 " bytes/sector, %" B_PRIu32 " sectors/cluster\n", 603 vol->bytes_per_sector, vol->sectors_per_cluster)); 604 DPRINTF(0, ("%" B_PRIu32 " reserved sectors, %" B_PRIu32 " total sectors\n", 605 vol->reserved_sectors, vol->total_sectors)); 606 DPRINTF(0, ("%" B_PRIu32 " %" B_PRIu8 "-bit fats, %" B_PRIu32 607 " sectors/fat, %" B_PRIu32 " root entries\n", vol->fat_count, 608 vol->fat_bits, vol->sectors_per_fat, vol->root_entries_count)); 609 DPRINTF(0, ("root directory starts at sector %" B_PRIu32 " (cluster %" 610 B_PRIu32 "), data at sector %" B_PRIu32 "\n", vol->root_start, 611 vol->root_vnode.cluster, vol->data_start)); 612 DPRINTF(0, ("%" B_PRIu32 " total clusters, %" B_PRIu32 " free\n", 613 vol->total_clusters, vol->free_clusters)); 614 DPRINTF(0, ("fat mirroring is %s, fs info sector at sector %" B_PRIu16 "\n", 615 vol->fat_mirrored ? "on" : "off", vol->fsinfo_sector)); 616 DPRINTF(0, ("last allocated cluster = %" B_PRIu32 "\n", 617 vol->last_allocated)); 618 619 if (vol->fat_bits == 32) { 620 // now that the block cache has been initialised, we can figure 621 // out the length of the root directory with count_clusters() 622 vol->root_vnode.st_size = count_clusters(vol, vol->root_vnode.cluster) 623 * vol->bytes_per_sector * vol->sectors_per_cluster; 624 vol->root_vnode.end_cluster = get_nth_fat_entry(vol, 625 vol->root_vnode.cluster, vol->root_vnode.st_size 626 / vol->bytes_per_sector / vol->sectors_per_cluster - 1); 627 } 628 629 // initialize root vnode 630 vol->root_vnode.vnid = vol->root_vnode.dir_vnid = GENERATE_DIR_CLUSTER_VNID( 631 vol->root_vnode.cluster, vol->root_vnode.cluster); 632 vol->root_vnode.sindex = vol->root_vnode.eindex = 0xffffffff; 633 vol->root_vnode.mode = FAT_SUBDIR; 634 time(&(vol->root_vnode.st_time)); 635 vol->root_vnode.st_crtim = vol->root_vnode.st_time; 636 vol->root_vnode.mime = NULL; 637 vol->root_vnode.dirty = false; 638 dlist_add(vol, vol->root_vnode.vnid); 639 640 641 DPRINTF(0, ("root vnode id = %" B_PRIdINO "\n", vol->root_vnode.vnid)); 642 DPRINTF(0, ("volume label [%s] (%" B_PRIu32 ")\n", vol->vol_label, 643 vol->vol_entry)); 644 645 *newVol = vol; 646 return B_NO_ERROR; 647 648error3: 649 uninit_vcache(vol); 650error2: 651 volume_uninit(vol); 652error1: 653 close(fd); 654error0: 655 return err >= B_NO_ERROR ? EINVAL : err; 656} 657 658 659// #pragma mark - Scanning 660 661 662typedef struct identify_cookie { 663 uint32 bytes_per_sector; 664 uint32 total_sectors; 665 char name[12]; 666} identify_cookie; 667 668 669static float 670dosfs_identify_partition(int fd, partition_data *partition, void **_cookie) 671{ 672 uint8 buf[512]; 673 int i; 674 uint32 bytes_per_sector; 675 uint32 fatCount; 676 uint32 total_sectors; 677 uint32 sectors_per_fat; 678 char name[12]; 679 identify_cookie *cookie; 680 681 // read in the boot sector 682 if (read_pos(fd, 0, buf, 512) != 512) 683 return -1; 684 685 // only check boot signature on hard disks to account for broken mtools 686 // behavior 687 if ((buf[0x1fe] != 0x55 || buf[0x1ff] != 0xaa) && buf[0x15] == 0xf8) 688 return -1; 689 if (!memcmp(buf + 3, "NTFS ", 8) || !memcmp(buf + 3, "HPFS ", 8)) 690 return -1; 691 692 // first fill in the universal fields from the bpb 693 bytes_per_sector = read16(buf, 0xb); 694 if (bytes_per_sector != 0x200 && bytes_per_sector != 0x400 695 && bytes_per_sector != 0x800 && bytes_per_sector != 0x1000) { 696 return -1; 697 } 698 699 // must be a power of two 700 i = buf[0xd]; 701 if (i != 1 && i != 2 && i != 4 && i != 8 && i != 0x10 && i != 0x20 702 && i != 0x40 && i != 0x80) 703 return -1; 704 705 fatCount = buf[0x10]; 706 if (fatCount == 0 || fatCount > 8) 707 return -1; 708 709 // check media descriptor versus known types 710 if (buf[0x15] != 0xf0 && buf[0x15] < 0xf8) 711 return -1; 712 713 name[0] = 0; 714 sectors_per_fat = read16(buf, 0x16); 715 if (sectors_per_fat == 0) { 716 total_sectors = read32(buf, 0x20); 717 dosfs_read_label(true, buf, name); 718 } else { 719 total_sectors = read16(buf, 0x13); 720 // partition size 721 if (total_sectors == 0) 722 total_sectors = read32(buf, 0x20); 723 724 dosfs_read_label(false, buf, name); 725 } 726 727 // find volume label (supercedes any label in the bpb) 728 { 729 nspace *vol; 730 vol = volume_init(fd, buf, 0, 0, NULL); 731 if (vol != NULL) 732 { 733 strlcpy(name, vol->vol_label, 12); 734 volume_uninit(vol); 735 } 736 } 737 738 cookie = (identify_cookie *)malloc(sizeof(identify_cookie)); 739 if (!cookie) 740 return -1; 741 742 cookie->bytes_per_sector = bytes_per_sector; 743 cookie->total_sectors = total_sectors; 744 sanitize_name(name, 12); 745 strlcpy(cookie->name, name, 12); 746 *_cookie = cookie; 747 748 return 0.8f; 749} 750 751 752static status_t 753dosfs_scan_partition(int fd, partition_data *partition, void *_cookie) 754{ 755 identify_cookie *cookie = (identify_cookie *)_cookie; 756 partition->status = B_PARTITION_VALID; 757 partition->flags |= B_PARTITION_FILE_SYSTEM; 758 partition->content_size = cookie->total_sectors * cookie->bytes_per_sector; 759 partition->block_size = cookie->bytes_per_sector; 760 partition->content_name = strdup(cookie->name); 761 if (partition->content_name == NULL) 762 return B_NO_MEMORY; 763 764 return B_OK; 765} 766 767 768static void 769dosfs_free_identify_partition_cookie(partition_data *partition, void *_cookie) 770{ 771 identify_cookie *cookie = (identify_cookie *)_cookie; 772 free(cookie); 773} 774 775 776// #pragma mark - 777 778 779static status_t 780dosfs_mount(fs_volume *_vol, const char *device, uint32 flags, 781 const char *args, ino_t *_rootID) 782{ 783 int result; 784 nspace *vol; 785 void *handle; 786 int op_sync_mode = 0; 787 int fs_flags = 0; 788 789 handle = load_driver_settings("fat"); 790 if (handle != NULL) { 791 debug_attr = strtoul(get_driver_parameter(handle, "debug_attr", "0", "0"), NULL, 0); 792 debug_dir = strtoul(get_driver_parameter(handle, "debug_dir", "0", "0"), NULL, 0); 793 debug_dlist = strtoul(get_driver_parameter(handle, "debug_dlist", "0", "0"), NULL, 0); 794 debug_dosfs = strtoul(get_driver_parameter(handle, "debug_dosfs", "0", "0"), NULL, 0); 795 debug_encodings = strtoul(get_driver_parameter(handle, "debug_encodings", "0", "0"), NULL, 0); 796 debug_fat = strtoul(get_driver_parameter(handle, "debug_fat", "0", "0"), NULL, 0); 797 debug_file = strtoul(get_driver_parameter(handle, "debug_file", "0", "0"), NULL, 0); 798 debug_iter = strtoul(get_driver_parameter(handle, "debug_iter", "0", "0"), NULL, 0); 799 debug_vcache = strtoul(get_driver_parameter(handle, "debug_vcache", "0", "0"), NULL, 0); 800 801 op_sync_mode = strtoul(get_driver_parameter(handle, "op_sync_mode", "0", "0"), NULL, 0); 802 if (op_sync_mode < 0 || op_sync_mode > 2) 803 op_sync_mode = 0; 804 if (strcasecmp(get_driver_parameter(handle, "lock_device", "true", "true"), "false") == 0) { 805 dprintf("dosfs: mounted with lock_device = false\n"); 806 } else { 807 dprintf("dosfs: mounted with lock_device = true\n"); 808 fs_flags |= FS_FLAGS_LOCK_DOOR; 809 } 810 811 unload_driver_settings(handle); 812 } 813 814 /* args is a command line option; dosfs doesn't use any so we can ignore it */ 815 816 // Try and mount volume as a FAT volume 817 if ((result = mount_fat_disk(device, _vol, flags, &vol, fs_flags, 818 op_sync_mode)) == B_NO_ERROR) { 819 char name[32]; 820 821 *_rootID = vol->root_vnode.vnid; 822 _vol->private_volume = (void *)vol; 823 _vol->ops = &gFATVolumeOps; 824 825 // You MUST do this. Create the vnode for the root. 826 result = publish_vnode(_vol, *_rootID, (void*)&(vol->root_vnode), 827 &gFATVnodeOps, make_mode(vol, &vol->root_vnode), 0); 828 if (result != B_NO_ERROR) { 829 dprintf("error creating new vnode (%s)\n", strerror(result)); 830 goto error; 831 } 832 sprintf(name, "fat lock %" B_PRIdDEV, vol->id); 833 recursive_lock_init_etc(&(vol->vlock), name, MUTEX_FLAG_CLONE_NAME); 834 835#if DEBUG 836 if (atomic_add(&instances, 1) == 0) { 837 add_debugger_command("fat", debug_fat_nspace, "dump a fat nspace structure"); 838 add_debugger_command("dvnode", debug_dvnode, "dump a fat vnode structure"); 839 add_debugger_command("dfvnid", debug_dfvnid, "find a vnid in the vnid cache"); 840 add_debugger_command("dfloc", debug_dfloc, "find a loc in the vnid cache"); 841 add_debugger_command("dc2s", debug_dc2s, "calculate sector for cluster"); 842 } 843#endif 844 } 845 846 return result; 847 848error: 849 block_cache_delete(vol->fBlockCache, false); 850 dlist_uninit(vol); 851 uninit_vcache(vol); 852 free(vol); 853 return EINVAL; 854} 855 856 857static void 858update_fsinfo(nspace *vol) 859{ 860 if (vol->fat_bits == 32 && vol->fsinfo_sector != 0xffff 861 && (vol->flags & B_FS_IS_READONLY) == 0) { 862 uchar *buffer; 863 status_t status = block_cache_get_writable_etc(vol->fBlockCache, 864 vol->fsinfo_sector, 0, vol->bytes_per_sector, -1, 865 (void**)&buffer); 866 if (status == B_OK) { 867 if ((read32(buffer,0) == 0x41615252) && (read32(buffer,0x1e4) == 0x61417272) && (read16(buffer,0x1fe) == 0xaa55)) { 868 //number of free clusters 869 buffer[0x1e8] = (vol->free_clusters & 0xff); 870 buffer[0x1e9] = ((vol->free_clusters >> 8) & 0xff); 871 buffer[0x1ea] = ((vol->free_clusters >> 16) & 0xff); 872 buffer[0x1eb] = ((vol->free_clusters >> 24) & 0xff); 873 //cluster number of most recently allocated cluster 874 buffer[0x1ec] = (vol->last_allocated & 0xff); 875 buffer[0x1ed] = ((vol->last_allocated >> 8) & 0xff); 876 buffer[0x1ee] = ((vol->last_allocated >> 16) & 0xff); 877 buffer[0x1ef] = ((vol->last_allocated >> 24) & 0xff); 878 } else { 879 dprintf("update_fsinfo: fsinfo block has invalid magic number\n"); 880 block_cache_set_dirty(vol->fBlockCache, vol->fsinfo_sector, 881 false, -1); 882 } 883 block_cache_put(vol->fBlockCache, vol->fsinfo_sector); 884 } else { 885 dprintf("update_fsinfo: error getting fsinfo sector %x: %s\n", 886 vol->fsinfo_sector, strerror(status)); 887 } 888 } 889} 890 891 892static status_t 893get_fsinfo(nspace *vol, uint32 *free_count, uint32 *last_allocated) 894{ 895 uchar *buffer; 896 status_t result; 897 898 if ((vol->fat_bits != 32) || (vol->fsinfo_sector == 0xffff)) 899 return B_ERROR; 900 901 result = block_cache_get_etc(vol->fBlockCache, vol->fsinfo_sector, 0, 902 vol->bytes_per_sector, (const void**)&buffer); 903 if (result != B_OK) { 904 dprintf("get_fsinfo: error getting fsinfo sector %x: %s\n", 905 vol->fsinfo_sector, strerror(result)); 906 return result; 907 } 908 909 if ((read32(buffer,0) == 0x41615252) && (read32(buffer,0x1e4) == 0x61417272) && (read16(buffer,0x1fe) == 0xaa55)) { 910 *free_count = read32(buffer,0x1e8); 911 *last_allocated = read32(buffer,0x1ec); 912 result = B_OK; 913 } else { 914 dprintf("get_fsinfo: fsinfo block has invalid magic number\n"); 915 result = B_ERROR; 916 } 917 918 block_cache_put(vol->fBlockCache, vol->fsinfo_sector); 919 return result; 920} 921 922 923static status_t 924dosfs_unmount(fs_volume *_vol) 925{ 926 int result = B_NO_ERROR; 927 928 nspace* vol = (nspace*)_vol->private_volume; 929 930 RecursiveLocker lock(vol->vlock); 931 932 DPRINTF(0, ("dosfs_unmount volume %" B_PRIdDEV "\n", vol->id)); 933 934 update_fsinfo(vol); 935 936 // Unlike in BeOS, we need to put the reference to our root node ourselves 937 put_vnode(_vol, vol->root_vnode.vnid); 938 block_cache_delete(vol->fBlockCache, true); 939 940#if DEBUG 941 if (atomic_add(&instances, -1) == 1) { 942 remove_debugger_command("fat", debug_fat_nspace); 943 remove_debugger_command("dvnode", debug_dvnode); 944 remove_debugger_command("dfvnid", debug_dfvnid); 945 remove_debugger_command("dfloc", debug_dfloc); 946 remove_debugger_command("dc2s", debug_dc2s); 947 } 948#endif 949 950 dlist_uninit(vol); 951 uninit_vcache(vol); 952 953 result = close(vol->fd); 954 lock.Unlock(); 955 recursive_lock_destroy(&(vol->vlock)); 956 free(vol); 957 958#if USE_DMALLOC 959 check_mem(); 960#endif 961 962 return result; 963} 964 965 966// dosfs_read_fs_stat - Fill in fs_info struct for device. 967static status_t 968dosfs_read_fs_stat(fs_volume *_vol, struct fs_info * fss) 969{ 970 nspace* vol = (nspace*)_vol->private_volume; 971 972 RecursiveLocker lock(vol->vlock); 973 974 DPRINTF(1, ("dosfs_read_fs_stat called\n")); 975 976 // fss->dev and fss->root filled in by kernel 977 978 // File system flags. 979 fss->flags = vol->flags; 980 981 // FS block size. 982 fss->block_size = vol->bytes_per_sector * vol->sectors_per_cluster; 983 984 // IO size - specifies buffer size for file copying 985 fss->io_size = 65536; 986 987 // Total blocks 988 fss->total_blocks = vol->total_clusters; 989 990 // Free blocks 991 fss->free_blocks = vol->free_clusters; 992 993 // Device name. 994 strncpy(fss->device_name, vol->device, sizeof(fss->device_name)); 995 996 if (vol->vol_entry > -2) 997 strlcpy(fss->volume_name, vol->vol_label, sizeof(fss->volume_name)); 998 else { 999 // No name defined, let userspace decide of one 1000 fss->volume_name[0] = 0; 1001 } 1002 1003 sanitize_name(fss->volume_name, 12); 1004 1005 // File system name 1006 strcpy(fss->fsh_name, "fat"); 1007 1008 return B_OK; 1009} 1010 1011 1012static status_t 1013dosfs_write_fs_stat(fs_volume *_vol, const struct fs_info * fss, uint32 mask) 1014{ 1015 status_t result = B_ERROR; 1016 nspace* vol = (nspace*)_vol->private_volume; 1017 1018 RecursiveLocker lock(vol->vlock); 1019 1020 DPRINTF(0, ("dosfs_write_fs_stat called\n")); 1021 1022 /* if it's a r/o file system, then don't allow volume renaming */ 1023 if ((vol->flags & B_FS_IS_READONLY) == 0) 1024 return EROFS; 1025 1026 if (mask & FS_WRITE_FSINFO_NAME) { 1027 // sanitize name 1028 char name[11]; 1029 int i,j; 1030 memset(name, ' ', 11); 1031 DPRINTF(1, ("wfsstat: setting name to %s\n", fss->volume_name)); 1032 for (i=j=0;(i<11)&&(fss->volume_name[j]);j++) { 1033 char c = fss->volume_name[j]; 1034 if ((c >= 'a') && (c <= 'z')) c += 'A' - 'a'; 1035 // spaces acceptable in volume names 1036 if (strchr(sAcceptable, c) || (c == ' ')) 1037 name[i++] = c; 1038 } 1039 if (i == 0) // bad name, kiddo 1040 return EINVAL; 1041 DPRINTF(1, ("wfsstat: sanitized to [%11.11s]\n", name)); 1042 1043 if (vol->vol_entry == -1) { 1044 // stored in the bpb 1045 uchar *buffer; 1046 result = block_cache_get_writable_etc(vol->fBlockCache, 0, 1047 0, vol->bytes_per_sector, -1, (void**)&buffer); 1048 if (result != B_OK) 1049 return result; 1050 1051 if ((vol->sectors_per_fat == 0 && (buffer[0x42] != 0x29 1052 || strncmp((const char *)buffer + 0x47, vol->vol_label, 11) 1053 != 0)) 1054 || (vol->sectors_per_fat != 0 && (buffer[0x26] != 0x29 1055 || strncmp((const char *)buffer + 0x2b, vol->vol_label, 11) 1056 == 0))) { 1057 dprintf("dosfs_wfsstat: label mismatch\n"); 1058 block_cache_set_dirty(vol->fBlockCache, 0, false, -1); 1059 result = B_ERROR; 1060 } else { 1061 memcpy(buffer + 0x2b, name, 11); 1062 result = B_OK; 1063 } 1064 block_cache_put(vol->fBlockCache, 0); 1065 } else if (vol->vol_entry >= 0) { 1066 struct diri diri; 1067 uint8 *buffer; 1068 buffer = diri_init(vol, vol->root_vnode.cluster, vol->vol_entry, &diri); 1069 1070 // check if it is the same as the old volume label 1071 if (buffer == NULL || strncmp((const char *)buffer, vol->vol_label, 11) == 0) { 1072 dprintf("dosfs_wfsstat: label mismatch\n"); 1073 return B_ERROR; 1074 } 1075 1076 diri_make_writable(&diri); 1077 memcpy(buffer, name, 11); 1078 result = B_OK; 1079 } else { 1080 uint32 index; 1081 result = create_volume_label(vol, name, &index); 1082 if (result == B_OK) 1083 vol->vol_entry = index; 1084 } 1085 1086 if (result == B_OK) { 1087 memcpy(vol->vol_label, name, 11); 1088 dosfs_trim_spaces(vol->vol_label); 1089 } 1090 } 1091 1092 if (vol->fs_flags & FS_FLAGS_OP_SYNC) 1093 _dosfs_sync(vol); 1094 1095 return result; 1096} 1097 1098 1099#if 0 1100static status_t 1101dosfs_ioctl(fs_volume *_vol, fs_vnode *_node, void *cookie, uint32 code, 1102 void *buf, size_t len) 1103{ 1104 status_t result = B_OK; 1105 nspace *vol = (nspace *)_vol->private_volume; 1106 vnode *node = (vnode *)_node->private_node; 1107 1108 TOUCH(cookie); TOUCH(len); 1109 1110 LOCK_VOL(vol); 1111 1112 switch (code) { 1113 case 100000 : 1114 dprintf("built at %s on %s\n", build_time, build_date); 1115 dprintf("vol info: %s (device %x, media descriptor %x)\n", vol->device, vol->fd, vol->media_descriptor); 1116 dprintf("%lx bytes/sector, %lx sectors/cluster\n", vol->bytes_per_sector, vol->sectors_per_cluster); 1117 dprintf("%lx reserved sectors, %lx total sectors\n", vol->reserved_sectors, vol->total_sectors); 1118 dprintf("%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); 1119 dprintf("root directory starts at sector %lx (cluster %lx), data at sector %lx\n", vol->root_start, vol->root_vnode.cluster, vol->data_start); 1120 dprintf("%lx total clusters, %lx free\n", vol->total_clusters, vol->free_clusters); 1121 dprintf("fat mirroring is %s, fs info sector at sector %x\n", (vol->fat_mirrored) ? "on" : "off", vol->fsinfo_sector); 1122 dprintf("last allocated cluster = %lx\n", vol->last_allocated); 1123 dprintf("root vnode id = %Lx\n", vol->root_vnode.vnid); 1124 dprintf("volume label [%s]\n", vol->vol_label); 1125 break; 1126 1127 case 100001 : 1128 dprintf("vnode id %Lx, dir vnid = %Lx\n", node->vnid, node->dir_vnid); 1129 dprintf("si = %lx, ei = %lx\n", node->sindex, node->eindex); 1130 dprintf("cluster = %lx (%lx), mode = %lx, size = %Lx\n", node->cluster, vol->data_start + vol->sectors_per_cluster * (node->cluster - 2), node->mode, node->st_size); 1131 dprintf("mime = %s\n", node->mime ? node->mime : "(null)"); 1132 dump_fat_chain(vol, node->cluster); 1133 break; 1134 1135 case 100002 : { 1136 struct diri diri; 1137 uint8 *buffer; 1138 uint32 i; 1139 for (i=0,buffer=diri_init(vol,node->cluster, 0, &diri);buffer;buffer=diri_next_entry(&diri),i++) { 1140 if (buffer[0] == 0) break; 1141 dprintf("entry %lx:\n", i); 1142 dump_directory(buffer); 1143 } 1144 break; 1145 } 1146 1147 case 100003 : 1148 dprintf("vcache validation not yet implemented\n"); 1149 dprintf("validating vcache for %lx\n", vol->id); 1150 validate_vcache(vol); 1151 dprintf("validation complete for %lx\n", vol->id); 1152 break; 1153 1154 case 100004 : 1155 dprintf("dumping vcache for %lx\n", vol->id); 1156 dump_vcache(vol); 1157 break; 1158 1159 case 100005 : 1160 dprintf("dumping dlist for %lx\n", vol->id); 1161 dlist_dump(vol); 1162 break; 1163 1164 default : 1165 DPRINTF(0, ("dosfs_ioctl: vol %" B_PRIdDEV ", vnode %" B_PRIdINO 1166 " code = %" B_PRIu32 "\n", vol->id, node->vnid, code)); 1167 result = B_DEV_INVALID_IOCTL; 1168 break; 1169 } 1170 1171 UNLOCK_VOL(vol); 1172 1173 return result; 1174} 1175#endif 1176 1177 1178status_t 1179_dosfs_sync(nspace *vol) 1180{ 1181 update_fsinfo(vol); 1182 block_cache_sync(vol->fBlockCache); 1183 1184 return B_OK; 1185} 1186 1187 1188static status_t 1189dosfs_sync(fs_volume *_vol) 1190{ 1191 nspace *vol = (nspace *)_vol->private_volume; 1192 1193 DPRINTF(0, ("dosfs_sync called on volume %" B_PRIdDEV "\n", vol->id)); 1194 1195 RecursiveLocker lock(vol->vlock); 1196 return _dosfs_sync(vol); 1197} 1198 1199 1200static status_t 1201dosfs_fsync(fs_volume *_vol, fs_vnode *_node) 1202{ 1203 nspace *vol = (nspace *)_vol->private_volume; 1204 vnode *node = (vnode *)_node->private_node; 1205 status_t err = B_OK; 1206 1207 RecursiveLocker lock(vol->vlock); 1208 1209 if (node->cache) 1210 err = file_cache_sync(node->cache); 1211 1212 return err; 1213} 1214 1215 1216// #pragma mark - 1217 1218 1219static uint32 1220dosfs_get_supported_operations(partition_data* partition, uint32 mask) 1221{ 1222 dprintf("dosfs_get_supported_operations\n"); 1223 // TODO: We should at least check the partition size. 1224 return B_DISK_SYSTEM_SUPPORTS_INITIALIZING 1225 | B_DISK_SYSTEM_SUPPORTS_CONTENT_NAME 1226 | B_DISK_SYSTEM_SUPPORTS_WRITING; 1227} 1228 1229 1230// #pragma mark - 1231 1232 1233static status_t 1234dos_std_ops(int32 op, ...) 1235{ 1236 dprintf("dos_std_ops()\n"); 1237 switch (op) { 1238 case B_MODULE_INIT: 1239 return B_OK; 1240 case B_MODULE_UNINIT: 1241 return B_OK; 1242 1243 default: 1244 return B_ERROR; 1245 } 1246} 1247 1248 1249fs_volume_ops gFATVolumeOps = { 1250 &dosfs_unmount, 1251 &dosfs_read_fs_stat, 1252 &dosfs_write_fs_stat, 1253 &dosfs_sync, 1254 &dosfs_read_vnode, 1255 1256 /* index directory & index operations */ 1257 NULL, //&fs_open_index_dir, 1258 NULL, //&fs_close_index_dir, 1259 NULL, //&fs_free_index_dir_cookie, 1260 NULL, //&fs_read_index_dir, 1261 NULL, //&fs_rewind_index_dir, 1262 1263 NULL, //&fs_create_index, 1264 NULL, //&fs_remove_index, 1265 NULL, //&fs_stat_index, 1266 1267 /* query operations */ 1268 NULL, //&fs_open_query, 1269 NULL, //&fs_close_query, 1270 NULL, //&fs_free_query_cookie, 1271 NULL, //&fs_read_query, 1272 NULL, //&fs_rewind_query, 1273}; 1274 1275 1276fs_vnode_ops gFATVnodeOps = { 1277 /* vnode operations */ 1278 &dosfs_walk, 1279 &dosfs_get_vnode_name, 1280 &dosfs_release_vnode, 1281 &dosfs_remove_vnode, 1282 1283 /* VM file access */ 1284 &dosfs_can_page, 1285 &dosfs_read_pages, 1286 &dosfs_write_pages, 1287 1288 NULL, // io() 1289 NULL, // cancel_io() 1290 1291 &dosfs_get_file_map, 1292 1293 NULL, // fs_ioctl() 1294 NULL, // fs_set_flags, 1295 NULL, // fs_select 1296 NULL, // fs_deselect 1297 &dosfs_fsync, 1298 1299 NULL, 1300 NULL, // fs_create_symlink, 1301 1302 NULL, // fs_link, 1303 &dosfs_unlink, 1304 &dosfs_rename, 1305 1306 &dosfs_access, 1307 &dosfs_rstat, 1308 &dosfs_wstat, 1309 NULL, // fs_preallocate, 1310 1311 /* file operations */ 1312 &dosfs_create, 1313 &dosfs_open, 1314 &dosfs_close, 1315 &dosfs_free_cookie, 1316 &dosfs_read, 1317 &dosfs_write, 1318 1319 /* directory operations */ 1320 &dosfs_mkdir, 1321 &dosfs_rmdir, 1322 &dosfs_opendir, 1323 &dosfs_closedir, 1324 &dosfs_free_dircookie, 1325 &dosfs_readdir, 1326 &dosfs_rewinddir, 1327 1328 /* attribute directory operations */ 1329 &dosfs_open_attrdir, 1330 &dosfs_close_attrdir, 1331 &dosfs_free_attrdir_cookie, 1332 &dosfs_read_attrdir, 1333 &dosfs_rewind_attrdir, 1334 1335 /* attribute operations */ 1336 NULL, // fs_create_attr, 1337 &dosfs_open_attr, 1338 &dosfs_close_attr, 1339 &dosfs_free_attr_cookie, 1340 &dosfs_read_attr, 1341 &dosfs_write_attr, 1342 1343 &dosfs_read_attr_stat, 1344 NULL, // fs_write_attr_stat, 1345 NULL, // fs_rename_attr, 1346 NULL, // fs_remove_attr, 1347}; 1348 1349 1350static file_system_module_info sFATFileSystem = { 1351 { 1352 "file_systems/fat" B_CURRENT_FS_API_VERSION, 1353 0, 1354 dos_std_ops, 1355 }, 1356 1357 "fat", // short_name 1358 "FAT32 File System", // pretty_name 1359 1360 // DDM flags 1361 0 1362// | B_DISK_SYSTEM_SUPPORTS_CHECKING 1363// | B_DISK_SYSTEM_SUPPORTS_REPAIRING 1364// | B_DISK_SYSTEM_SUPPORTS_RESIZING 1365// | B_DISK_SYSTEM_SUPPORTS_MOVING 1366// | B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_NAME 1367// | B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_PARAMETERS 1368 | B_DISK_SYSTEM_SUPPORTS_INITIALIZING 1369 | B_DISK_SYSTEM_SUPPORTS_CONTENT_NAME 1370// | B_DISK_SYSTEM_SUPPORTS_DEFRAGMENTING 1371// | B_DISK_SYSTEM_SUPPORTS_DEFRAGMENTING_WHILE_MOUNTED 1372// | B_DISK_SYSTEM_SUPPORTS_CHECKING_WHILE_MOUNTED 1373// | B_DISK_SYSTEM_SUPPORTS_REPAIRING_WHILE_MOUNTED 1374// | B_DISK_SYSTEM_SUPPORTS_RESIZING_WHILE_MOUNTED 1375// | B_DISK_SYSTEM_SUPPORTS_MOVING_WHILE_MOUNTED 1376// | B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_NAME_WHILE_MOUNTED 1377// | B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_PARAMETERS_WHILE_MOUNTED 1378 | B_DISK_SYSTEM_SUPPORTS_WRITING 1379 , 1380 1381 // scanning 1382 dosfs_identify_partition, 1383 dosfs_scan_partition, 1384 dosfs_free_identify_partition_cookie, 1385 NULL, // free_partition_content_cookie() 1386 1387 &dosfs_mount, 1388 1389 /* capability querying operations */ 1390 &dosfs_get_supported_operations, 1391 1392 NULL, // validate_resize 1393 NULL, // validate_move 1394 NULL, // validate_set_content_name 1395 NULL, // validate_set_content_parameters 1396 NULL, // validate_initialize, 1397 1398 /* shadow partition modification */ 1399 NULL, // shadow_changed 1400 1401 /* writing */ 1402 NULL, // defragment 1403 NULL, // repair 1404 NULL, // resize 1405 NULL, // move 1406 NULL, // set_content_name 1407 NULL, // set_content_parameters 1408 dosfs_initialize, 1409 dosfs_uninitialize 1410}; 1411 1412module_info *modules[] = { 1413 (module_info *)&sFATFileSystem, 1414 NULL, 1415}; 1416