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