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#include <stdio.h> 6#include <stdlib.h> 7#include <string.h> 8#include <sys/stat.h> 9#include <time.h> 10 11#include <KernelExport.h> 12#include <Drivers.h> 13#include <driver_settings.h> 14 15#include <scsi.h> 16 17#include <fsproto.h> 18#ifndef COMPILE_IN_BEOS 19#include <fs_volume.h> 20#endif 21#include <lock.h> 22#include <cache.h> 23 24#include "dosfs.h" 25#include "attr.h" 26#include "dir.h" 27#include "dlist.h" 28#include "fat.h" 29#include "file.h" 30#include "iter.h" 31#include "util.h" 32#include "vcache.h" 33 34extern const char *build_time, *build_date; 35 36/* debug levels */ 37int debug_attr = 0, debug_dir = 0, debug_dlist = 0, debug_dosfs = 0, 38 debug_encodings = 0, debug_fat = 0, debug_file = 0, 39 debug_iter = 0, debug_vcache = 0; 40 41#define DPRINTF(a,b) if (debug_dosfs > (a)) dprintf b 42 43CHECK_MAGIC(vnode,struct vnode,VNODE_MAGIC) 44CHECK_MAGIC(nspace,struct _nspace, NSPACE_MAGIC) 45 46static status_t get_fsinfo(nspace *vol, uint32 *free_count, uint32 *last_allocated); 47 48#if DEBUG 49 50int32 instances = 0; 51 52int debug_dos(int argc, char **argv) 53{ 54 int i; 55 for (i=1;i<argc;i++) { 56 nspace *vol = (nspace *)strtoul(argv[i], NULL, 0); 57 if (vol == NULL) 58 continue; 59 60 kprintf("dos nspace @ %p\n", vol); 61 kprintf("magic: %lx\n", vol->magic); 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 return B_OK; 87} 88 89int debug_dvnode(int argc, char **argv) 90{ 91 int i; 92 93 if (argc < 2) { 94 kprintf("dvnode vnode\n"); 95 return B_OK; 96 } 97 98 for (i=1;i<argc;i++) { 99 vnode *n = (vnode *)strtoul(argv[i], NULL, 0); 100 if (!n) continue; 101 102 kprintf("vnode @ %p", n); 103#if TRACK_FILENAME 104 kprintf(" (%s)", n->filename); 105#endif 106 kprintf("\nmagic %lx, vnid %Lx, dir vnid %Lx\n", 107 n->magic, n->vnid, n->dir_vnid); 108 kprintf("iteration %lx, si=%lx, ei=%lx, cluster=%lx\n", 109 n->iteration, n->sindex, n->eindex, n->cluster); 110 kprintf("mode %lx, size %Lx, time %lx\n", 111 n->mode, n->st_size, n->st_time); 112 kprintf("end cluster = %lx\n", n->end_cluster); 113 if (n->mime) kprintf("mime type %s\n", n->mime); 114 } 115 116 return B_OK; 117} 118 119int debug_dc2s(int argc, char **argv) 120{ 121 int i; 122 nspace *vol; 123 124 if (argc < 3) { 125 kprintf("dc2s nspace cluster\n"); 126 return B_OK; 127 } 128 129 vol = (nspace *)strtoul(argv[1], NULL, 0); 130 if (vol == NULL) 131 return B_OK; 132 133 for (i=2;i<argc;i++) { 134 uint32 cluster = strtoul(argv[i], NULL, 0); 135 kprintf("cluster %lx = block %Lx\n", cluster, vol->data_start + 136 (off_t)(cluster - 2) * vol->sectors_per_cluster); 137 } 138 139 return B_OK; 140} 141 142#endif 143 144static int lock_removable_device(int fd, bool state) 145{ 146 return ioctl(fd, B_SCSI_PREVENT_ALLOW, &state, sizeof(state)); 147} 148 149static status_t mount_fat_disk(const char *path, nspace_id nsid, 150 const int flags, nspace** newVol, int fs_flags, int op_sync_mode) 151{ 152 nspace *vol = NULL; 153 uint8 buf[512]; 154 int i; 155 device_geometry geo; 156 status_t err; 157 158 *newVol = NULL; 159 if ((vol = (nspace*)calloc(sizeof(nspace), 1)) == NULL) { 160 dprintf("dosfs error: out of memory\n"); 161 return ENOMEM; 162 } 163 164 vol->magic = NSPACE_MAGIC; 165 vol->flags = B_FS_IS_PERSISTENT | B_FS_HAS_MIME; 166 vol->fs_flags = fs_flags; 167 168 // open read-only for now 169 if ((err = (vol->fd = open(path, O_RDONLY))) < 0) { 170 dprintf("dosfs: unable to open %s (%s)\n", path, strerror(err)); 171 goto error0; 172 } 173 174 // get device characteristics 175 if (ioctl(vol->fd, B_GET_GEOMETRY, &geo) < 0) { 176 struct stat st; 177 if ((fstat(vol->fd, &st) >= 0) && 178 S_ISREG(st.st_mode)) { 179 /* support mounting disk images */ 180 geo.bytes_per_sector = 0x200; 181 geo.sectors_per_track = 1; 182 geo.cylinder_count = st.st_size / 0x200; 183 geo.head_count = 1; 184 geo.read_only = !(st.st_mode & S_IWUSR); 185 geo.removable = true; 186 } else { 187 dprintf("dosfs: error getting device geometry\n"); 188 goto error0; 189 } 190 } 191 if ((geo.bytes_per_sector != 0x200) && (geo.bytes_per_sector != 0x400) && (geo.bytes_per_sector != 0x800)) { 192 dprintf("dosfs: unsupported device block size (%lu)\n", geo.bytes_per_sector); 193 goto error0; 194 } 195 if (geo.removable) { 196 DPRINTF(0, ("%s is removable\n", path)); 197 vol->flags |= B_FS_IS_REMOVABLE; 198 } 199 if (geo.read_only || (flags & B_MOUNT_READ_ONLY)) { 200 DPRINTF(0, ("%s is read-only\n", path)); 201 vol->flags |= B_FS_IS_READONLY; 202 } else { 203 // reopen it with read/write permissions 204 close(vol->fd); 205 if ((err = (vol->fd = open(path, O_RDWR))) < 0) { 206 dprintf("dosfs: unable to open %s (%s)\n", path, strerror(err)); 207 goto error0; 208 } 209 if ((vol->flags & B_FS_IS_REMOVABLE) && (vol->fs_flags & FS_FLAGS_LOCK_DOOR)) 210 lock_removable_device(vol->fd, true); 211 } 212 213 // see if we need to go into op sync mode 214 vol->fs_flags &= ~FS_FLAGS_OP_SYNC; 215 switch(op_sync_mode) { 216 case 1: 217 if((vol->flags & B_FS_IS_REMOVABLE) == 0) { 218 // we're not removable, so skip op_sync 219 break; 220 } 221 case 2: 222 dprintf("dosfs: mounted with op_sync enabled\n"); 223 vol->fs_flags |= FS_FLAGS_OP_SYNC; 224 break; 225 case 0: 226 default: 227 ; 228 } 229 230 // read in the boot sector 231 if ((err = read_pos(vol->fd, 0, (void*)buf, 512)) != 512) { 232 dprintf("dosfs: error reading boot sector\n"); 233 goto error; 234 } 235 236 // only check boot signature on hard disks to account for broken mtools 237 // behavior 238 if (((buf[0x1fe] != 0x55) || (buf[0x1ff] != 0xaa)) && (buf[0x15] == 0xf8)) 239 goto error; 240 241 if (!memcmp(buf+3, "NTFS ", 8) || !memcmp(buf+3, "HPFS ", 8)) { 242 dprintf("%4.4s, not FAT\n", buf+3); 243 goto error; 244 } 245 246 // first fill in the universal fields from the bpb 247 vol->bytes_per_sector = read16(buf,0xb); 248 if ((vol->bytes_per_sector != 0x200) && (vol->bytes_per_sector != 0x400) && (vol->bytes_per_sector != 0x800)) { 249 dprintf("dosfs error: unsupported bytes per sector (%lu)\n", 250 vol->bytes_per_sector); 251 goto error; 252 } 253 254 vol->sectors_per_cluster = i = buf[0xd]; 255 if ((i != 1) && (i != 2) && (i != 4) && (i != 8) && 256 (i != 0x10) && (i != 0x20) && (i != 0x40) && (i != 0x80)) { 257 dprintf("dosfs: sectors/cluster = %d\n", i); 258 goto error; 259 } 260 261 vol->reserved_sectors = read16(buf,0xe); 262 263 vol->fat_count = buf[0x10]; 264 if ((vol->fat_count == 0) || (vol->fat_count > 8)) { 265 dprintf("dosfs: unreasonable fat count (%lu)\n", vol->fat_count); 266 goto error; 267 } 268 269 vol->media_descriptor = buf[0x15]; 270 // check media descriptor versus known types 271 if ((buf[0x15] != 0xF0) && (buf[0x15] < 0xf8)) { 272 dprintf("dosfs error: invalid media descriptor byte\n"); 273 goto error; 274 } 275 276 vol->vol_entry = -2; // for now, assume there is no volume entry 277 memset(vol->vol_label, ' ', 11); 278 279 // now become more discerning citizens 280 vol->sectors_per_fat = read16(buf,0x16); 281 if (vol->sectors_per_fat == 0) { 282 // fat32 land 283 vol->fat_bits = 32; 284 vol->sectors_per_fat = read32(buf,0x24); 285 vol->total_sectors = read32(buf,0x20); 286 287 vol->fsinfo_sector = read16(buf, 0x30); 288 if ((vol->fsinfo_sector != 0xffff) && (vol->fsinfo_sector >= vol->reserved_sectors)) { 289 dprintf("dosfs: fsinfo sector too large (%x)\n", vol->fsinfo_sector); 290 goto error; 291 } 292 293 vol->fat_mirrored = !(buf[0x28] & 0x80); 294 vol->active_fat = (vol->fat_mirrored) ? (buf[0x28] & 0xf) : 0; 295 296 vol->data_start = vol->reserved_sectors + vol->fat_count*vol->sectors_per_fat; 297 vol->total_clusters = (vol->total_sectors - vol->data_start) / vol->sectors_per_cluster; 298 299 vol->root_vnode.cluster = read32(buf,0x2c); 300 if (vol->root_vnode.cluster >= vol->total_clusters) { 301 dprintf("dosfs: root vnode cluster too large (%lx)\n", vol->root_vnode.cluster); 302 goto error; 303 } 304 } else { 305 // fat12 & fat16 306 if (vol->fat_count != 2) { 307 dprintf("dosfs error: claims %ld fat tables\n", vol->fat_count); 308 goto error; 309 } 310 311 vol->root_entries_count = read16(buf,0x11); 312 if (vol->root_entries_count % (vol->bytes_per_sector / 0x20)) { 313 dprintf("dosfs error: invalid number of root entries\n"); 314 goto error; 315 } 316 317 vol->fsinfo_sector = 0xffff; 318 vol->total_sectors = read16(buf,0x13); // partition size 319 if (vol->total_sectors == 0) 320 vol->total_sectors = read32(buf,0x20); 321 322 { 323 /* 324 Zip disks that were formatted at iomega have an incorrect number 325 of sectors. They say that they have 196576 sectors but they 326 really only have 196192. This check is a work-around for their 327 brain-deadness. 328 */ 329 unsigned char bogus_zip_data[] = { 330 0x00, 0x02, 0x04, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 331 0xf8, 0xc0, 0x00, 0x20, 0x00, 0x40, 0x00, 0x20, 0x00, 0x00 332 }; 333 334 if (memcmp(buf+0x0b, bogus_zip_data, sizeof(bogus_zip_data)) == 0 && 335 vol->total_sectors == 196576 && 336 ((off_t)geo.sectors_per_track * 337 (off_t)geo.cylinder_count * 338 (off_t)geo.head_count) == 196192) { 339 340 vol->total_sectors = 196192; 341 } 342 } 343 344 345 if (buf[0x26] == 0x29) { 346 // fill in the volume label 347 if (memcmp(buf+0x2b, " ", 11)) { 348 memcpy(vol->vol_label, buf+0x2b, 11); 349 vol->vol_entry = -1; 350 } 351 } 352 353 vol->fat_mirrored = true; 354 vol->active_fat = 0; 355 356 vol->root_start = vol->reserved_sectors + vol->fat_count * vol->sectors_per_fat; 357 vol->root_sectors = vol->root_entries_count * 0x20 / vol->bytes_per_sector; 358 vol->root_vnode.cluster = 1; 359 vol->root_vnode.end_cluster = 1; 360 vol->root_vnode.st_size = vol->root_sectors * vol->bytes_per_sector; 361 362 vol->data_start = vol->root_start + vol->root_sectors; 363 vol->total_clusters = (vol->total_sectors - vol->data_start) / vol->sectors_per_cluster; 364 365 // XXX: uncertain about border cases; win32 sdk says cutoffs are at 366 // at ff6/ff7 (or fff6/fff7), but that doesn't make much sense 367 if (vol->total_clusters > 0xff1) 368 vol->fat_bits = 16; 369 else 370 vol->fat_bits = 12; 371 } 372 373 /* check that the partition is large enough to contain the file system */ 374 if (vol->total_sectors > geo.sectors_per_track * geo.cylinder_count * 375 geo.head_count) { 376 dprintf("dosfs: volume extends past end of partition\n"); 377 err = B_PARTITION_TOO_SMALL; 378 goto error; 379 } 380 381 // perform sanity checks on the FAT 382 383 // the media descriptor in active FAT should match the one in the BPB 384 if ((err = read_pos(vol->fd, vol->bytes_per_sector*(vol->reserved_sectors + vol->active_fat * vol->sectors_per_fat), (void *)buf, 0x200)) != 0x200) { 385 dprintf("dosfs: error reading FAT\n"); 386 goto error; 387 } 388 389 if (buf[0] != vol->media_descriptor) { 390 dprintf("dosfs error: media descriptor mismatch (%x != %x)\n", buf[0], vol->media_descriptor); 391 goto error; 392 } 393 394 if (vol->fat_mirrored) { 395 uint32 i; 396 uint8 buf2[512]; 397 for (i=0;i<vol->fat_count;i++) { 398 if (i != vol->active_fat) { 399 DPRINTF(1, ("checking fat #%ld\n", i)); 400 buf2[0] = ~buf[0]; 401 if ((err = read_pos(vol->fd, vol->bytes_per_sector*(vol->reserved_sectors + vol->sectors_per_fat*i), (void *)buf2, 0x200)) != 0x200) { 402 dprintf("dosfs: error reading FAT %ld\n", i); 403 goto error; 404 } 405 406 if (buf2[0] != vol->media_descriptor) { 407 dprintf("dosfs error: media descriptor mismatch in fat # %ld (%x != %x)\n", i, buf2[0], vol->media_descriptor); 408 goto error; 409 } 410#if 0 411 // checking for exact matches of fats is too 412 // restrictive; allow these to go through in 413 // case the fat is corrupted for some reason 414 if (memcmp(buf, buf2, 0x200)) { 415 dprintf("dosfs error: fat %d doesn't match active fat (%d)\n", i, vol->active_fat); 416 goto error; 417 } 418#endif 419 } 420 } 421 } 422 423 // now we are convinced of the drive's validity 424 425 vol->id = nsid; 426 strncpy(vol->device,path,256); 427 428 // this will be updated later if fsinfo exists 429 vol->last_allocated = 2; 430 431 vol->beos_vnid = INVALID_VNID_BITS_MASK; 432 { 433 void *handle; 434 handle = load_driver_settings("dos"); 435 vol->respect_disk_image = 436 get_driver_boolean_parameter(handle, "respect", true, true); 437 unload_driver_settings(handle); 438 } 439 440 // initialize block cache 441 if (init_cache_for_device(vol->fd, (off_t)vol->total_sectors) < 0) { 442 dprintf("error initializing block cache\n"); 443 goto error; 444 } 445 446 // as well as the vnode cache 447 if (init_vcache(vol) != B_OK) { 448 dprintf("error initializing vnode cache\n"); 449 goto error1; 450 } 451 452 // and the dlist cache 453 if (dlist_init(vol) != B_OK) { 454 dprintf("error initializing dlist cache\n"); 455 goto error2; 456 } 457 458 if (vol->flags & B_FS_IS_READONLY) 459 vol->free_clusters = 0; 460 else { 461 uint32 free_count, last_allocated; 462 err = get_fsinfo(vol, &free_count, &last_allocated); 463 if (err >= 0) { 464 if (free_count < vol->total_clusters) 465 vol->free_clusters = free_count; 466 else { 467 dprintf("free cluster count from fsinfo block invalid %lx\n", free_count); 468 err = -1; 469 } 470 if (last_allocated < vol->total_clusters) 471 vol->last_allocated = last_allocated; //update to a closer match 472 } 473 if (err < 0) { 474 if ((err = count_free_clusters(vol)) < 0) { 475 dprintf("error counting free clusters (%s)\n", strerror(err)); 476 goto error3; 477 } 478 vol->free_clusters = err; 479 } 480 } 481 482 DPRINTF(0, ("built at %s on %s\n", build_time, build_date)); 483 DPRINTF(0, ("mounting %s (id %lx, device %x, media descriptor %x)\n", vol->device, vol->id, vol->fd, vol->media_descriptor)); 484 DPRINTF(0, ("%lx bytes/sector, %lx sectors/cluster\n", vol->bytes_per_sector, vol->sectors_per_cluster)); 485 DPRINTF(0, ("%lx reserved sectors, %lx total sectors\n", vol->reserved_sectors, vol->total_sectors)); 486 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)); 487 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)); 488 DPRINTF(0, ("%lx total clusters, %lx free\n", vol->total_clusters, vol->free_clusters)); 489 DPRINTF(0, ("fat mirroring is %s, fs info sector at sector %x\n", (vol->fat_mirrored) ? "on" : "off", vol->fsinfo_sector)); 490 DPRINTF(0, ("last allocated cluster = %lx\n", vol->last_allocated)); 491 492 if (vol->fat_bits == 32) { 493 // now that the block cache has been initialised, we can figure 494 // out the length of the root directory with count_clusters() 495 vol->root_vnode.st_size = count_clusters(vol, vol->root_vnode.cluster) * vol->bytes_per_sector * vol->sectors_per_cluster; 496 vol->root_vnode.end_cluster = get_nth_fat_entry(vol, vol->root_vnode.cluster, vol->root_vnode.st_size / vol->bytes_per_sector / vol->sectors_per_cluster - 1); 497 } 498 499 // initialize root vnode 500 vol->root_vnode.magic = VNODE_MAGIC; 501 vol->root_vnode.vnid = vol->root_vnode.dir_vnid = GENERATE_DIR_CLUSTER_VNID(vol->root_vnode.cluster,vol->root_vnode.cluster); 502 vol->root_vnode.sindex = vol->root_vnode.eindex = 0xffffffff; 503 vol->root_vnode.mode = FAT_SUBDIR; 504 time(&(vol->root_vnode.st_time)); 505 vol->root_vnode.mime = NULL; 506 vol->root_vnode.dirty = false; 507 dlist_add(vol, vol->root_vnode.vnid); 508 509 // find volume label (supercedes any label in the bpb) 510 { 511 struct diri diri; 512 uint8 *buffer; 513 buffer = diri_init(vol, vol->root_vnode.cluster, 0, &diri); 514 for (;buffer;buffer=diri_next_entry(&diri)) { 515 if ((buffer[0x0b] & FAT_VOLUME) && (buffer[0x0b] != 0xf) && (buffer[0] != 0xe5)) { 516 vol->vol_entry = diri.current_index; 517 memcpy(vol->vol_label, buffer, 11); 518 break; 519 } 520 } 521 diri_free(&diri); 522 } 523 524 DPRINTF(0, ("root vnode id = %Lx\n", vol->root_vnode.vnid)); 525 DPRINTF(0, ("volume label [%11.11s] (%lx)\n", vol->vol_label, vol->vol_entry)); 526 527 // steal a trick from bfs 528 if (!memcmp(vol->vol_label, "__RO__ ", 11)) { 529 vol->flags |= B_FS_IS_READONLY; 530 } 531 532 *newVol = vol; 533 return B_NO_ERROR; 534 535error3: 536 dlist_uninit(vol); 537error2: 538 uninit_vcache(vol); 539error1: 540 remove_cached_device_blocks(vol->fd, NO_WRITES); 541error: 542 if (!(vol->flags & B_FS_IS_READONLY) && (vol->flags & B_FS_IS_REMOVABLE) && (vol->fs_flags & FS_FLAGS_LOCK_DOOR)) 543 lock_removable_device(vol->fd, false); 544error0: 545 close(vol->fd); 546 free(vol); 547 return (err >= B_NO_ERROR) ? EINVAL : err; 548} 549 550static int dosfs_mount(nspace_id nsid, const char *device, ulong flags, void *parms, 551 size_t len, void **data, vnode_id *vnid) 552{ 553 int result; 554 nspace *vol; 555 void *handle; 556 int op_sync_mode; 557 int fs_flags = 0; 558 559 handle = load_driver_settings("dos"); 560 debug_attr = strtoul(get_driver_parameter(handle, "debug_attr", "0", "0"), NULL, 0); 561 debug_dir = strtoul(get_driver_parameter(handle, "debug_dir", "0", "0"), NULL, 0); 562 debug_dlist = strtoul(get_driver_parameter(handle, "debug_dlist", "0", "0"), NULL, 0); 563 debug_dosfs = strtoul(get_driver_parameter(handle, "debug_dosfs", "0", "0"), NULL, 0); 564 debug_encodings = strtoul(get_driver_parameter(handle, "debug_encodings", "0", "0"), NULL, 0); 565 debug_fat = strtoul(get_driver_parameter(handle, "debug_fat", "0", "0"), NULL, 0); 566 debug_file = strtoul(get_driver_parameter(handle, "debug_file", "0", "0"), NULL, 0); 567 debug_iter = strtoul(get_driver_parameter(handle, "debug_iter", "0", "0"), NULL, 0); 568 debug_vcache = strtoul(get_driver_parameter(handle, "debug_vcache", "0", "0"), NULL, 0); 569 570 op_sync_mode = strtoul(get_driver_parameter(handle, "op_sync_mode", "0", "0"), NULL, 0); 571 if (op_sync_mode < 0 || op_sync_mode > 2) { 572 op_sync_mode = 0; 573 } 574 if (strcasecmp(get_driver_parameter(handle, "lock_device", "true", "true"), "false") == 0) { 575 dprintf("dosfs: mounted with lock_device = false\n"); 576 } else { 577 dprintf("dosfs: mounted with lock_device = true\n"); 578 fs_flags |= FS_FLAGS_LOCK_DOOR; 579 } 580 581 unload_driver_settings(handle); 582 583 /* parms and len are command line options; dosfs doesn't use any so 584 we can ignore these arguments */ 585 TOUCH(parms); TOUCH(len); 586 587#if __RO__ 588 // make it read-only 589 flags |= 1; 590#endif 591 592 if (data == NULL) { 593 dprintf("dosfs_mount passed NULL data pointer\n"); 594 return EINVAL; 595 } 596 597 // Try and mount volume as a FAT volume 598 if ((result = mount_fat_disk(device, nsid, flags, &vol, fs_flags, op_sync_mode)) == B_NO_ERROR) { 599 char name[32]; 600 601 if (check_nspace_magic(vol, "dosfs_mount")) return EINVAL; 602 603 *vnid = vol->root_vnode.vnid; 604 *data = (void*)vol; 605 606 // You MUST do this. Create the vnode for the root. 607 result = new_vnode(nsid, *vnid, (void*)&(vol->root_vnode)); 608 if (result != B_NO_ERROR) { 609 dprintf("error creating new vnode (%s)\n", strerror(result)); 610 goto error; 611 } 612 sprintf(name, "fat lock %lx", vol->id); 613 if ((result = new_lock(&(vol->vlock), name)) != 0) { 614 dprintf("error creating lock (%s)\n", strerror(result)); 615 goto error; 616 } 617 618#if DEBUG 619 load_driver_symbols("dos"); 620 621 if (atomic_add(&instances, 1) == 0) { 622 add_debugger_command("dos", debug_dos, "dump a dos nspace structure"); 623 add_debugger_command("dvnode", debug_dvnode, "dump a dos vnode structure"); 624 add_debugger_command("dfvnid", debug_dfvnid, "find a vnid in the vnid cache"); 625 add_debugger_command("dfloc", debug_dfloc, "find a loc in the vnid cache"); 626 add_debugger_command("dc2s", debug_dc2s, "calculate sector for cluster"); 627 } 628#endif 629 } 630 631 return result; 632 633error: 634 remove_cached_device_blocks(vol->fd, NO_WRITES); 635 dlist_uninit(vol); 636 uninit_vcache(vol); 637 free(vol); 638 return EINVAL; 639} 640 641static void update_fsinfo(nspace *vol) 642{ 643 if ((vol->fat_bits == 32) && (vol->fsinfo_sector != 0xffff) && 644 ((vol->flags & B_FS_IS_READONLY) == false)) { 645 uchar *buffer; 646 if ((buffer = (uchar *)get_block(vol->fd, vol->fsinfo_sector, vol->bytes_per_sector)) != NULL) { 647 if ((read32(buffer,0) == 0x41615252) && (read32(buffer,0x1e4) == 0x61417272) && (read16(buffer,0x1fe) == 0xaa55)) { 648 //number of free clusters 649 buffer[0x1e8] = (vol->free_clusters & 0xff); 650 buffer[0x1e9] = ((vol->free_clusters >> 8) & 0xff); 651 buffer[0x1ea] = ((vol->free_clusters >> 16) & 0xff); 652 buffer[0x1eb] = ((vol->free_clusters >> 24) & 0xff); 653 //cluster number of most recently allocated cluster 654 buffer[0x1ec] = (vol->last_allocated & 0xff); 655 buffer[0x1ed] = ((vol->last_allocated >> 8) & 0xff); 656 buffer[0x1ee] = ((vol->last_allocated >> 16) & 0xff); 657 buffer[0x1ef] = ((vol->last_allocated >> 24) & 0xff); 658 mark_blocks_dirty(vol->fd, vol->fsinfo_sector, 1); 659 } else { 660 dprintf("update_fsinfo: fsinfo block has invalid magic number\n"); 661 } 662 release_block(vol->fd, vol->fsinfo_sector); 663 } else { 664 dprintf("update_fsinfo: error getting fsinfo sector %x\n", vol->fsinfo_sector); 665 } 666 } 667} 668 669static status_t get_fsinfo(nspace *vol, uint32 *free_count, uint32 *last_allocated) 670{ 671 uchar *buffer; 672 int32 result; 673 674 if ((vol->fat_bits != 32) || (vol->fsinfo_sector == 0xffff)) 675 return B_ERROR; 676 677 if ((buffer = (uchar *)get_block(vol->fd, vol->fsinfo_sector, vol->bytes_per_sector)) == NULL) { 678 dprintf("get_fsinfo: error getting fsinfo sector %x\n", vol->fsinfo_sector); 679 return EIO; 680 } 681 682 if ((read32(buffer,0) == 0x41615252) && (read32(buffer,0x1e4) == 0x61417272) && (read16(buffer,0x1fe) == 0xaa55)) { 683 *free_count = read32(buffer,0x1e8); 684 *last_allocated = read32(buffer,0x1ec); 685 result = B_OK; 686 } else { 687 dprintf("get_fsinfo: fsinfo block has invalid magic number\n"); 688 result = B_ERROR; 689 } 690 691 release_block(vol->fd, vol->fsinfo_sector); 692 return result; 693} 694 695static int dosfs_unmount(void *_vol) 696{ 697 int result = B_NO_ERROR; 698 699 nspace* vol = (nspace*)_vol; 700 701 LOCK_VOL(vol); 702 703 if (check_nspace_magic(vol, "dosfs_unmount")) { 704 UNLOCK_VOL(vol); 705 return EINVAL; 706 } 707 708 DPRINTF(0, ("dosfs_unmount volume %lx\n", vol->id)); 709 710 update_fsinfo(vol); 711 flush_device(vol->fd, 0); 712 remove_cached_device_blocks(vol->fd, ALLOW_WRITES); 713 714#if DEBUG 715 if (atomic_add(&instances, -1) == 1) { 716 remove_debugger_command("dos", debug_dos); 717 remove_debugger_command("dvnode", debug_dvnode); 718 remove_debugger_command("dfvnid", debug_dfvnid); 719 remove_debugger_command("dfloc", debug_dfloc); 720 remove_debugger_command("dc2s", debug_dc2s); 721 } 722#endif 723 724 dlist_uninit(vol); 725 uninit_vcache(vol); 726 727 if (!(vol->flags & B_FS_IS_READONLY) && (vol->flags & B_FS_IS_REMOVABLE) && (vol->fs_flags & FS_FLAGS_LOCK_DOOR)) 728 lock_removable_device(vol->fd, false); 729 result = close(vol->fd); 730 free_lock(&(vol->vlock)); 731 vol->magic = ~VNODE_MAGIC; 732 free(vol); 733 734#if USE_DMALLOC 735 check_mem(); 736#endif 737 738 return result; 739} 740 741// dosfs_rfsstat - Fill in fs_info struct for device. 742static int dosfs_rfsstat(void *_vol, struct fs_info * fss) 743{ 744 nspace* vol = (nspace*)_vol; 745 int i; 746 747 LOCK_VOL(vol); 748 749 if (check_nspace_magic(vol, "dosfs_rfsstat")) { 750 UNLOCK_VOL(vol); 751 return EINVAL; 752 } 753 754 DPRINTF(1, ("dosfs_rfsstat called\n")); 755 756 // fss->dev and fss->root filled in by kernel 757 758 // File system flags. 759 fss->flags = vol->flags; 760 761 // FS block size. 762 fss->block_size = vol->bytes_per_sector * vol->sectors_per_cluster; 763 764 // IO size - specifies buffer size for file copying 765 fss->io_size = 65536; 766 767 // Total blocks 768 fss->total_blocks = vol->total_clusters; 769 770 // Free blocks 771 fss->free_blocks = vol->free_clusters; 772 773 // Device name. 774 strncpy(fss->device_name, vol->device, sizeof(fss->device_name)); 775 776 if (vol->vol_entry > -2) 777 strncpy(fss->volume_name, vol->vol_label, sizeof(fss->volume_name)); 778 else 779 strcpy(fss->volume_name, "no name "); 780 781 // XXX: should sanitize name as well 782 for (i=10;i>0;i--) 783 if (fss->volume_name[i] != ' ') 784 break; 785 fss->volume_name[i+1] = 0; 786 for (;i>=0;i--) { 787 if ((fss->volume_name[i] >= 'A') && (fss->volume_name[i] <= 'Z')) 788 fss->volume_name[i] += 'a' - 'A'; 789 } 790 791 // File system name 792 strcpy(fss->fsh_name, "fat"); 793 794 UNLOCK_VOL(vol); 795 796 return 0; 797} 798 799static int dosfs_wfsstat(void *_vol, struct fs_info * fss, long mask) 800{ 801 int result = B_ERROR; 802 nspace* vol = (nspace*)_vol; 803 804 LOCK_VOL(vol); 805 806 if (check_nspace_magic(vol, "dosfs_wfsstat")) { 807 UNLOCK_VOL(vol); 808 return EINVAL; 809 } 810 811 DPRINTF(0, ("dosfs_wfsstat called\n")); 812 813 /* if it's a r/o file system and not the special hack, then don't allow 814 * volume renaming */ 815 if ((vol->flags & B_FS_IS_READONLY) && memcmp(vol->vol_label, "__RO__ ", 11)) { 816 UNLOCK_VOL(vol); 817 return EROFS; 818 } 819 820 if (mask & WFSSTAT_NAME) { 821 // sanitize name 822 char name[11]; 823 int i,j; 824 memset(name, ' ', 11); 825 DPRINTF(1, ("wfsstat: setting name to %s\n", fss->volume_name)); 826 for (i=j=0;(i<11)&&(fss->volume_name[j]);j++) { 827 static char acceptable[] = "!#$%&'()-0123456789@ABCDEFGHIJKLMNOPQRSTUVWXYZ^_`{}~"; 828 char c = fss->volume_name[j]; 829 if ((c >= 'a') && (c <= 'z')) c += 'A' - 'a'; 830 // spaces acceptable in volume names 831 if (strchr(acceptable, c) || (c == ' ')) 832 name[i++] = c; 833 } 834 if (i == 0) { // bad name, kiddo 835 result = EINVAL; 836 goto bi; 837 } 838 DPRINTF(1, ("wfsstat: sanitized to [%11.11s]\n", name)); 839 840 if (vol->vol_entry == -1) { 841 // stored in the bpb 842 uchar *buffer; 843 if ((buffer = get_block(vol->fd, 0, vol->bytes_per_sector)) == NULL) { 844 result = EIO; 845 goto bi; 846 } 847 if ((buffer[0x26] != 0x29) || memcmp(buffer + 0x2b, vol->vol_label, 11)) { 848 dprintf("dosfs_wfsstat: label mismatch\n"); 849 result = B_ERROR; 850 } else { 851 memcpy(buffer + 0x2b, name, 11); 852 mark_blocks_dirty(vol->fd, 0, 1); 853 result = 0; 854 } 855 release_block(vol->fd, 0); 856 } else if (vol->vol_entry >= 0) { 857 struct diri diri; 858 uint8 *buffer; 859 buffer = diri_init(vol, vol->root_vnode.cluster, vol->vol_entry, &diri); 860 861 // check if it is the same as the old volume label 862 if ((buffer == NULL) || (memcmp(buffer, vol->vol_label, 11))) { 863 dprintf("dosfs_wfsstat: label mismatch\n"); 864 diri_free(&diri); 865 result = B_ERROR; 866 goto bi; 867 } 868 memcpy(buffer, name, 11); 869 diri_mark_dirty(&diri); 870 diri_free(&diri); 871 result = 0; 872 } else { 873 uint32 index; 874 result = create_volume_label(vol, name, &index); 875 if (result == B_OK) vol->vol_entry = index; 876 } 877 878 if (result == 0) 879 memcpy(vol->vol_label, name, 11); 880 } 881 882 if (vol->fs_flags & FS_FLAGS_OP_SYNC) 883 _dosfs_sync(vol); 884 885bi: UNLOCK_VOL(vol); 886 887 return result; 888} 889 890static int dosfs_ioctl(void *_vol, void *_node, void *cookie, int code, 891 void *buf, size_t len) 892{ 893 status_t result = B_OK; 894 nspace *vol = (nspace *)_vol; 895 vnode *node = (vnode *)_node; 896 897 TOUCH(cookie); TOUCH(buf); TOUCH(len); 898 899 LOCK_VOL(vol); 900 901 if (check_nspace_magic(vol, "dosfs_ioctl") || 902 check_vnode_magic(node, "dosfs_ioctl")) { 903 UNLOCK_VOL(vol); 904 return EINVAL; 905 } 906 907 switch (code) { 908 case 10002 : /* return real creation time */ 909 if (buf) *(bigtime_t *)buf = node->st_time; 910 break; 911 case 10003 : /* return real last modification time */ 912 if (buf) *(bigtime_t *)buf = node->st_time; 913 break; 914 915 case 69666 : 916 result = fragment(vol, buf); 917 break; 918 919 case 100000 : 920 dprintf("built at %s on %s\n", build_time, build_date); 921 dprintf("vol info: %s (device %x, media descriptor %x)\n", vol->device, vol->fd, vol->media_descriptor); 922 dprintf("%lx bytes/sector, %lx sectors/cluster\n", vol->bytes_per_sector, vol->sectors_per_cluster); 923 dprintf("%lx reserved sectors, %lx total sectors\n", vol->reserved_sectors, vol->total_sectors); 924 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); 925 dprintf("root directory starts at sector %lx (cluster %lx), data at sector %lx\n", vol->root_start, vol->root_vnode.cluster, vol->data_start); 926 dprintf("%lx total clusters, %lx free\n", vol->total_clusters, vol->free_clusters); 927 dprintf("fat mirroring is %s, fs info sector at sector %x\n", (vol->fat_mirrored) ? "on" : "off", vol->fsinfo_sector); 928 dprintf("last allocated cluster = %lx\n", vol->last_allocated); 929 dprintf("root vnode id = %Lx\n", vol->root_vnode.vnid); 930 dprintf("volume label [%11.11s]\n", vol->vol_label); 931 break; 932 933 case 100001 : 934 dprintf("vnode id %Lx, dir vnid = %Lx\n", node->vnid, node->dir_vnid); 935 dprintf("si = %lx, ei = %lx\n", node->sindex, node->eindex); 936 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); 937 dprintf("mime = %s\n", node->mime ? node->mime : "(null)"); 938 dump_fat_chain(vol, node->cluster); 939 break; 940 941 case 100002 : 942 {struct diri diri; 943 uint8 *buffer; 944 uint32 i; 945 for (i=0,buffer=diri_init(vol,node->cluster, 0, &diri);buffer;buffer=diri_next_entry(&diri),i++) { 946 if (buffer[0] == 0) break; 947 dprintf("entry %lx:\n", i); 948 dump_directory(buffer); 949 } 950 diri_free(&diri);} 951 break; 952 953 case 100003 : 954 dprintf("vcache validation not yet implemented\n"); 955#if 0 956 dprintf("validating vcache for %lx\n", vol->id); 957 validate_vcache(vol); 958 dprintf("validation complete for %lx\n", vol->id); 959#endif 960 break; 961 962 case 100004 : 963 dprintf("dumping vcache for %lx\n", vol->id); 964 dump_vcache(vol); 965 break; 966 967 case 100005 : 968 dprintf("dumping dlist for %lx\n", vol->id); 969 dlist_dump(vol); 970 break; 971 972 default : 973 dprintf("dosfs_ioctl: vol %lx, vnode %Lx code = %d\n", vol->id, node->vnid, code); 974 result = EINVAL; 975 break; 976 } 977 978 UNLOCK_VOL(vol); 979 980 return result; 981} 982 983int _dosfs_sync(nspace *vol) 984{ 985 if (check_nspace_magic(vol, "dosfs_sync")) 986 return EINVAL; 987 988 update_fsinfo(vol); 989 flush_device(vol->fd, 0); 990 991 return 0; 992} 993 994static int dosfs_sync(void *_vol) 995{ 996 nspace *vol = (nspace *)_vol; 997 int err; 998 999 DPRINTF(0, ("dosfs_sync called on volume %lx\n", vol->id)); 1000 1001 LOCK_VOL(vol); 1002 err = _dosfs_sync(vol); 1003 UNLOCK_VOL(vol); 1004 1005 return err; 1006} 1007 1008static int dosfs_fsync(void *vol, void *node) 1009{ 1010 TOUCH(node); 1011 1012 return dosfs_sync(vol); 1013} 1014 1015vnode_ops fs_entry = { 1016 &dosfs_read_vnode, 1017 &dosfs_write_vnode, 1018 &dosfs_remove_vnode, 1019 NULL, 1020 &dosfs_walk, 1021 &dosfs_access, 1022 &dosfs_create, 1023 &dosfs_mkdir, 1024 NULL, 1025 NULL, 1026 &dosfs_rename, 1027 &dosfs_unlink, 1028 &dosfs_rmdir, 1029 &dosfs_readlink, 1030 &dosfs_opendir, 1031 &dosfs_closedir, 1032 &dosfs_free_dircookie, 1033 &dosfs_rewinddir, 1034 &dosfs_readdir, 1035 &dosfs_open, 1036 &dosfs_close, 1037 &dosfs_free_cookie, 1038 &dosfs_read, 1039 &dosfs_write, 1040 NULL, 1041 NULL, 1042 &dosfs_ioctl, 1043 NULL, 1044 &dosfs_rstat, 1045 &dosfs_wstat, 1046 &dosfs_fsync, 1047 NULL, 1048 &dosfs_mount, 1049 &dosfs_unmount, 1050 &dosfs_sync, 1051 &dosfs_rfsstat, 1052 &dosfs_wfsstat, 1053 NULL, 1054 NULL, 1055 NULL, 1056 NULL, 1057 NULL, 1058 NULL, 1059 NULL, 1060 NULL, 1061 NULL, 1062 NULL, 1063 NULL, 1064 &dosfs_open_attrdir, 1065 &dosfs_close_attrdir, 1066 &dosfs_free_attrcookie, 1067 &dosfs_rewind_attrdir, 1068 &dosfs_read_attrdir, 1069 &dosfs_write_attr, 1070 &dosfs_read_attr, 1071 NULL, 1072 NULL, 1073 &dosfs_stat_attr, 1074 NULL, 1075 NULL, 1076 NULL, 1077 NULL 1078}; 1079 1080int32 api_version = B_CUR_FS_API_VERSION; 1081