1 /* 2 * Copyright 2002-2005, Axel Dörfler, axeld@pinc-software.de. 3 * Distributed under the terms of the MIT License. 4 * 5 * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. 6 * Distributed under the terms of the NewOS License. 7 */ 8 9 /* Virtual File System and File System Interface Layer */ 10 11 #include <OS.h> 12 #include <StorageDefs.h> 13 #include <fs_info.h> 14 #include <fs_interface.h> 15 #include <fs_volume.h> 16 17 #include <disk_device_manager/KDiskDevice.h> 18 #include <disk_device_manager/KDiskDeviceManager.h> 19 #include <disk_device_manager/KDiskDeviceUtils.h> 20 #include <disk_device_manager/KPartitionVisitor.h> 21 #include <disk_device_manager/KDiskSystem.h> 22 #include <KPath.h> 23 #include <syscalls.h> 24 #include <boot/kernel_args.h> 25 #include <vfs.h> 26 #include <vm.h> 27 #include <vm_cache.h> 28 #include <file_cache.h> 29 #include <block_cache.h> 30 #include <khash.h> 31 #include <lock.h> 32 #include <fd.h> 33 #include <fs/node_monitor.h> 34 #include <util/kernel_cpp.h> 35 36 #include <string.h> 37 #include <stdio.h> 38 #include <ctype.h> 39 #include <unistd.h> 40 #include <sys/stat.h> 41 #include <sys/resource.h> 42 #include <fcntl.h> 43 #include <limits.h> 44 #include <stddef.h> 45 46 //#define TRACE_VFS 47 #ifdef TRACE_VFS 48 # define PRINT(x) dprintf x 49 # define FUNCTION(x) dprintf x 50 #else 51 # define PRINT(x) ; 52 # define FUNCTION(x) ; 53 #endif 54 55 #define ADD_DEBUGGER_COMMANDS 56 57 #define MAX_SYM_LINKS SYMLINKS_MAX 58 59 const static uint32 kMaxUnusedVnodes = 8192; 60 // This is the maximum number of unused vnodes that the system 61 // will keep around. 62 // It may be chosen with respect to the available memory or enhanced 63 // by some timestamp/frequency heurism. 64 65 static struct { 66 const char *path; 67 const char *target; 68 } sPredefinedLinks[] = { 69 {"/system", "/boot/beos/system"}, 70 {"/bin", "/boot/beos/bin"}, 71 {"/etc", "/boot/beos/etc"}, 72 {"/var", "/boot/var"}, 73 {"/tmp", "/boot/var/tmp"}, 74 {NULL} 75 }; 76 77 struct vnode { 78 struct vnode *next; 79 vm_cache_ref *cache; 80 mount_id device; 81 list_link mount_link; 82 list_link unused_link; 83 vnode_id id; 84 fs_vnode private_node; 85 struct fs_mount *mount; 86 struct vnode *covered_by; 87 int32 ref_count; 88 uint8 remove : 1; 89 uint8 busy : 1; 90 uint8 unpublished : 1; 91 struct advisory_locking *advisory_locking; 92 }; 93 94 struct vnode_hash_key { 95 mount_id device; 96 vnode_id vnode; 97 }; 98 99 #define FS_CALL(vnode, op) (vnode->mount->fs->op) 100 #define FS_MOUNT_CALL(mount, op) (mount->fs->op) 101 102 struct fs_mount { 103 struct fs_mount *next; 104 file_system_module_info *fs; 105 mount_id id; 106 void *cookie; 107 char *device_name; 108 char *fs_name; 109 recursive_lock rlock; // guards the vnodes list 110 struct vnode *root_vnode; 111 struct vnode *covers_vnode; 112 KPartition *partition; 113 struct list vnodes; 114 bool unmounting; 115 bool owns_file_device; 116 }; 117 118 struct advisory_locking { 119 sem_id lock; 120 sem_id wait_sem; 121 struct list locks; 122 }; 123 124 struct advisory_lock { 125 list_link link; 126 team_id team; 127 off_t offset; 128 off_t length; 129 bool shared; 130 }; 131 132 static mutex sFileSystemsMutex; 133 134 /** \brief Guards sMountsTable. 135 * 136 * The holder is allowed to read/write access the sMountsTable. 137 * Manipulation of the fs_mount structures themselves 138 * (and their destruction) requires different locks though. 139 */ 140 static mutex sMountMutex; 141 142 /** \brief Guards mount/unmount operations. 143 * 144 * The fs_mount() and fs_unmount() hold the lock during their whole operation. 145 * That is locking the lock ensures that no FS is mounted/unmounted. In 146 * particular this means that 147 * - sMountsTable will not be modified, 148 * - the fields immutable after initialization of the fs_mount structures in 149 * sMountsTable will not be modified, 150 * - vnode::covered_by of any vnode in sVnodeTable will not be modified, 151 * 152 * The thread trying to lock the lock must not hold sVnodeMutex or 153 * sMountMutex. 154 */ 155 static recursive_lock sMountOpLock; 156 157 /** \brief Guards sVnodeTable. 158 * 159 * The holder is allowed to read/write access sVnodeTable and to 160 * to any unbusy vnode in that table, save 161 * to the immutable fields (device, id, private_node, mount) to which 162 * only read-only access is allowed, and to the field covered_by, which is 163 * guarded by sMountOpLock. 164 * 165 * The thread trying to lock the mutex must not hold sMountMutex. 166 */ 167 static mutex sVnodeMutex; 168 169 #define VNODE_HASH_TABLE_SIZE 1024 170 static hash_table *sVnodeTable; 171 static list sUnusedVnodeList; 172 static uint32 sUnusedVnodes = 0; 173 static struct vnode *sRoot; 174 175 #define MOUNTS_HASH_TABLE_SIZE 16 176 static hash_table *sMountsTable; 177 static mount_id sNextMountID = 1; 178 179 mode_t __gUmask = 022; 180 181 // This can be used by other code to see if there is a boot file system already 182 dev_t gBootDevice = -1; 183 184 185 /* function declarations */ 186 187 // file descriptor operation prototypes 188 static status_t file_read(struct file_descriptor *, off_t pos, void *buffer, size_t *); 189 static status_t file_write(struct file_descriptor *, off_t pos, const void *buffer, size_t *); 190 static off_t file_seek(struct file_descriptor *, off_t pos, int seek_type); 191 static void file_free_fd(struct file_descriptor *); 192 static status_t file_close(struct file_descriptor *); 193 static status_t file_select(struct file_descriptor *, uint8 event, uint32 ref, 194 struct select_sync *sync); 195 static status_t file_deselect(struct file_descriptor *, uint8 event, 196 struct select_sync *sync); 197 static status_t dir_read(struct file_descriptor *, struct dirent *buffer, size_t bufferSize, uint32 *_count); 198 static status_t dir_read(struct vnode *vnode, fs_cookie cookie, struct dirent *buffer, size_t bufferSize, uint32 *_count); 199 static status_t dir_rewind(struct file_descriptor *); 200 static void dir_free_fd(struct file_descriptor *); 201 static status_t dir_close(struct file_descriptor *); 202 static status_t attr_dir_read(struct file_descriptor *, struct dirent *buffer, size_t bufferSize, uint32 *_count); 203 static status_t attr_dir_rewind(struct file_descriptor *); 204 static void attr_dir_free_fd(struct file_descriptor *); 205 static status_t attr_dir_close(struct file_descriptor *); 206 static status_t attr_read(struct file_descriptor *, off_t pos, void *buffer, size_t *); 207 static status_t attr_write(struct file_descriptor *, off_t pos, const void *buffer, size_t *); 208 static off_t attr_seek(struct file_descriptor *, off_t pos, int seek_type); 209 static void attr_free_fd(struct file_descriptor *); 210 static status_t attr_close(struct file_descriptor *); 211 static status_t attr_read_stat(struct file_descriptor *, struct stat *); 212 static status_t attr_write_stat(struct file_descriptor *, const struct stat *, int statMask); 213 static status_t index_dir_read(struct file_descriptor *, struct dirent *buffer, size_t bufferSize, uint32 *_count); 214 static status_t index_dir_rewind(struct file_descriptor *); 215 static void index_dir_free_fd(struct file_descriptor *); 216 static status_t index_dir_close(struct file_descriptor *); 217 static status_t query_read(struct file_descriptor *, struct dirent *buffer, size_t bufferSize, uint32 *_count); 218 static status_t query_rewind(struct file_descriptor *); 219 static void query_free_fd(struct file_descriptor *); 220 static status_t query_close(struct file_descriptor *); 221 222 static status_t common_ioctl(struct file_descriptor *, ulong, void *buf, size_t len); 223 static status_t common_read_stat(struct file_descriptor *, struct stat *); 224 static status_t common_write_stat(struct file_descriptor *, const struct stat *, int statMask); 225 226 static status_t vnode_path_to_vnode(struct vnode *vnode, char *path, 227 bool traverseLeafLink, int count, struct vnode **_vnode, vnode_id *_parentID, int *_type); 228 static status_t dir_vnode_to_path(struct vnode *vnode, char *buffer, size_t bufferSize); 229 static status_t fd_and_path_to_vnode(int fd, char *path, bool traverseLeafLink, 230 struct vnode **_vnode, vnode_id *_parentID, bool kernel); 231 static void inc_vnode_ref_count(struct vnode *vnode); 232 static status_t dec_vnode_ref_count(struct vnode *vnode, bool reenter); 233 static inline void put_vnode(struct vnode *vnode); 234 235 static struct fd_ops sFileOps = { 236 file_read, 237 file_write, 238 file_seek, 239 common_ioctl, 240 file_select, 241 file_deselect, 242 NULL, // read_dir() 243 NULL, // rewind_dir() 244 common_read_stat, 245 common_write_stat, 246 file_close, 247 file_free_fd 248 }; 249 250 static struct fd_ops sDirectoryOps = { 251 NULL, // read() 252 NULL, // write() 253 NULL, // seek() 254 common_ioctl, 255 NULL, // select() 256 NULL, // deselect() 257 dir_read, 258 dir_rewind, 259 common_read_stat, 260 common_write_stat, 261 dir_close, 262 dir_free_fd 263 }; 264 265 static struct fd_ops sAttributeDirectoryOps = { 266 NULL, // read() 267 NULL, // write() 268 NULL, // seek() 269 common_ioctl, 270 NULL, // select() 271 NULL, // deselect() 272 attr_dir_read, 273 attr_dir_rewind, 274 common_read_stat, 275 common_write_stat, 276 attr_dir_close, 277 attr_dir_free_fd 278 }; 279 280 static struct fd_ops sAttributeOps = { 281 attr_read, 282 attr_write, 283 attr_seek, 284 common_ioctl, 285 NULL, // select() 286 NULL, // deselect() 287 NULL, // read_dir() 288 NULL, // rewind_dir() 289 attr_read_stat, 290 attr_write_stat, 291 attr_close, 292 attr_free_fd 293 }; 294 295 static struct fd_ops sIndexDirectoryOps = { 296 NULL, // read() 297 NULL, // write() 298 NULL, // seek() 299 NULL, // ioctl() 300 NULL, // select() 301 NULL, // deselect() 302 index_dir_read, 303 index_dir_rewind, 304 NULL, // read_stat() 305 NULL, // write_stat() 306 index_dir_close, 307 index_dir_free_fd 308 }; 309 310 #if 0 311 static struct fd_ops sIndexOps = { 312 NULL, // read() 313 NULL, // write() 314 NULL, // seek() 315 NULL, // ioctl() 316 NULL, // select() 317 NULL, // deselect() 318 NULL, // dir_read() 319 NULL, // dir_rewind() 320 index_read_stat, // read_stat() 321 NULL, // write_stat() 322 NULL, // dir_close() 323 NULL // free_fd() 324 }; 325 #endif 326 327 static struct fd_ops sQueryOps = { 328 NULL, // read() 329 NULL, // write() 330 NULL, // seek() 331 NULL, // ioctl() 332 NULL, // select() 333 NULL, // deselect() 334 query_read, 335 query_rewind, 336 NULL, // read_stat() 337 NULL, // write_stat() 338 query_close, 339 query_free_fd 340 }; 341 342 343 // VNodePutter 344 class VNodePutter { 345 public: 346 VNodePutter(struct vnode *vnode = NULL) : fVNode(vnode) {} 347 348 ~VNodePutter() 349 { 350 Put(); 351 } 352 353 void SetTo(struct vnode *vnode) 354 { 355 Put(); 356 fVNode = vnode; 357 } 358 359 void Put() 360 { 361 if (fVNode) { 362 put_vnode(fVNode); 363 fVNode = NULL; 364 } 365 } 366 367 struct vnode *Detach() 368 { 369 struct vnode *vnode = fVNode; 370 fVNode = NULL; 371 return vnode; 372 } 373 374 private: 375 struct vnode *fVNode; 376 }; 377 378 379 class FDCloser { 380 public: 381 FDCloser() : fFD(-1), fKernel(true) {} 382 383 FDCloser(int fd, bool kernel) : fFD(fd), fKernel(kernel) {} 384 385 ~FDCloser() 386 { 387 Close(); 388 } 389 390 void SetTo(int fd, bool kernel) 391 { 392 Close(); 393 fFD = fd; 394 fKernel = kernel; 395 } 396 397 void Close() 398 { 399 if (fFD >= 0) { 400 if (fKernel) 401 _kern_close(fFD); 402 else 403 _user_close(fFD); 404 fFD = -1; 405 } 406 } 407 408 int Detach() 409 { 410 int fd = fFD; 411 fFD = -1; 412 return fd; 413 } 414 415 private: 416 int fFD; 417 bool fKernel; 418 }; 419 420 421 static int 422 mount_compare(void *_m, const void *_key) 423 { 424 struct fs_mount *mount = (fs_mount *)_m; 425 const mount_id *id = (mount_id *)_key; 426 427 if (mount->id == *id) 428 return 0; 429 430 return -1; 431 } 432 433 434 static uint32 435 mount_hash(void *_m, const void *_key, uint32 range) 436 { 437 struct fs_mount *mount = (fs_mount *)_m; 438 const mount_id *id = (mount_id *)_key; 439 440 if (mount) 441 return mount->id % range; 442 443 return (uint32)*id % range; 444 } 445 446 447 /** Finds the mounted device (the fs_mount structure) with the given ID. 448 * Note, you must hold the gMountMutex lock when you call this function. 449 */ 450 451 static struct fs_mount * 452 find_mount(mount_id id) 453 { 454 ASSERT_LOCKED_MUTEX(&sMountMutex); 455 456 return (fs_mount *)hash_lookup(sMountsTable, (void *)&id); 457 } 458 459 460 static struct fs_mount * 461 get_mount(mount_id id) 462 { 463 struct fs_mount *mount; 464 465 mutex_lock(&sMountMutex); 466 467 mount = find_mount(id); 468 if (mount) { 469 // ToDo: the volume is locked (against removal) by locking 470 // its root node - investigate if that's a good idea 471 if (mount->root_vnode) 472 inc_vnode_ref_count(mount->root_vnode); 473 else 474 mount = NULL; 475 } 476 477 mutex_unlock(&sMountMutex); 478 479 return mount; 480 } 481 482 483 static void 484 put_mount(struct fs_mount *mount) 485 { 486 if (mount) 487 put_vnode(mount->root_vnode); 488 } 489 490 491 static status_t 492 put_file_system(file_system_module_info *fs) 493 { 494 return put_module(fs->info.name); 495 } 496 497 498 /** Tries to open the specified file system module. 499 * Accepts a file system name of the form "bfs" or "file_systems/bfs/v1". 500 * Returns a pointer to file system module interface, or NULL if it 501 * could not open the module. 502 */ 503 504 static file_system_module_info * 505 get_file_system(const char *fsName) 506 { 507 char name[B_FILE_NAME_LENGTH]; 508 if (strncmp(fsName, "file_systems/", strlen("file_systems/"))) { 509 // construct module name if we didn't get one 510 // (we currently support only one API) 511 snprintf(name, sizeof(name), "file_systems/%s/v1", fsName); 512 fsName = NULL; 513 } 514 515 file_system_module_info *info; 516 if (get_module(fsName ? fsName : name, (module_info **)&info) != B_OK) 517 return NULL; 518 519 return info; 520 } 521 522 523 /** Accepts a file system name of the form "bfs" or "file_systems/bfs/v1" 524 * and returns a compatible fs_info.fsh_name name ("bfs" in both cases). 525 * The name is allocated for you, and you have to free() it when you're 526 * done with it. 527 * Returns NULL if the required memory is no available. 528 */ 529 530 static char * 531 get_file_system_name(const char *fsName) 532 { 533 const size_t length = strlen("file_systems/"); 534 535 if (strncmp(fsName, "file_systems/", length)) { 536 // the name already seems to be the module's file name 537 return strdup(fsName); 538 } 539 540 fsName += length; 541 const char *end = strchr(fsName, '/'); 542 if (end == NULL) { 543 // this doesn't seem to be a valid name, but well... 544 return strdup(fsName); 545 } 546 547 // cut off the trailing /v1 548 549 char *name = (char *)malloc(end + 1 - fsName); 550 if (name == NULL) 551 return NULL; 552 553 strlcpy(name, fsName, end + 1 - fsName); 554 return name; 555 } 556 557 558 static int 559 vnode_compare(void *_vnode, const void *_key) 560 { 561 struct vnode *vnode = (struct vnode *)_vnode; 562 const struct vnode_hash_key *key = (vnode_hash_key *)_key; 563 564 if (vnode->device == key->device && vnode->id == key->vnode) 565 return 0; 566 567 return -1; 568 } 569 570 571 static uint32 572 vnode_hash(void *_vnode, const void *_key, uint32 range) 573 { 574 struct vnode *vnode = (struct vnode *)_vnode; 575 const struct vnode_hash_key *key = (vnode_hash_key *)_key; 576 577 #define VHASH(mountid, vnodeid) (((uint32)((vnodeid) >> 32) + (uint32)(vnodeid)) ^ (uint32)(mountid)) 578 579 if (vnode != NULL) 580 return VHASH(vnode->device, vnode->id) % range; 581 582 return VHASH(key->device, key->vnode) % range; 583 584 #undef VHASH 585 } 586 587 588 static void 589 add_vnode_to_mount_list(struct vnode *vnode, struct fs_mount *mount) 590 { 591 recursive_lock_lock(&mount->rlock); 592 593 list_add_link_to_head(&mount->vnodes, &vnode->mount_link); 594 595 recursive_lock_unlock(&mount->rlock); 596 } 597 598 599 static void 600 remove_vnode_from_mount_list(struct vnode *vnode, struct fs_mount *mount) 601 { 602 recursive_lock_lock(&mount->rlock); 603 604 list_remove_link(&vnode->mount_link); 605 vnode->mount_link.next = vnode->mount_link.prev = NULL; 606 607 recursive_lock_unlock(&mount->rlock); 608 } 609 610 611 static status_t 612 create_new_vnode(struct vnode **_vnode, mount_id mountID, vnode_id vnodeID) 613 { 614 FUNCTION(("create_new_vnode()\n")); 615 616 struct vnode *vnode = (struct vnode *)malloc(sizeof(struct vnode)); 617 if (vnode == NULL) 618 return B_NO_MEMORY; 619 620 // initialize basic values 621 memset(vnode, 0, sizeof(struct vnode)); 622 vnode->device = mountID; 623 vnode->id = vnodeID; 624 625 // add the vnode to the mount structure 626 mutex_lock(&sMountMutex); 627 vnode->mount = find_mount(mountID); 628 if (!vnode->mount || vnode->mount->unmounting) { 629 mutex_unlock(&sMountMutex); 630 free(vnode); 631 return B_ENTRY_NOT_FOUND; 632 } 633 634 hash_insert(sVnodeTable, vnode); 635 add_vnode_to_mount_list(vnode, vnode->mount); 636 637 mutex_unlock(&sMountMutex); 638 639 vnode->ref_count = 1; 640 *_vnode = vnode; 641 642 return B_OK; 643 } 644 645 646 /** Frees the vnode and all resources it has acquired, and removes 647 * it from the vnode hash as well as from its mount structure. 648 * Will also make sure that any cache modifications are written back. 649 */ 650 651 static void 652 free_vnode(struct vnode *vnode, bool reenter) 653 { 654 ASSERT(vnode->ref_count == 0 && vnode->busy); 655 656 // write back any changes in this vnode's cache -- but only 657 // if the vnode won't be deleted, in which case the changes 658 // will be discarded 659 660 if (vnode->cache && !vnode->remove) 661 vm_cache_write_modified(vnode->cache); 662 663 if (!vnode->unpublished) { 664 if (vnode->remove) 665 FS_CALL(vnode, remove_vnode)(vnode->mount->cookie, vnode->private_node, reenter); 666 else 667 FS_CALL(vnode, put_vnode)(vnode->mount->cookie, vnode->private_node, reenter); 668 } 669 670 // The file system has removed the resources of the vnode now, so we can 671 // make it available again (and remove the busy vnode from the hash) 672 mutex_lock(&sVnodeMutex); 673 hash_remove(sVnodeTable, vnode); 674 mutex_unlock(&sVnodeMutex); 675 676 // if we have a vm_cache attached, remove it 677 if (vnode->cache) 678 vm_cache_release_ref(vnode->cache); 679 680 vnode->cache = NULL; 681 682 remove_vnode_from_mount_list(vnode, vnode->mount); 683 684 free(vnode); 685 } 686 687 688 /** \brief Decrements the reference counter of the given vnode and deletes it, 689 * if the counter dropped to 0. 690 * 691 * The caller must, of course, own a reference to the vnode to call this 692 * function. 693 * The caller must not hold the sVnodeMutex or the sMountMutex. 694 * 695 * \param vnode the vnode. 696 * \param reenter \c true, if this function is called (indirectly) from within 697 * a file system. 698 * \return \c B_OK, if everything went fine, an error code otherwise. 699 */ 700 701 static status_t 702 dec_vnode_ref_count(struct vnode *vnode, bool reenter) 703 { 704 int32 oldRefCount; 705 706 mutex_lock(&sVnodeMutex); 707 708 if (vnode->busy) 709 panic("dec_vnode_ref_count called on vnode that was busy! vnode %p\n", vnode); 710 711 oldRefCount = atomic_add(&vnode->ref_count, -1); 712 713 PRINT(("dec_vnode_ref_count: vnode %p, ref now %ld\n", vnode, vnode->ref_count)); 714 715 if (oldRefCount == 1) { 716 bool freeNode = false; 717 718 // Just insert the vnode into an unused list if we don't need 719 // to delete it 720 if (vnode->remove) { 721 vnode->busy = true; 722 freeNode = true; 723 } else { 724 list_add_item(&sUnusedVnodeList, vnode); 725 if (++sUnusedVnodes > kMaxUnusedVnodes) { 726 // there are too many unused vnodes so we free the oldest one 727 // ToDo: evaluate this mechanism 728 vnode = (struct vnode *)list_remove_head_item(&sUnusedVnodeList); 729 vnode->busy = true; 730 freeNode = true; 731 sUnusedVnodes--; 732 } 733 } 734 735 mutex_unlock(&sVnodeMutex); 736 737 if (freeNode) 738 free_vnode(vnode, reenter); 739 } else 740 mutex_unlock(&sVnodeMutex); 741 742 return B_OK; 743 } 744 745 746 /** \brief Increments the reference counter of the given vnode. 747 * 748 * The caller must either already have a reference to the vnode or hold 749 * the sVnodeMutex. 750 * 751 * \param vnode the vnode. 752 */ 753 754 static void 755 inc_vnode_ref_count(struct vnode *vnode) 756 { 757 atomic_add(&vnode->ref_count, 1); 758 PRINT(("inc_vnode_ref_count: vnode %p, ref now %ld\n", vnode, vnode->ref_count)); 759 } 760 761 762 /** \brief Looks up a vnode by mount and node ID in the sVnodeTable. 763 * 764 * The caller must hold the sVnodeMutex. 765 * 766 * \param mountID the mount ID. 767 * \param vnodeID the node ID. 768 * 769 * \return The vnode structure, if it was found in the hash table, \c NULL 770 * otherwise. 771 */ 772 773 static struct vnode * 774 lookup_vnode(mount_id mountID, vnode_id vnodeID) 775 { 776 struct vnode_hash_key key; 777 778 key.device = mountID; 779 key.vnode = vnodeID; 780 781 return (vnode *)hash_lookup(sVnodeTable, &key); 782 } 783 784 785 /** \brief Retrieves a vnode for a given mount ID, node ID pair. 786 * 787 * If the node is not yet in memory, it will be loaded. 788 * 789 * The caller must not hold the sVnodeMutex or the sMountMutex. 790 * 791 * \param mountID the mount ID. 792 * \param vnodeID the node ID. 793 * \param _vnode Pointer to a vnode* variable into which the pointer to the 794 * retrieved vnode structure shall be written. 795 * \param reenter \c true, if this function is called (indirectly) from within 796 * a file system. 797 * \return \c B_OK, if everything when fine, an error code otherwise. 798 */ 799 800 static status_t 801 get_vnode(mount_id mountID, vnode_id vnodeID, struct vnode **_vnode, int reenter) 802 { 803 FUNCTION(("get_vnode: mountid %ld vnid 0x%Lx %p\n", mountID, vnodeID, _vnode)); 804 805 mutex_lock(&sVnodeMutex); 806 807 restart: 808 struct vnode *vnode = lookup_vnode(mountID, vnodeID); 809 if (vnode && vnode->busy) { 810 // ToDo: this is an endless loop if the vnode is not 811 // becoming unbusy anymore (for whatever reason) 812 mutex_unlock(&sVnodeMutex); 813 snooze(10000); // 10 ms 814 mutex_lock(&sVnodeMutex); 815 goto restart; 816 } 817 818 PRINT(("get_vnode: tried to lookup vnode, got %p\n", vnode)); 819 820 status_t status; 821 822 if (vnode) { 823 if (vnode->ref_count == 0) { 824 // this vnode has been unused before 825 list_remove_item(&sUnusedVnodeList, vnode); 826 } 827 inc_vnode_ref_count(vnode); 828 } else { 829 // we need to create a new vnode and read it in 830 status = create_new_vnode(&vnode, mountID, vnodeID); 831 if (status < B_OK) 832 goto err; 833 834 vnode->busy = true; 835 mutex_unlock(&sVnodeMutex); 836 837 status = FS_CALL(vnode, get_vnode)(vnode->mount->cookie, vnodeID, &vnode->private_node, reenter); 838 if (status < B_OK || vnode->private_node == NULL) { 839 if (status == B_NO_ERROR) 840 status = B_BAD_VALUE; 841 } 842 mutex_lock(&sVnodeMutex); 843 844 if (status < B_OK) 845 goto err1; 846 847 vnode->busy = false; 848 } 849 850 mutex_unlock(&sVnodeMutex); 851 852 PRINT(("get_vnode: returning %p\n", vnode)); 853 854 *_vnode = vnode; 855 return B_OK; 856 857 err1: 858 hash_remove(sVnodeTable, vnode); 859 remove_vnode_from_mount_list(vnode, vnode->mount); 860 err: 861 mutex_unlock(&sVnodeMutex); 862 if (vnode) 863 free(vnode); 864 865 return status; 866 } 867 868 869 /** \brief Decrements the reference counter of the given vnode and deletes it, 870 * if the counter dropped to 0. 871 * 872 * The caller must, of course, own a reference to the vnode to call this 873 * function. 874 * The caller must not hold the sVnodeMutex or the sMountMutex. 875 * 876 * \param vnode the vnode. 877 */ 878 879 static inline void 880 put_vnode(struct vnode *vnode) 881 { 882 dec_vnode_ref_count(vnode, false); 883 } 884 885 886 static status_t 887 create_advisory_locking(struct vnode *vnode) 888 { 889 status_t status; 890 891 struct advisory_locking *locking = (struct advisory_locking *)malloc(sizeof(struct advisory_locking)); 892 if (locking == NULL) 893 return B_NO_MEMORY; 894 895 locking->wait_sem = create_sem(0, "advisory lock"); 896 if (locking->wait_sem < B_OK) { 897 status = locking->wait_sem; 898 goto err1; 899 } 900 901 locking->lock = create_sem(1, "advisory locking"); 902 if (locking->lock < B_OK) { 903 status = locking->lock; 904 goto err2; 905 } 906 907 list_init(&locking->locks); 908 vnode->advisory_locking = locking; 909 return B_OK; 910 911 err2: 912 delete_sem(locking->wait_sem); 913 err1: 914 free(locking); 915 return status; 916 } 917 918 919 static inline void 920 put_advisory_locking(struct advisory_locking *locking) 921 { 922 release_sem(locking->lock); 923 } 924 925 926 static struct advisory_locking * 927 get_advisory_locking(struct vnode *vnode) 928 { 929 mutex_lock(&sVnodeMutex); 930 931 struct advisory_locking *locking = vnode->advisory_locking; 932 if (locking != NULL) 933 acquire_sem(locking->lock); 934 935 mutex_unlock(&sVnodeMutex); 936 return locking; 937 } 938 939 940 static status_t 941 get_advisory_lock(struct vnode *vnode, struct flock *flock) 942 { 943 return B_ERROR; 944 } 945 946 947 /** Removes the specified lock, or all locks of the calling team 948 * if \a flock is NULL. 949 */ 950 951 static status_t 952 release_advisory_lock(struct vnode *vnode, struct flock *flock) 953 { 954 FUNCTION(("release_advisory_lock(vnode = %p, flock = %p)\n", vnode, flock)); 955 956 struct advisory_locking *locking = get_advisory_locking(vnode); 957 if (locking == NULL) 958 return flock != NULL ? B_BAD_VALUE : B_OK; 959 960 team_id team = team_get_current_team_id(); 961 962 // find matching lock entry 963 964 status_t status = B_BAD_VALUE; 965 struct advisory_lock *lock = NULL; 966 while ((lock = (struct advisory_lock *)list_get_next_item(&locking->locks, lock)) != NULL) { 967 if (lock->team == team && (flock == NULL || (flock != NULL 968 && lock->offset == flock->l_start 969 && lock->length == flock->l_len))) { 970 // we found our lock, free it 971 list_remove_item(&locking->locks, lock); 972 free(lock); 973 status = B_OK; 974 break; 975 } 976 } 977 978 bool removeLocking = list_is_empty(&locking->locks); 979 release_sem_etc(locking->wait_sem, 1, B_RELEASE_ALL); 980 981 put_advisory_locking(locking); 982 983 if (status < B_OK) 984 return status; 985 986 if (removeLocking) { 987 // we can remove the whole advisory locking structure; it's no longer used 988 mutex_lock(&sVnodeMutex); 989 locking = vnode->advisory_locking; 990 if (locking != NULL) 991 acquire_sem(locking->lock); 992 993 // the locking could have been changed in the mean time 994 if (list_is_empty(&locking->locks)) 995 vnode->advisory_locking = NULL; 996 else { 997 removeLocking = false; 998 release_sem_etc(locking->lock, 1, B_DO_NOT_RESCHEDULE); 999 } 1000 1001 mutex_unlock(&sVnodeMutex); 1002 } 1003 if (removeLocking) { 1004 // we've detached the locking from the vnode, so we can safely delete it 1005 delete_sem(locking->lock); 1006 delete_sem(locking->wait_sem); 1007 free(locking); 1008 } 1009 1010 return B_OK; 1011 } 1012 1013 1014 static status_t 1015 acquire_advisory_lock(struct vnode *vnode, struct flock *flock, bool wait) 1016 { 1017 FUNCTION(("acquire_advisory_lock(vnode = %p, flock = %p, wait = %s)\n", 1018 vnode, flock, wait ? "yes" : "no")); 1019 1020 bool shared = flock->l_type == F_RDLCK; 1021 status_t status = B_OK; 1022 1023 restart: 1024 // if this vnode has an advisory_locking structure attached, 1025 // lock that one and search for any colliding lock 1026 struct advisory_locking *locking = get_advisory_locking(vnode); 1027 sem_id waitForLock = -1; 1028 1029 if (locking != NULL) { 1030 // test for collisions 1031 struct advisory_lock *lock = NULL; 1032 while ((lock = (struct advisory_lock *)list_get_next_item(&locking->locks, lock)) != NULL) { 1033 if (lock->offset <= flock->l_start + flock->l_len 1034 && lock->offset + lock->length > flock->l_start) { 1035 // locks do overlap 1036 if (!shared || !lock->shared) { 1037 // we need to wait 1038 waitForLock = locking->wait_sem; 1039 break; 1040 } 1041 } 1042 } 1043 1044 if (waitForLock < B_OK || !wait) 1045 put_advisory_locking(locking); 1046 } 1047 1048 // wait for the lock if we have to, or else return immediately 1049 1050 if (waitForLock >= B_OK) { 1051 if (!wait) 1052 status = B_PERMISSION_DENIED; 1053 else { 1054 status = switch_sem_etc(locking->lock, waitForLock, 1, B_CAN_INTERRUPT, 0); 1055 if (status == B_OK) { 1056 // see if we're still colliding 1057 goto restart; 1058 } 1059 } 1060 } 1061 1062 if (status < B_OK) 1063 return status; 1064 1065 // install new lock 1066 1067 mutex_lock(&sVnodeMutex); 1068 1069 locking = vnode->advisory_locking; 1070 if (locking == NULL) { 1071 status = create_advisory_locking(vnode); 1072 locking = vnode->advisory_locking; 1073 } 1074 1075 if (locking != NULL) 1076 acquire_sem(locking->lock); 1077 1078 mutex_unlock(&sVnodeMutex); 1079 1080 if (status < B_OK) 1081 return status; 1082 1083 struct advisory_lock *lock = (struct advisory_lock *)malloc(sizeof(struct advisory_lock)); 1084 if (lock == NULL) { 1085 if (waitForLock >= B_OK) 1086 release_sem_etc(waitForLock, 1, B_RELEASE_ALL); 1087 release_sem(locking->lock); 1088 return B_NO_MEMORY; 1089 } 1090 1091 lock->team = team_get_current_team_id(); 1092 // values must already be normalized when getting here 1093 lock->offset = flock->l_start; 1094 lock->length = flock->l_len; 1095 lock->shared = shared; 1096 1097 list_add_item(&locking->locks, lock); 1098 release_sem(locking->lock); 1099 1100 return status; 1101 } 1102 1103 1104 static status_t 1105 normalize_flock(struct file_descriptor *descriptor, struct flock *flock) 1106 { 1107 switch (flock->l_whence) { 1108 case SEEK_SET: 1109 break; 1110 case SEEK_CUR: 1111 flock->l_start += descriptor->pos; 1112 break; 1113 case SEEK_END: 1114 { 1115 struct vnode *vnode = descriptor->u.vnode; 1116 struct stat stat; 1117 status_t status; 1118 1119 if (FS_CALL(vnode, read_stat) == NULL) 1120 return EOPNOTSUPP; 1121 1122 status = FS_CALL(vnode, read_stat)(vnode->mount->cookie, vnode->private_node, &stat); 1123 if (status < B_OK) 1124 return status; 1125 1126 flock->l_start += stat.st_size; 1127 break; 1128 } 1129 default: 1130 return B_BAD_VALUE; 1131 } 1132 1133 if (flock->l_start < 0) 1134 flock->l_start = 0; 1135 if (flock->l_len == 0) 1136 flock->l_len = OFF_MAX; 1137 1138 // don't let the offset and length overflow 1139 if (flock->l_start > 0 && OFF_MAX - flock->l_start < flock->l_len) 1140 flock->l_len = OFF_MAX - flock->l_start; 1141 1142 if (flock->l_len < 0) { 1143 // a negative length reverses the region 1144 flock->l_start += flock->l_len; 1145 flock->l_len = -flock->l_len; 1146 } 1147 1148 return B_OK; 1149 } 1150 1151 1152 /** \brief Resolves a mount point vnode to the volume root vnode it is covered 1153 * by. 1154 * 1155 * Given an arbitrary vnode, the function checks, whether the node is covered 1156 * by the root of a volume. If it is the function obtains a reference to the 1157 * volume root node and returns it. 1158 * 1159 * \param vnode The vnode in question. 1160 * \return The volume root vnode the vnode cover is covered by, if it is 1161 * indeed a mount point, or \c NULL otherwise. 1162 */ 1163 1164 static struct vnode * 1165 resolve_mount_point_to_volume_root(struct vnode *vnode) 1166 { 1167 if (!vnode) 1168 return NULL; 1169 1170 struct vnode *volumeRoot = NULL; 1171 1172 recursive_lock_lock(&sMountOpLock); 1173 if (vnode->covered_by) { 1174 volumeRoot = vnode->covered_by; 1175 inc_vnode_ref_count(volumeRoot); 1176 } 1177 recursive_lock_unlock(&sMountOpLock); 1178 1179 return volumeRoot; 1180 } 1181 1182 1183 /** \brief Resolves a mount point vnode to the volume root vnode it is covered 1184 * by. 1185 * 1186 * Given an arbitrary vnode (identified by mount and node ID), the function 1187 * checks, whether the node is covered by the root of a volume. If it is the 1188 * function returns the mount and node ID of the volume root node. Otherwise 1189 * it simply returns the supplied mount and node ID. 1190 * 1191 * In case of error (e.g. the supplied node could not be found) the variables 1192 * for storing the resolved mount and node ID remain untouched and an error 1193 * code is returned. 1194 * 1195 * \param mountID The mount ID of the vnode in question. 1196 * \param nodeID The node ID of the vnode in question. 1197 * \param resolvedMountID Pointer to storage for the resolved mount ID. 1198 * \param resolvedNodeID Pointer to storage for the resolved node ID. 1199 * \return 1200 * - \c B_OK, if everything went fine, 1201 * - another error code, if something went wrong. 1202 */ 1203 1204 status_t 1205 resolve_mount_point_to_volume_root(mount_id mountID, vnode_id nodeID, 1206 mount_id *resolvedMountID, vnode_id *resolvedNodeID) 1207 { 1208 // get the node 1209 struct vnode *node; 1210 status_t error = get_vnode(mountID, nodeID, &node, false); 1211 if (error != B_OK) 1212 return error; 1213 1214 1215 // resolve the node 1216 struct vnode *resolvedNode = resolve_mount_point_to_volume_root(node); 1217 if (resolvedNode) { 1218 put_vnode(node); 1219 node = resolvedNode; 1220 } 1221 1222 // set the return values 1223 *resolvedMountID = node->device; 1224 *resolvedNodeID = node->id; 1225 1226 put_vnode(node); 1227 1228 return B_OK; 1229 } 1230 1231 1232 /** \brief Resolves a volume root vnode to the underlying mount point vnode. 1233 * 1234 * Given an arbitrary vnode, the function checks, whether the node is the 1235 * root of a volume. If it is (and if it is not "/"), the function obtains 1236 * a reference to the underlying mount point node and returns it. 1237 * 1238 * \param vnode The vnode in question. 1239 * \return The mount point vnode the vnode covers, if it is indeed a volume 1240 * root and not "/", or \c NULL otherwise. 1241 */ 1242 1243 static struct vnode * 1244 resolve_volume_root_to_mount_point(struct vnode *vnode) 1245 { 1246 if (!vnode) 1247 return NULL; 1248 1249 struct vnode *mountPoint = NULL; 1250 1251 recursive_lock_lock(&sMountOpLock); 1252 struct fs_mount *mount = vnode->mount; 1253 if (vnode == mount->root_vnode && mount->covers_vnode) { 1254 mountPoint = mount->covers_vnode; 1255 inc_vnode_ref_count(mountPoint); 1256 } 1257 recursive_lock_unlock(&sMountOpLock); 1258 1259 return mountPoint; 1260 } 1261 1262 1263 /** \brief Gets the directory path and leaf name for a given path. 1264 * 1265 * The supplied \a path is transformed to refer to the directory part of 1266 * the entry identified by the original path, and into the buffer \a filename 1267 * the leaf name of the original entry is written. 1268 * Neither the returned path nor the leaf name can be expected to be 1269 * canonical. 1270 * 1271 * \param path The path to be analyzed. Must be able to store at least one 1272 * additional character. 1273 * \param filename The buffer into which the leaf name will be written. 1274 * Must be of size B_FILE_NAME_LENGTH at least. 1275 * \return \c B_OK, if everything went fine, \c B_NAME_TOO_LONG, if the leaf 1276 * name is longer than \c B_FILE_NAME_LENGTH. 1277 */ 1278 1279 static status_t 1280 get_dir_path_and_leaf(char *path, char *filename) 1281 { 1282 char *p = strrchr(path, '/'); 1283 // '/' are not allowed in file names! 1284 1285 FUNCTION(("get_dir_path_and_leaf(path = %s)\n", path)); 1286 1287 if (!p) { 1288 // this path is single segment with no '/' in it 1289 // ex. "foo" 1290 if (strlcpy(filename, path, B_FILE_NAME_LENGTH) >= B_FILE_NAME_LENGTH) 1291 return B_NAME_TOO_LONG; 1292 strcpy(path, "."); 1293 } else { 1294 p++; 1295 if (*p == '\0') { 1296 // special case: the path ends in '/' 1297 strcpy(filename, "."); 1298 } else { 1299 // normal leaf: replace the leaf portion of the path with a '.' 1300 if (strlcpy(filename, p, B_FILE_NAME_LENGTH) 1301 >= B_FILE_NAME_LENGTH) { 1302 return B_NAME_TOO_LONG; 1303 } 1304 } 1305 p[0] = '.'; 1306 p[1] = '\0'; 1307 } 1308 return B_OK; 1309 } 1310 1311 1312 static status_t 1313 entry_ref_to_vnode(mount_id mountID, vnode_id directoryID, const char *name, struct vnode **_vnode) 1314 { 1315 char clonedName[B_FILE_NAME_LENGTH + 1]; 1316 if (strlcpy(clonedName, name, B_FILE_NAME_LENGTH) >= B_FILE_NAME_LENGTH) 1317 return B_NAME_TOO_LONG; 1318 1319 // get the directory vnode and let vnode_path_to_vnode() do the rest 1320 struct vnode *directory; 1321 1322 status_t status = get_vnode(mountID, directoryID, &directory, false); 1323 if (status < 0) 1324 return status; 1325 1326 return vnode_path_to_vnode(directory, clonedName, false, 0, _vnode, NULL, NULL); 1327 } 1328 1329 1330 /** Returns the vnode for the relative path starting at the specified \a vnode. 1331 * \a path must not be NULL. 1332 * If it returns successfully, \a path contains the name of the last path 1333 * component. 1334 */ 1335 1336 static status_t 1337 vnode_path_to_vnode(struct vnode *vnode, char *path, bool traverseLeafLink, 1338 int count, struct vnode **_vnode, vnode_id *_parentID, int *_type) 1339 { 1340 status_t status = 0; 1341 vnode_id lastParentID = -1; 1342 int type = 0; 1343 1344 FUNCTION(("vnode_path_to_vnode(vnode = %p, path = %s)\n", vnode, path)); 1345 1346 if (path == NULL) 1347 return B_BAD_VALUE; 1348 1349 while (true) { 1350 struct vnode *nextVnode; 1351 vnode_id vnodeID; 1352 char *nextPath; 1353 1354 PRINT(("vnode_path_to_vnode: top of loop. p = %p, p = '%s'\n", path, path)); 1355 1356 // done? 1357 if (path[0] == '\0') 1358 break; 1359 1360 // walk to find the next path component ("path" will point to a single 1361 // path component), and filter out multiple slashes 1362 for (nextPath = path + 1; *nextPath != '\0' && *nextPath != '/'; nextPath++); 1363 1364 if (*nextPath == '/') { 1365 *nextPath = '\0'; 1366 do 1367 nextPath++; 1368 while (*nextPath == '/'); 1369 } 1370 1371 // See if the '..' is at the root of a mount and move to the covered 1372 // vnode so we pass the '..' path to the underlying filesystem 1373 if (!strcmp("..", path) 1374 && vnode->mount->root_vnode == vnode 1375 && vnode->mount->covers_vnode) { 1376 nextVnode = vnode->mount->covers_vnode; 1377 inc_vnode_ref_count(nextVnode); 1378 put_vnode(vnode); 1379 vnode = nextVnode; 1380 } 1381 1382 // Check if we have the right to search the current directory vnode. 1383 // If a file system doesn't have the access() function, we assume that 1384 // searching a directory is always allowed 1385 if (FS_CALL(vnode, access)) 1386 status = FS_CALL(vnode, access)(vnode->mount->cookie, vnode->private_node, X_OK); 1387 1388 // Tell the filesystem to get the vnode of this path component (if we got the 1389 // permission from the call above) 1390 if (status >= B_OK) 1391 status = FS_CALL(vnode, lookup)(vnode->mount->cookie, vnode->private_node, path, &vnodeID, &type); 1392 1393 if (status < B_OK) { 1394 put_vnode(vnode); 1395 return status; 1396 } 1397 1398 // Lookup the vnode, the call to fs_lookup should have caused a get_vnode to be called 1399 // from inside the filesystem, thus the vnode would have to be in the list and it's 1400 // ref count incremented at this point 1401 mutex_lock(&sVnodeMutex); 1402 nextVnode = lookup_vnode(vnode->device, vnodeID); 1403 mutex_unlock(&sVnodeMutex); 1404 1405 if (!nextVnode) { 1406 // pretty screwed up here - the file system found the vnode, but the hash 1407 // lookup failed, so our internal structures are messed up 1408 panic("vnode_path_to_vnode: could not lookup vnode (mountid 0x%lx vnid 0x%Lx)\n", 1409 vnode->device, vnodeID); 1410 put_vnode(vnode); 1411 return B_ENTRY_NOT_FOUND; 1412 } 1413 1414 // If the new node is a symbolic link, resolve it (if we've been told to do it) 1415 if (S_ISLNK(type) && !(!traverseLeafLink && nextPath[0] == '\0')) { 1416 size_t bufferSize; 1417 char *buffer; 1418 1419 PRINT(("traverse link\n")); 1420 1421 // it's not exactly nice style using goto in this way, but hey, it works :-/ 1422 if (count + 1 > MAX_SYM_LINKS) { 1423 status = B_LINK_LIMIT; 1424 goto resolve_link_error; 1425 } 1426 1427 buffer = (char *)malloc(bufferSize = B_PATH_NAME_LENGTH); 1428 if (buffer == NULL) { 1429 status = B_NO_MEMORY; 1430 goto resolve_link_error; 1431 } 1432 1433 status = FS_CALL(nextVnode, read_link)(nextVnode->mount->cookie, 1434 nextVnode->private_node, buffer, &bufferSize); 1435 if (status < B_OK) { 1436 free(buffer); 1437 1438 resolve_link_error: 1439 put_vnode(vnode); 1440 put_vnode(nextVnode); 1441 1442 return status; 1443 } 1444 put_vnode(nextVnode); 1445 1446 // Check if we start from the root directory or the current 1447 // directory ("vnode" still points to that one). 1448 // Cut off all leading slashes if it's the root directory 1449 path = buffer; 1450 if (path[0] == '/') { 1451 // we don't need the old directory anymore 1452 put_vnode(vnode); 1453 1454 while (*++path == '/') 1455 ; 1456 vnode = sRoot; 1457 inc_vnode_ref_count(vnode); 1458 } 1459 inc_vnode_ref_count(vnode); 1460 // balance the next recursion - we will decrement the ref_count 1461 // of the vnode, no matter if we succeeded or not 1462 1463 status = vnode_path_to_vnode(vnode, path, traverseLeafLink, count + 1, 1464 &nextVnode, &lastParentID, _type); 1465 1466 free(buffer); 1467 1468 if (status < B_OK) { 1469 put_vnode(vnode); 1470 return status; 1471 } 1472 } else 1473 lastParentID = vnode->id; 1474 1475 // decrease the ref count on the old dir we just looked up into 1476 put_vnode(vnode); 1477 1478 path = nextPath; 1479 vnode = nextVnode; 1480 1481 // see if we hit a mount point 1482 struct vnode *mountPoint = resolve_mount_point_to_volume_root(vnode); 1483 if (mountPoint) { 1484 put_vnode(vnode); 1485 vnode = mountPoint; 1486 } 1487 } 1488 1489 *_vnode = vnode; 1490 if (_type) 1491 *_type = type; 1492 if (_parentID) 1493 *_parentID = lastParentID; 1494 1495 return B_OK; 1496 } 1497 1498 1499 static status_t 1500 path_to_vnode(char *path, bool traverseLink, struct vnode **_vnode, 1501 vnode_id *_parentID, bool kernel) 1502 { 1503 struct vnode *start; 1504 1505 FUNCTION(("path_to_vnode(path = \"%s\")\n", path)); 1506 1507 if (!path) 1508 return B_BAD_VALUE; 1509 1510 // figure out if we need to start at root or at cwd 1511 if (*path == '/') { 1512 if (sRoot == NULL) { 1513 // we're a bit early, aren't we? 1514 return B_ERROR; 1515 } 1516 1517 while (*++path == '/') 1518 ; 1519 start = sRoot; 1520 inc_vnode_ref_count(start); 1521 } else { 1522 struct io_context *context = get_current_io_context(kernel); 1523 1524 mutex_lock(&context->io_mutex); 1525 start = context->cwd; 1526 inc_vnode_ref_count(start); 1527 mutex_unlock(&context->io_mutex); 1528 } 1529 1530 return vnode_path_to_vnode(start, path, traverseLink, 0, _vnode, _parentID, NULL); 1531 } 1532 1533 1534 /** Returns the vnode in the next to last segment of the path, and returns 1535 * the last portion in filename. 1536 * The path buffer must be able to store at least one additional character. 1537 */ 1538 1539 static status_t 1540 path_to_dir_vnode(char *path, struct vnode **_vnode, char *filename, bool kernel) 1541 { 1542 status_t status = get_dir_path_and_leaf(path, filename); 1543 if (status != B_OK) 1544 return status; 1545 1546 return path_to_vnode(path, true, _vnode, NULL, kernel); 1547 } 1548 1549 1550 /** \brief Retrieves the directory vnode and the leaf name of an entry referred 1551 * to by a FD + path pair. 1552 * 1553 * \a path must be given in either case. \a fd might be omitted, in which 1554 * case \a path is either an absolute path or one relative to the current 1555 * directory. If both a supplied and \a path is relative it is reckoned off 1556 * of the directory referred to by \a fd. If \a path is absolute \a fd is 1557 * ignored. 1558 * 1559 * The caller has the responsibility to call put_vnode() on the returned 1560 * directory vnode. 1561 * 1562 * \param fd The FD. May be < 0. 1563 * \param path The absolute or relative path. Must not be \c NULL. The buffer 1564 * is modified by this function. It must have at least room for a 1565 * string one character longer than the path it contains. 1566 * \param _vnode A pointer to a variable the directory vnode shall be written 1567 * into. 1568 * \param filename A buffer of size B_FILE_NAME_LENGTH or larger into which 1569 * the leaf name of the specified entry will be written. 1570 * \param kernel \c true, if invoked from inside the kernel, \c false if 1571 * invoked from userland. 1572 * \return \c B_OK, if everything went fine, another error code otherwise. 1573 */ 1574 1575 static status_t 1576 fd_and_path_to_dir_vnode(int fd, char *path, struct vnode **_vnode, 1577 char *filename, bool kernel) 1578 { 1579 if (!path) 1580 return B_BAD_VALUE; 1581 if (fd < 0) 1582 return path_to_dir_vnode(path, _vnode, filename, kernel); 1583 1584 status_t status = get_dir_path_and_leaf(path, filename); 1585 if (status != B_OK) 1586 return status; 1587 1588 return fd_and_path_to_vnode(fd, path, true, _vnode, NULL, kernel); 1589 } 1590 1591 1592 static status_t 1593 get_vnode_name(struct vnode *vnode, struct vnode *parent, 1594 char *name, size_t nameSize) 1595 { 1596 VNodePutter vnodePutter; 1597 1598 // See if vnode is the root of a mount and move to the covered 1599 // vnode so we get the underlying file system 1600 if (vnode->mount->root_vnode == vnode && vnode->mount->covers_vnode != NULL) { 1601 vnode = vnode->mount->covers_vnode; 1602 inc_vnode_ref_count(vnode); 1603 vnodePutter.SetTo(vnode); 1604 } 1605 1606 if (FS_CALL(vnode, get_vnode_name)) { 1607 // The FS supports getting the name of a vnode. 1608 return FS_CALL(vnode, get_vnode_name)(vnode->mount->cookie, 1609 vnode->private_node, name, nameSize); 1610 } 1611 1612 // The FS doesn't support getting the name of a vnode. So we search the 1613 // parent directory for the vnode, if the caller let us. 1614 1615 if (parent == NULL) 1616 return EOPNOTSUPP; 1617 1618 fs_cookie cookie; 1619 1620 status_t status = FS_CALL(parent, open_dir)(parent->mount->cookie, 1621 parent->private_node, &cookie); 1622 if (status >= B_OK) { 1623 char buffer[sizeof(struct dirent) + B_FILE_NAME_LENGTH]; 1624 struct dirent *dirent = (struct dirent *)buffer; 1625 while (true) { 1626 uint32 num = 1; 1627 status = dir_read(parent, cookie, dirent, sizeof(buffer), &num); 1628 if (status < B_OK) 1629 break; 1630 1631 if (vnode->id == dirent->d_ino) { 1632 // found correct entry! 1633 if (strlcpy(name, dirent->d_name, nameSize) >= nameSize) 1634 status = B_BUFFER_OVERFLOW; 1635 break; 1636 } 1637 } 1638 FS_CALL(vnode, close_dir)(vnode->mount->cookie, vnode->private_node, cookie); 1639 } 1640 return status; 1641 } 1642 1643 1644 /** Gets the full path to a given directory vnode. 1645 * It uses the fs_get_vnode_name() call to get the name of a vnode; if a 1646 * file system doesn't support this call, it will fall back to iterating 1647 * through the parent directory to get the name of the child. 1648 * 1649 * To protect against circular loops, it supports a maximum tree depth 1650 * of 256 levels. 1651 * 1652 * Note that the path may not be correct the time this function returns! 1653 * It doesn't use any locking to prevent returning the correct path, as 1654 * paths aren't safe anyway: the path to a file can change at any time. 1655 * 1656 * It might be a good idea, though, to check if the returned path exists 1657 * in the calling function (it's not done here because of efficiency) 1658 */ 1659 1660 static status_t 1661 dir_vnode_to_path(struct vnode *vnode, char *buffer, size_t bufferSize) 1662 { 1663 FUNCTION(("dir_vnode_to_path(%p, %p, %lu)\n", vnode, buffer, bufferSize)); 1664 1665 /* this implementation is currently bound to B_PATH_NAME_LENGTH */ 1666 char path[B_PATH_NAME_LENGTH]; 1667 int32 insert = sizeof(path); 1668 int32 maxLevel = 256; 1669 int32 length; 1670 status_t status; 1671 1672 if (vnode == NULL || buffer == NULL) 1673 return EINVAL; 1674 1675 // we don't use get_vnode() here because this call is more 1676 // efficient and does all we need from get_vnode() 1677 inc_vnode_ref_count(vnode); 1678 1679 // resolve a volume root to its mount point 1680 struct vnode *mountPoint = resolve_volume_root_to_mount_point(vnode); 1681 if (mountPoint) { 1682 put_vnode(vnode); 1683 vnode = mountPoint; 1684 } 1685 1686 path[--insert] = '\0'; 1687 1688 while (true) { 1689 // the name buffer is also used for fs_read_dir() 1690 char nameBuffer[sizeof(struct dirent) + B_FILE_NAME_LENGTH]; 1691 char *name = &((struct dirent *)nameBuffer)->d_name[0]; 1692 struct vnode *parentVnode; 1693 vnode_id parentID, id; 1694 int type; 1695 1696 // lookup the parent vnode 1697 status = FS_CALL(vnode, lookup)(vnode->mount->cookie, vnode->private_node, "..", &parentID, &type); 1698 if (status < B_OK) 1699 goto out; 1700 1701 mutex_lock(&sVnodeMutex); 1702 parentVnode = lookup_vnode(vnode->device, parentID); 1703 mutex_unlock(&sVnodeMutex); 1704 1705 if (parentVnode == NULL) { 1706 panic("dir_vnode_to_path: could not lookup vnode (mountid 0x%lx vnid 0x%Lx)\n", vnode->device, parentID); 1707 status = B_ENTRY_NOT_FOUND; 1708 goto out; 1709 } 1710 1711 // resolve a volume root to its mount point 1712 mountPoint = resolve_volume_root_to_mount_point(parentVnode); 1713 if (mountPoint) { 1714 put_vnode(parentVnode); 1715 parentVnode = mountPoint; 1716 parentID = parentVnode->id; 1717 } 1718 1719 bool hitRoot = (parentVnode == vnode); 1720 1721 // Does the file system support getting the name of a vnode? 1722 // If so, get it here... 1723 if (status == B_OK && FS_CALL(vnode, get_vnode_name)) 1724 status = FS_CALL(vnode, get_vnode_name)(vnode->mount->cookie, vnode->private_node, name, B_FILE_NAME_LENGTH); 1725 1726 // ... if not, find it out later (by iterating through 1727 // the parent directory, searching for the id) 1728 id = vnode->id; 1729 1730 // release the current vnode, we only need its parent from now on 1731 put_vnode(vnode); 1732 vnode = parentVnode; 1733 1734 if (status < B_OK) 1735 goto out; 1736 1737 // ToDo: add an explicit check for loops in about 10 levels to do 1738 // real loop detection 1739 1740 // don't go deeper as 'maxLevel' to prevent circular loops 1741 if (maxLevel-- < 0) { 1742 status = ELOOP; 1743 goto out; 1744 } 1745 1746 if (hitRoot) { 1747 // we have reached "/", which means we have constructed the full 1748 // path 1749 break; 1750 } 1751 1752 if (!FS_CALL(vnode, get_vnode_name)) { 1753 // If we haven't got the vnode's name yet, we have to search for it 1754 // in the parent directory now 1755 fs_cookie cookie; 1756 1757 status = FS_CALL(vnode, open_dir)(vnode->mount->cookie, vnode->private_node, &cookie); 1758 if (status >= B_OK) { 1759 struct dirent *dirent = (struct dirent *)nameBuffer; 1760 while (true) { 1761 uint32 num = 1; 1762 status = dir_read(vnode, cookie, dirent, sizeof(nameBuffer), 1763 &num); 1764 1765 if (status < B_OK) 1766 break; 1767 1768 if (id == dirent->d_ino) 1769 // found correct entry! 1770 break; 1771 } 1772 FS_CALL(vnode, close_dir)(vnode->mount->cookie, vnode->private_node, cookie); 1773 } 1774 1775 if (status < B_OK) 1776 goto out; 1777 } 1778 1779 // add the name infront of the current path 1780 name[B_FILE_NAME_LENGTH - 1] = '\0'; 1781 length = strlen(name); 1782 insert -= length; 1783 if (insert <= 0) { 1784 status = ENOBUFS; 1785 goto out; 1786 } 1787 memcpy(path + insert, name, length); 1788 path[--insert] = '/'; 1789 } 1790 1791 // the root dir will result in an empty path: fix it 1792 if (path[insert] == '\0') 1793 path[--insert] = '/'; 1794 1795 PRINT((" path is: %s\n", path + insert)); 1796 1797 // copy the path to the output buffer 1798 length = sizeof(path) - insert; 1799 if (length <= (int)bufferSize) 1800 memcpy(buffer, path + insert, length); 1801 else 1802 status = ENOBUFS; 1803 1804 out: 1805 put_vnode(vnode); 1806 return status; 1807 } 1808 1809 1810 /** Checks the length of every path component, and adds a '.' 1811 * if the path ends in a slash. 1812 * The given path buffer must be able to store at least one 1813 * additional character. 1814 */ 1815 1816 static status_t 1817 check_path(char *to) 1818 { 1819 int32 length = 0; 1820 1821 // check length of every path component 1822 1823 while (*to) { 1824 char *begin; 1825 if (*to == '/') 1826 to++, length++; 1827 1828 begin = to; 1829 while (*to != '/' && *to) 1830 to++, length++; 1831 1832 if (to - begin > B_FILE_NAME_LENGTH) 1833 return B_NAME_TOO_LONG; 1834 } 1835 1836 if (length == 0) 1837 return B_ENTRY_NOT_FOUND; 1838 1839 // complete path if there is a slash at the end 1840 1841 if (*(to - 1) == '/') { 1842 if (length > B_PATH_NAME_LENGTH - 2) 1843 return B_NAME_TOO_LONG; 1844 1845 to[0] = '.'; 1846 to[1] = '\0'; 1847 } 1848 1849 return B_OK; 1850 } 1851 1852 1853 static struct file_descriptor * 1854 get_fd_and_vnode(int fd, struct vnode **_vnode, bool kernel) 1855 { 1856 struct file_descriptor *descriptor = get_fd(get_current_io_context(kernel), fd); 1857 if (descriptor == NULL) 1858 return NULL; 1859 1860 if (descriptor->u.vnode == NULL) { 1861 put_fd(descriptor); 1862 return NULL; 1863 } 1864 1865 // ToDo: when we can close a file descriptor at any point, investigate 1866 // if this is still valid to do (accessing the vnode without ref_count 1867 // or locking) 1868 *_vnode = descriptor->u.vnode; 1869 return descriptor; 1870 } 1871 1872 1873 static struct vnode * 1874 get_vnode_from_fd(int fd, bool kernel) 1875 { 1876 struct file_descriptor *descriptor; 1877 struct vnode *vnode; 1878 1879 descriptor = get_fd(get_current_io_context(kernel), fd); 1880 if (descriptor == NULL) 1881 return NULL; 1882 1883 vnode = descriptor->u.vnode; 1884 if (vnode != NULL) 1885 inc_vnode_ref_count(vnode); 1886 1887 put_fd(descriptor); 1888 return vnode; 1889 } 1890 1891 1892 /** Gets the vnode from an FD + path combination. If \a fd is lower than zero, 1893 * only the path will be considered. In this case, the \a path must not be 1894 * NULL. 1895 * If \a fd is a valid file descriptor, \a path may be NULL for directories, 1896 * and should be NULL for files. 1897 */ 1898 1899 static status_t 1900 fd_and_path_to_vnode(int fd, char *path, bool traverseLeafLink, 1901 struct vnode **_vnode, vnode_id *_parentID, bool kernel) 1902 { 1903 if (fd < 0 && !path) 1904 return B_BAD_VALUE; 1905 1906 if (fd < 0 || (path != NULL && path[0] == '/')) { 1907 // no FD or absolute path 1908 return path_to_vnode(path, traverseLeafLink, _vnode, _parentID, kernel); 1909 } 1910 1911 // FD only, or FD + relative path 1912 struct vnode *vnode = get_vnode_from_fd(fd, kernel); 1913 if (!vnode) 1914 return B_FILE_ERROR; 1915 1916 if (path != NULL) { 1917 return vnode_path_to_vnode(vnode, path, traverseLeafLink, 0, 1918 _vnode, _parentID, NULL); 1919 } 1920 1921 // there is no relative path to take into account 1922 1923 *_vnode = vnode; 1924 if (_parentID) 1925 *_parentID = -1; 1926 1927 return B_OK; 1928 } 1929 1930 1931 static int 1932 get_new_fd(int type, struct fs_mount *mount, struct vnode *vnode, 1933 fs_cookie cookie, int openMode, bool kernel) 1934 { 1935 struct file_descriptor *descriptor; 1936 int fd; 1937 1938 descriptor = alloc_fd(); 1939 if (!descriptor) 1940 return B_NO_MEMORY; 1941 1942 if (vnode) 1943 descriptor->u.vnode = vnode; 1944 else 1945 descriptor->u.mount = mount; 1946 descriptor->cookie = cookie; 1947 1948 switch (type) { 1949 case FDTYPE_FILE: 1950 descriptor->ops = &sFileOps; 1951 break; 1952 case FDTYPE_DIR: 1953 descriptor->ops = &sDirectoryOps; 1954 break; 1955 case FDTYPE_ATTR: 1956 descriptor->ops = &sAttributeOps; 1957 break; 1958 case FDTYPE_ATTR_DIR: 1959 descriptor->ops = &sAttributeDirectoryOps; 1960 break; 1961 case FDTYPE_INDEX_DIR: 1962 descriptor->ops = &sIndexDirectoryOps; 1963 break; 1964 case FDTYPE_QUERY: 1965 descriptor->ops = &sQueryOps; 1966 break; 1967 default: 1968 panic("get_new_fd() called with unknown type %d\n", type); 1969 break; 1970 } 1971 descriptor->type = type; 1972 descriptor->open_mode = openMode; 1973 1974 fd = new_fd(get_current_io_context(kernel), descriptor); 1975 if (fd < 0) { 1976 free(descriptor); 1977 return B_NO_MORE_FDS; 1978 } 1979 1980 return fd; 1981 } 1982 1983 #ifdef ADD_DEBUGGER_COMMANDS 1984 1985 1986 static void 1987 _dump_advisory_locking(advisory_locking *locking) 1988 { 1989 if (locking == NULL) 1990 return; 1991 1992 kprintf(" lock: %ld", locking->lock); 1993 kprintf(" wait_sem: %ld", locking->wait_sem); 1994 1995 struct advisory_lock *lock = NULL; 1996 int32 index = 0; 1997 while ((lock = (advisory_lock *)list_get_next_item(&locking->locks, lock)) != NULL) { 1998 kprintf(" [%2ld] team: %ld\n", index, lock->team); 1999 kprintf(" offset: %Ld\n", lock->offset); 2000 kprintf(" length: %Ld\n", lock->length); 2001 kprintf(" shared? %s\n", lock->shared ? "yes" : "no"); 2002 } 2003 } 2004 2005 2006 static void 2007 _dump_mount(struct fs_mount *mount) 2008 { 2009 kprintf("MOUNT: %p\n", mount); 2010 kprintf(" id: %ld\n", mount->id); 2011 kprintf(" device_name: %s\n", mount->device_name); 2012 kprintf(" fs_name: %s\n", mount->fs_name); 2013 kprintf(" cookie: %p\n", mount->cookie); 2014 kprintf(" root_vnode: %p\n", mount->root_vnode); 2015 kprintf(" covers_vnode: %p\n", mount->covers_vnode); 2016 kprintf(" partition: %p\n", mount->partition); 2017 kprintf(" lock: %ld\n", mount->rlock.sem); 2018 kprintf(" flags: %s%s\n", mount->unmounting ? " unmounting" : "", 2019 mount->owns_file_device ? " owns_file_device" : ""); 2020 } 2021 2022 2023 static void 2024 _dump_vnode(struct vnode *vnode) 2025 { 2026 kprintf("VNODE: %p\n", vnode); 2027 kprintf(" device: %ld\n", vnode->device); 2028 kprintf(" id: %Ld\n", vnode->id); 2029 kprintf(" ref_count: %ld\n", vnode->ref_count); 2030 kprintf(" private_node: %p\n", vnode->private_node); 2031 kprintf(" mount: %p\n", vnode->mount); 2032 kprintf(" covered_by: %p\n", vnode->covered_by); 2033 kprintf(" cache_ref: %p\n", vnode->cache); 2034 kprintf(" flags: %s%s%s\n", vnode->remove ? "r" : "-", 2035 vnode->busy ? "b" : "-", vnode->unpublished ? "u" : "-"); 2036 kprintf(" advisory_lock: %p\n", vnode->advisory_locking); 2037 2038 _dump_advisory_locking(vnode->advisory_locking); 2039 } 2040 2041 2042 static int 2043 dump_mount(int argc, char **argv) 2044 { 2045 if (argc != 2) { 2046 kprintf("usage: mount [id/address]\n"); 2047 return 0; 2048 } 2049 2050 struct fs_mount *mount = NULL; 2051 2052 // if the argument looks like a hex number, treat it as such 2053 if (strlen(argv[1]) > 2 && argv[1][0] == '0' && argv[1][1] == 'x') { 2054 mount = (fs_mount *)strtoul(argv[1], NULL, 16); 2055 if (IS_USER_ADDRESS(mount)) { 2056 kprintf("invalid fs_mount address\n"); 2057 return 0; 2058 } 2059 } else { 2060 mount_id id = atoll(argv[1]); 2061 mount = (fs_mount *)hash_lookup(sMountsTable, (void *)&id); 2062 if (mount == NULL) { 2063 kprintf("fs_mount not found\n"); 2064 return 0; 2065 } 2066 } 2067 2068 _dump_mount(mount); 2069 return 0; 2070 } 2071 2072 2073 static int 2074 dump_mounts(int argc, char **argv) 2075 { 2076 struct hash_iterator iterator; 2077 struct fs_mount *mount; 2078 2079 kprintf("address id root covers fs_name\n"); 2080 2081 hash_open(sMountsTable, &iterator); 2082 while ((mount = (struct fs_mount *)hash_next(sMountsTable, &iterator)) != NULL) { 2083 kprintf("%p%4ld %p %p %s\n", mount, mount->id, mount->root_vnode, 2084 mount->covers_vnode, mount->fs_name); 2085 } 2086 2087 hash_close(sMountsTable, &iterator, false); 2088 return 0; 2089 } 2090 2091 2092 static int 2093 dump_vnode(int argc, char **argv) 2094 { 2095 if (argc < 2) { 2096 kprintf("usage: vnode [id/device id/address]\n"); 2097 return 0; 2098 } 2099 2100 struct vnode *vnode = NULL; 2101 2102 // if the argument looks like a hex number, treat it as such 2103 if (strlen(argv[1]) > 2 && argv[1][0] == '0' && argv[1][1] == 'x') { 2104 vnode = (struct vnode *)strtoul(argv[1], NULL, 16); 2105 if (IS_USER_ADDRESS(vnode)) { 2106 kprintf("invalid vnode address\n"); 2107 return 0; 2108 } 2109 _dump_vnode(vnode); 2110 return 0; 2111 } 2112 2113 struct hash_iterator iterator; 2114 mount_id device = -1; 2115 vnode_id id; 2116 if (argc > 2) { 2117 device = atoi(argv[1]); 2118 id = atoll(argv[2]); 2119 } else 2120 id = atoll(argv[1]); 2121 2122 hash_open(sVnodeTable, &iterator); 2123 while ((vnode = (struct vnode *)hash_next(sVnodeTable, &iterator)) != NULL) { 2124 if (vnode->id != id || device != -1 && vnode->device != device) 2125 continue; 2126 2127 _dump_vnode(vnode); 2128 } 2129 2130 hash_close(sVnodeTable, &iterator, false); 2131 return 0; 2132 } 2133 2134 2135 static int 2136 dump_vnodes(int argc, char **argv) 2137 { 2138 // restrict dumped nodes to a certain device if requested 2139 mount_id device = -1; 2140 if (argc > 1) 2141 device = atoi(argv[1]); 2142 2143 struct hash_iterator iterator; 2144 struct vnode *vnode; 2145 2146 kprintf("address dev inode ref cache locking flags\n"); 2147 2148 hash_open(sVnodeTable, &iterator); 2149 while ((vnode = (struct vnode *)hash_next(sVnodeTable, &iterator)) != NULL) { 2150 if (device != -1 && vnode->device != device) 2151 continue; 2152 2153 kprintf("%p%4ld%10Ld%5ld %p %p %s%s%s\n", vnode, vnode->device, vnode->id, 2154 vnode->ref_count, vnode->cache, vnode->advisory_locking, 2155 vnode->remove ? "r" : "-", vnode->busy ? "b" : "-", 2156 vnode->unpublished ? "u" : "-"); 2157 } 2158 2159 hash_close(sVnodeTable, &iterator, false); 2160 return 0; 2161 } 2162 2163 2164 static int 2165 dump_vnode_caches(int argc, char **argv) 2166 { 2167 struct hash_iterator iterator; 2168 struct vnode *vnode; 2169 2170 kprintf("address dev inode cache size pages\n"); 2171 2172 hash_open(sVnodeTable, &iterator); 2173 while ((vnode = (struct vnode *)hash_next(sVnodeTable, &iterator)) != NULL) { 2174 if (vnode->cache == NULL) 2175 continue; 2176 2177 // count pages in cache 2178 size_t numPages = 0; 2179 for (struct vm_page *page = vnode->cache->cache->page_list; 2180 page != NULL; page = page->cache_next) { 2181 numPages++; 2182 } 2183 2184 kprintf("%p%4ld%10Ld %p %8Ld%8ld\n", vnode, vnode->device, vnode->id, vnode->cache, 2185 (vnode->cache->cache->virtual_size + B_PAGE_SIZE - 1) / B_PAGE_SIZE, numPages); 2186 } 2187 2188 hash_close(sVnodeTable, &iterator, false); 2189 return 0; 2190 } 2191 2192 #endif // ADD_DEBUGGER_COMMANDS 2193 2194 2195 // #pragma mark - 2196 // Public VFS API 2197 2198 2199 extern "C" status_t 2200 new_vnode(mount_id mountID, vnode_id vnodeID, fs_vnode privateNode) 2201 { 2202 FUNCTION(("new_vnode(mountID = %ld, vnodeID = %Ld, node = %p)\n", 2203 mountID, vnodeID, privateNode)); 2204 2205 if (privateNode == NULL) 2206 return B_BAD_VALUE; 2207 2208 mutex_lock(&sVnodeMutex); 2209 2210 // file system integrity check: 2211 // test if the vnode already exists and bail out if this is the case! 2212 2213 // ToDo: the R5 implementation obviously checks for a different cookie 2214 // and doesn't panic if they are equal 2215 2216 struct vnode *vnode = lookup_vnode(mountID, vnodeID); 2217 if (vnode != NULL) 2218 panic("vnode %ld:%Ld already exists (node = %p, vnode->node = %p)!", mountID, vnodeID, privateNode, vnode->private_node); 2219 2220 status_t status = create_new_vnode(&vnode, mountID, vnodeID); 2221 if (status == B_OK) { 2222 vnode->private_node = privateNode; 2223 vnode->busy = true; 2224 vnode->unpublished = true; 2225 } 2226 2227 PRINT(("returns: %s\n", strerror(status))); 2228 2229 mutex_unlock(&sVnodeMutex); 2230 return status; 2231 } 2232 2233 2234 extern "C" status_t 2235 publish_vnode(mount_id mountID, vnode_id vnodeID, fs_vnode privateNode) 2236 { 2237 FUNCTION(("publish_vnode()\n")); 2238 2239 mutex_lock(&sVnodeMutex); 2240 2241 struct vnode *vnode = lookup_vnode(mountID, vnodeID); 2242 status_t status = B_OK; 2243 2244 if (vnode != NULL && vnode->busy && vnode->unpublished 2245 && vnode->private_node == privateNode) { 2246 vnode->busy = false; 2247 vnode->unpublished = false; 2248 } else if (vnode == NULL && privateNode != NULL) { 2249 status = create_new_vnode(&vnode, mountID, vnodeID); 2250 if (status == B_OK) 2251 vnode->private_node = privateNode; 2252 } else 2253 status = B_BAD_VALUE; 2254 2255 PRINT(("returns: %s\n", strerror(status))); 2256 2257 mutex_unlock(&sVnodeMutex); 2258 return status; 2259 } 2260 2261 2262 extern "C" status_t 2263 get_vnode(mount_id mountID, vnode_id vnodeID, fs_vnode *_fsNode) 2264 { 2265 struct vnode *vnode; 2266 2267 status_t status = get_vnode(mountID, vnodeID, &vnode, true); 2268 if (status < B_OK) 2269 return status; 2270 2271 *_fsNode = vnode->private_node; 2272 return B_OK; 2273 } 2274 2275 2276 extern "C" status_t 2277 put_vnode(mount_id mountID, vnode_id vnodeID) 2278 { 2279 struct vnode *vnode; 2280 2281 mutex_lock(&sVnodeMutex); 2282 vnode = lookup_vnode(mountID, vnodeID); 2283 mutex_unlock(&sVnodeMutex); 2284 2285 if (vnode) 2286 dec_vnode_ref_count(vnode, true); 2287 2288 return B_OK; 2289 } 2290 2291 2292 extern "C" status_t 2293 remove_vnode(mount_id mountID, vnode_id vnodeID) 2294 { 2295 struct vnode *vnode; 2296 bool remove = false; 2297 2298 mutex_lock(&sVnodeMutex); 2299 2300 vnode = lookup_vnode(mountID, vnodeID); 2301 if (vnode != NULL) { 2302 vnode->remove = true; 2303 if (vnode->unpublished) { 2304 // prepare the vnode for deletion 2305 vnode->busy = true; 2306 remove = true; 2307 } 2308 } 2309 2310 mutex_unlock(&sVnodeMutex); 2311 2312 if (remove) { 2313 // if the vnode hasn't been published yet, we delete it here 2314 atomic_add(&vnode->ref_count, -1); 2315 free_vnode(vnode, true); 2316 } 2317 2318 return B_OK; 2319 } 2320 2321 2322 extern "C" status_t 2323 unremove_vnode(mount_id mountID, vnode_id vnodeID) 2324 { 2325 struct vnode *vnode; 2326 2327 mutex_lock(&sVnodeMutex); 2328 2329 vnode = lookup_vnode(mountID, vnodeID); 2330 if (vnode) 2331 vnode->remove = false; 2332 2333 mutex_unlock(&sVnodeMutex); 2334 return B_OK; 2335 } 2336 2337 2338 // #pragma mark - 2339 // Functions the VFS exports for other parts of the kernel 2340 2341 2342 /** Acquires another reference to the vnode that has to be released 2343 * by calling vfs_put_vnode(). 2344 */ 2345 2346 void 2347 vfs_acquire_vnode(void *_vnode) 2348 { 2349 inc_vnode_ref_count((struct vnode *)_vnode); 2350 } 2351 2352 2353 /** This is currently called from file_cache_create() only. 2354 * It's probably a temporary solution as long as devfs requires that 2355 * fs_read_pages()/fs_write_pages() are called with the standard 2356 * open cookie and not with a device cookie. 2357 * If that's done differently, remove this call; it has no other 2358 * purpose. 2359 */ 2360 2361 extern "C" status_t 2362 vfs_get_cookie_from_fd(int fd, void **_cookie) 2363 { 2364 struct file_descriptor *descriptor; 2365 2366 descriptor = get_fd(get_current_io_context(true), fd); 2367 if (descriptor == NULL) 2368 return B_FILE_ERROR; 2369 2370 *_cookie = descriptor->cookie; 2371 return B_OK; 2372 } 2373 2374 2375 extern "C" int 2376 vfs_get_vnode_from_fd(int fd, bool kernel, void **vnode) 2377 { 2378 *vnode = get_vnode_from_fd(fd, kernel); 2379 2380 if (*vnode == NULL) 2381 return B_FILE_ERROR; 2382 2383 return B_NO_ERROR; 2384 } 2385 2386 2387 extern "C" status_t 2388 vfs_get_vnode_from_path(const char *path, bool kernel, void **_vnode) 2389 { 2390 struct vnode *vnode; 2391 status_t status; 2392 char buffer[B_PATH_NAME_LENGTH + 1]; 2393 2394 PRINT(("vfs_get_vnode_from_path: entry. path = '%s', kernel %d\n", path, kernel)); 2395 2396 strlcpy(buffer, path, sizeof(buffer)); 2397 2398 status = path_to_vnode(buffer, true, &vnode, NULL, kernel); 2399 if (status < B_OK) 2400 return status; 2401 2402 *_vnode = vnode; 2403 return B_OK; 2404 } 2405 2406 2407 extern "C" status_t 2408 vfs_get_vnode(mount_id mountID, vnode_id vnodeID, void **_vnode) 2409 { 2410 struct vnode *vnode; 2411 2412 status_t status = get_vnode(mountID, vnodeID, &vnode, false); 2413 if (status < B_OK) 2414 return status; 2415 2416 *_vnode = vnode; 2417 return B_OK; 2418 } 2419 2420 2421 extern "C" status_t 2422 vfs_lookup_vnode(mount_id mountID, vnode_id vnodeID, void **_vnode) 2423 { 2424 // ToDo: this currently doesn't use the sVnodeMutex lock - that's 2425 // because it's only called from file_cache_create() with that 2426 // lock held anyway (as it should be called from fs_read_vnode()). 2427 // Find a better solution! 2428 struct vnode *vnode = lookup_vnode(mountID, vnodeID); 2429 if (vnode == NULL) 2430 return B_ERROR; 2431 2432 *_vnode = vnode; 2433 return B_OK; 2434 //return get_vnode(mountID, vnodeID, (struct vnode **)_vnode, true); 2435 } 2436 2437 2438 extern "C" status_t 2439 vfs_get_fs_node_from_path(mount_id mountID, const char *path, bool kernel, void **_node) 2440 { 2441 char buffer[B_PATH_NAME_LENGTH + 1]; 2442 struct vnode *vnode; 2443 status_t status; 2444 2445 PRINT(("vfs_get_fs_node_from_path(mountID = %ld, path = \"%s\", kernel %d)\n", mountID, path, kernel)); 2446 2447 strlcpy(buffer, path, sizeof(buffer)); 2448 status = path_to_vnode(buffer, true, &vnode, NULL, kernel); 2449 if (status < B_OK) 2450 return status; 2451 2452 if (vnode->device != mountID) { 2453 // wrong mount ID - must not gain access on foreign file system nodes 2454 put_vnode(vnode); 2455 return B_BAD_VALUE; 2456 } 2457 2458 *_node = vnode->private_node; 2459 return B_OK; 2460 } 2461 2462 2463 /** Finds the full path to the file that contains the module \a moduleName, 2464 * puts it into \a pathBuffer, and returns B_OK for success. 2465 * If \a pathBuffer was too small, it returns \c B_BUFFER_OVERFLOW, 2466 * \c B_ENTRY_NOT_FOUNT if no file could be found. 2467 * \a pathBuffer is clobbered in any case and must not be relied on if this 2468 * functions returns unsuccessfully. 2469 */ 2470 2471 status_t 2472 vfs_get_module_path(const char *basePath, const char *moduleName, char *pathBuffer, 2473 size_t bufferSize) 2474 { 2475 struct vnode *dir, *file; 2476 status_t status; 2477 size_t length; 2478 char *path; 2479 2480 if (bufferSize == 0 || strlcpy(pathBuffer, basePath, bufferSize) >= bufferSize) 2481 return B_BUFFER_OVERFLOW; 2482 2483 status = path_to_vnode(pathBuffer, true, &dir, NULL, true); 2484 if (status < B_OK) 2485 return status; 2486 2487 // the path buffer had been clobbered by the above call 2488 length = strlcpy(pathBuffer, basePath, bufferSize); 2489 if (pathBuffer[length - 1] != '/') 2490 pathBuffer[length++] = '/'; 2491 2492 path = pathBuffer + length; 2493 bufferSize -= length; 2494 2495 while (moduleName) { 2496 int type; 2497 2498 char *nextPath = strchr(moduleName, '/'); 2499 if (nextPath == NULL) 2500 length = strlen(moduleName); 2501 else { 2502 length = nextPath - moduleName; 2503 nextPath++; 2504 } 2505 2506 if (length + 1 >= bufferSize) { 2507 status = B_BUFFER_OVERFLOW; 2508 goto err; 2509 } 2510 2511 memcpy(path, moduleName, length); 2512 path[length] = '\0'; 2513 moduleName = nextPath; 2514 2515 status = vnode_path_to_vnode(dir, path, true, 0, &file, NULL, &type); 2516 if (status < B_OK) 2517 goto err; 2518 2519 put_vnode(dir); 2520 2521 if (S_ISDIR(type)) { 2522 // goto the next directory 2523 path[length] = '/'; 2524 path[length + 1] = '\0'; 2525 path += length + 1; 2526 bufferSize -= length + 1; 2527 2528 dir = file; 2529 } else if (S_ISREG(type)) { 2530 // it's a file so it should be what we've searched for 2531 put_vnode(file); 2532 2533 return B_OK; 2534 } else { 2535 PRINT(("vfs_get_module_path(): something is strange here: %d...\n", type)); 2536 status = B_ERROR; 2537 goto err; 2538 } 2539 } 2540 2541 // if we got here, the moduleName just pointed to a directory, not to 2542 // a real module - what should we do in this case? 2543 status = B_ENTRY_NOT_FOUND; 2544 2545 err: 2546 put_vnode(dir); 2547 return status; 2548 } 2549 2550 2551 /** \brief Normalizes a given path. 2552 * 2553 * The path must refer to an existing or non-existing entry in an existing 2554 * directory, that is chopping off the leaf component the remaining path must 2555 * refer to an existing directory. 2556 * 2557 * The returned will be canonical in that it will be absolute, will not 2558 * contain any "." or ".." components or duplicate occurrences of '/'s, 2559 * and none of the directory components will by symbolic links. 2560 * 2561 * Any two paths referring to the same entry, will result in the same 2562 * normalized path (well, that is pretty much the definition of `normalized', 2563 * isn't it :-). 2564 * 2565 * \param path The path to be normalized. 2566 * \param buffer The buffer into which the normalized path will be written. 2567 * \param bufferSize The size of \a buffer. 2568 * \param kernel \c true, if the IO context of the kernel shall be used, 2569 * otherwise that of the team this thread belongs to. Only relevant, 2570 * if the path is relative (to get the CWD). 2571 * \return \c B_OK if everything went fine, another error code otherwise. 2572 */ 2573 2574 status_t 2575 vfs_normalize_path(const char *path, char *buffer, size_t bufferSize, 2576 bool kernel) 2577 { 2578 if (!path || !buffer || bufferSize < 1) 2579 return B_BAD_VALUE; 2580 2581 PRINT(("vfs_normalize_path(`%s')\n", path)); 2582 2583 // copy the supplied path to the stack, so it can be modified 2584 char mutablePath[B_PATH_NAME_LENGTH + 1]; 2585 if (strlcpy(mutablePath, path, B_PATH_NAME_LENGTH) >= B_PATH_NAME_LENGTH) 2586 return B_NAME_TOO_LONG; 2587 2588 // get the dir vnode and the leaf name 2589 struct vnode *dirNode; 2590 char leaf[B_FILE_NAME_LENGTH]; 2591 status_t error = path_to_dir_vnode(mutablePath, &dirNode, leaf, kernel); 2592 if (error != B_OK) { 2593 PRINT(("vfs_normalize_path(): failed to get dir vnode: %s\n", strerror(error))); 2594 return error; 2595 } 2596 2597 // if the leaf is "." or "..", we directly get the correct directory 2598 // vnode and ignore the leaf later 2599 bool isDir = (strcmp(leaf, ".") == 0 || strcmp(leaf, "..") == 0); 2600 if (isDir) 2601 error = vnode_path_to_vnode(dirNode, leaf, false, 0, &dirNode, NULL, NULL); 2602 if (error != B_OK) { 2603 PRINT(("vfs_normalize_path(): failed to get dir vnode for \".\" or \"..\": %s\n", strerror(error))); 2604 return error; 2605 } 2606 2607 // get the directory path 2608 error = dir_vnode_to_path(dirNode, buffer, bufferSize); 2609 put_vnode(dirNode); 2610 if (error < B_OK) { 2611 PRINT(("vfs_normalize_path(): failed to get dir path: %s\n", strerror(error))); 2612 return error; 2613 } 2614 2615 // append the leaf name 2616 if (!isDir) { 2617 // insert a directory separator only if this is not the file system root 2618 if ((strcmp(buffer, "/") != 0 2619 && strlcat(buffer, "/", bufferSize) >= bufferSize) 2620 || strlcat(buffer, leaf, bufferSize) >= bufferSize) { 2621 return B_NAME_TOO_LONG; 2622 } 2623 } 2624 2625 PRINT(("vfs_normalize_path() -> `%s'\n", buffer)); 2626 return B_OK; 2627 } 2628 2629 2630 extern "C" void 2631 vfs_put_vnode(void *_vnode) 2632 { 2633 put_vnode((struct vnode *)_vnode); 2634 } 2635 2636 2637 extern "C" status_t 2638 vfs_get_cwd(mount_id *_mountID, vnode_id *_vnodeID) 2639 { 2640 // Get current working directory from io context 2641 struct io_context *context = get_current_io_context(false); 2642 status_t status = B_OK; 2643 2644 mutex_lock(&context->io_mutex); 2645 2646 if (context->cwd != NULL) { 2647 *_mountID = context->cwd->device; 2648 *_vnodeID = context->cwd->id; 2649 } else 2650 status = B_ERROR; 2651 2652 mutex_unlock(&context->io_mutex); 2653 return status; 2654 } 2655 2656 2657 extern "C" bool 2658 vfs_can_page(void *_vnode, void *cookie) 2659 { 2660 struct vnode *vnode = (struct vnode *)_vnode; 2661 2662 FUNCTION(("vfs_canpage: vnode 0x%p\n", vnode)); 2663 2664 if (FS_CALL(vnode, can_page)) 2665 return FS_CALL(vnode, can_page)(vnode->mount->cookie, vnode->private_node, cookie); 2666 2667 return false; 2668 } 2669 2670 2671 extern "C" status_t 2672 vfs_read_pages(void *_vnode, void *cookie, off_t pos, const iovec *vecs, size_t count, size_t *_numBytes) 2673 { 2674 struct vnode *vnode = (struct vnode *)_vnode; 2675 2676 FUNCTION(("vfs_read_pages: vnode %p, vecs %p, pos %Ld\n", vnode, vecs, pos)); 2677 2678 return FS_CALL(vnode, read_pages)(vnode->mount->cookie, vnode->private_node, cookie, pos, vecs, count, _numBytes); 2679 } 2680 2681 2682 extern "C" status_t 2683 vfs_write_pages(void *_vnode, void *cookie, off_t pos, const iovec *vecs, size_t count, size_t *_numBytes) 2684 { 2685 struct vnode *vnode = (struct vnode *)_vnode; 2686 2687 FUNCTION(("vfs_write_pages: vnode %p, vecs %p, pos %Ld\n", vnode, vecs, pos)); 2688 2689 return FS_CALL(vnode, write_pages)(vnode->mount->cookie, vnode->private_node, cookie, pos, vecs, count, _numBytes); 2690 } 2691 2692 2693 extern "C" status_t 2694 vfs_get_vnode_cache(void *_vnode, vm_cache_ref **_cache, bool allocate) 2695 { 2696 struct vnode *vnode = (struct vnode *)_vnode; 2697 2698 if (vnode->cache != NULL) { 2699 *_cache = vnode->cache; 2700 return B_OK; 2701 } 2702 2703 mutex_lock(&sVnodeMutex); 2704 2705 status_t status = B_OK; 2706 2707 // The cache could have been created in the meantime 2708 if (vnode->cache == NULL) { 2709 if (allocate) 2710 status = vm_create_vnode_cache(vnode, &vnode->cache); 2711 else 2712 status = B_BAD_VALUE; 2713 } 2714 2715 if (status == B_OK) 2716 *_cache = vnode->cache; 2717 2718 mutex_unlock(&sVnodeMutex); 2719 return status; 2720 } 2721 2722 2723 status_t 2724 vfs_get_file_map(void *_vnode, off_t offset, size_t size, file_io_vec *vecs, size_t *_count) 2725 { 2726 struct vnode *vnode = (struct vnode *)_vnode; 2727 2728 FUNCTION(("vfs_get_file_map: vnode %p, vecs %p, offset %Ld, size = %lu\n", vnode, vecs, offset, size)); 2729 2730 return FS_CALL(vnode, get_file_map)(vnode->mount->cookie, vnode->private_node, offset, size, vecs, _count); 2731 } 2732 2733 2734 status_t 2735 vfs_stat_vnode(void *_vnode, struct stat *stat) 2736 { 2737 struct vnode *vnode = (struct vnode *)_vnode; 2738 2739 status_t status = FS_CALL(vnode, read_stat)(vnode->mount->cookie, 2740 vnode->private_node, stat); 2741 2742 // fill in the st_dev and st_ino fields 2743 if (status == B_OK) { 2744 stat->st_dev = vnode->device; 2745 stat->st_ino = vnode->id; 2746 } 2747 2748 return status; 2749 } 2750 2751 2752 status_t 2753 vfs_get_vnode_name(void *_vnode, char *name, size_t nameSize) 2754 { 2755 return get_vnode_name((struct vnode *)_vnode, NULL, name, nameSize); 2756 } 2757 2758 2759 /** Closes all file descriptors of the specified I/O context that 2760 * don't have the O_CLOEXEC flag set. 2761 */ 2762 2763 void 2764 vfs_exec_io_context(void *_context) 2765 { 2766 struct io_context *context = (struct io_context *)_context; 2767 uint32 i; 2768 2769 2770 for (i = 0; i < context->table_size; i++) { 2771 mutex_lock(&context->io_mutex); 2772 2773 struct file_descriptor *descriptor = context->fds[i]; 2774 bool remove = false; 2775 2776 if (descriptor != NULL && (descriptor->open_mode & O_CLOEXEC) != 0) { 2777 context->fds[i] = NULL; 2778 context->num_used_fds--; 2779 2780 remove = true; 2781 } 2782 2783 mutex_unlock(&context->io_mutex); 2784 2785 if (remove) { 2786 close_fd(descriptor); 2787 put_fd(descriptor); 2788 } 2789 } 2790 } 2791 2792 2793 /** Sets up a new io_control structure, and inherits the properties 2794 * of the parent io_control if it is given. 2795 */ 2796 2797 void * 2798 vfs_new_io_context(void *_parentContext) 2799 { 2800 size_t tableSize; 2801 struct io_context *context; 2802 struct io_context *parentContext; 2803 2804 context = (io_context *)malloc(sizeof(struct io_context)); 2805 if (context == NULL) 2806 return NULL; 2807 2808 memset(context, 0, sizeof(struct io_context)); 2809 2810 parentContext = (struct io_context *)_parentContext; 2811 if (parentContext) 2812 tableSize = parentContext->table_size; 2813 else 2814 tableSize = DEFAULT_FD_TABLE_SIZE; 2815 2816 context->fds = (file_descriptor **)malloc(sizeof(struct file_descriptor *) * tableSize); 2817 if (context->fds == NULL) { 2818 free(context); 2819 return NULL; 2820 } 2821 2822 memset(context->fds, 0, sizeof(struct file_descriptor *) * tableSize); 2823 2824 if (mutex_init(&context->io_mutex, "I/O context") < 0) { 2825 free(context->fds); 2826 free(context); 2827 return NULL; 2828 } 2829 2830 // Copy all parent files which don't have the O_CLOEXEC flag set 2831 2832 if (parentContext) { 2833 size_t i; 2834 2835 mutex_lock(&parentContext->io_mutex); 2836 2837 context->cwd = parentContext->cwd; 2838 if (context->cwd) 2839 inc_vnode_ref_count(context->cwd); 2840 2841 for (i = 0; i < tableSize; i++) { 2842 struct file_descriptor *descriptor = parentContext->fds[i]; 2843 2844 if (descriptor != NULL && (descriptor->open_mode & O_CLOEXEC) == 0) { 2845 context->fds[i] = descriptor; 2846 atomic_add(&descriptor->ref_count, 1); 2847 atomic_add(&descriptor->open_count, 1); 2848 } 2849 } 2850 2851 mutex_unlock(&parentContext->io_mutex); 2852 } else { 2853 context->cwd = sRoot; 2854 2855 if (context->cwd) 2856 inc_vnode_ref_count(context->cwd); 2857 } 2858 2859 context->table_size = tableSize; 2860 2861 list_init(&context->node_monitors); 2862 context->max_monitors = MAX_NODE_MONITORS; 2863 2864 return context; 2865 } 2866 2867 2868 status_t 2869 vfs_free_io_context(void *_ioContext) 2870 { 2871 struct io_context *context = (struct io_context *)_ioContext; 2872 uint32 i; 2873 2874 if (context->cwd) 2875 dec_vnode_ref_count(context->cwd, false); 2876 2877 mutex_lock(&context->io_mutex); 2878 2879 for (i = 0; i < context->table_size; i++) { 2880 if (struct file_descriptor *descriptor = context->fds[i]) { 2881 close_fd(descriptor); 2882 put_fd(descriptor); 2883 } 2884 } 2885 2886 mutex_unlock(&context->io_mutex); 2887 2888 mutex_destroy(&context->io_mutex); 2889 2890 remove_node_monitors(context); 2891 free(context->fds); 2892 free(context); 2893 2894 return B_OK; 2895 } 2896 2897 2898 static status_t 2899 vfs_resize_fd_table(struct io_context *context, const int newSize) 2900 { 2901 void *fds; 2902 int status = B_OK; 2903 2904 if (newSize <= 0 || newSize > MAX_FD_TABLE_SIZE) 2905 return EINVAL; 2906 2907 mutex_lock(&context->io_mutex); 2908 2909 if ((size_t)newSize < context->table_size) { 2910 // shrink the fd table 2911 int i; 2912 2913 // Make sure none of the fds being dropped are in use 2914 for(i = context->table_size; i-- > newSize;) { 2915 if (context->fds[i]) { 2916 status = EBUSY; 2917 goto out; 2918 } 2919 } 2920 2921 fds = malloc(sizeof(struct file_descriptor *) * newSize); 2922 if (fds == NULL) { 2923 status = ENOMEM; 2924 goto out; 2925 } 2926 2927 memcpy(fds, context->fds, sizeof(struct file_descriptor *) * newSize); 2928 } else { 2929 // enlarge the fd table 2930 2931 fds = malloc(sizeof(struct file_descriptor *) * newSize); 2932 if (fds == NULL) { 2933 status = ENOMEM; 2934 goto out; 2935 } 2936 2937 // copy the fd array, and zero the additional slots 2938 memcpy(fds, context->fds, sizeof(void *) * context->table_size); 2939 memset((char *)fds + (sizeof(void *) * context->table_size), 0, 2940 sizeof(void *) * (newSize - context->table_size)); 2941 } 2942 2943 free(context->fds); 2944 context->fds = (file_descriptor **)fds; 2945 context->table_size = newSize; 2946 2947 out: 2948 mutex_unlock(&context->io_mutex); 2949 return status; 2950 } 2951 2952 2953 int 2954 vfs_getrlimit(int resource, struct rlimit * rlp) 2955 { 2956 if (!rlp) 2957 return -1; 2958 2959 switch (resource) { 2960 case RLIMIT_NOFILE: 2961 { 2962 struct io_context *ioctx = get_current_io_context(false); 2963 2964 mutex_lock(&ioctx->io_mutex); 2965 2966 rlp->rlim_cur = ioctx->table_size; 2967 rlp->rlim_max = MAX_FD_TABLE_SIZE; 2968 2969 mutex_unlock(&ioctx->io_mutex); 2970 2971 return 0; 2972 } 2973 2974 default: 2975 return -1; 2976 } 2977 } 2978 2979 2980 int 2981 vfs_setrlimit(int resource, const struct rlimit * rlp) 2982 { 2983 if (!rlp) 2984 return -1; 2985 2986 switch (resource) { 2987 case RLIMIT_NOFILE: 2988 return vfs_resize_fd_table(get_current_io_context(false), rlp->rlim_cur); 2989 2990 default: 2991 return -1; 2992 } 2993 } 2994 2995 2996 status_t 2997 vfs_bootstrap_file_systems(void) 2998 { 2999 status_t status; 3000 3001 // bootstrap the root filesystem 3002 status = _kern_mount("/", NULL, "rootfs", 0, NULL); 3003 if (status < B_OK) 3004 panic("error mounting rootfs!\n"); 3005 3006 _kern_setcwd(-1, "/"); 3007 3008 // bootstrap the devfs 3009 _kern_create_dir(-1, "/dev", 0755); 3010 status = _kern_mount("/dev", NULL, "devfs", 0, NULL); 3011 if (status < B_OK) 3012 panic("error mounting devfs\n"); 3013 3014 // bootstrap the pipefs 3015 _kern_create_dir(-1, "/pipe", 0755); 3016 status = _kern_mount("/pipe", NULL, "pipefs", 0, NULL); 3017 if (status < B_OK) 3018 panic("error mounting pipefs\n"); 3019 3020 // bootstrap the bootfs (if possible) 3021 _kern_create_dir(-1, "/boot", 0755); 3022 status = _kern_mount("/boot", NULL, "bootfs", 0, NULL); 3023 if (status < B_OK) { 3024 // this is no fatal exception at this point, as we may mount 3025 // a real on disk file system later 3026 dprintf("Can't mount bootfs (will try disk file system later)\n"); 3027 } 3028 3029 // create some standard links on the rootfs 3030 3031 for (int32 i = 0; sPredefinedLinks[i].path != NULL; i++) { 3032 _kern_create_symlink(-1, sPredefinedLinks[i].path, 3033 sPredefinedLinks[i].target, 0); 3034 // we don't care if it will succeed or not 3035 } 3036 3037 return B_OK; 3038 } 3039 3040 3041 status_t 3042 vfs_mount_boot_file_system(kernel_args *args) 3043 { 3044 // make the boot partition (and probably others) available 3045 KDiskDeviceManager::CreateDefault(); 3046 KDiskDeviceManager *manager = KDiskDeviceManager::Default(); 3047 3048 status_t status = manager->InitialDeviceScan(); 3049 if (status == B_OK) { 3050 // ToDo: do this for real... (no hacks allowed :)) 3051 for (;;) { 3052 snooze(500000); 3053 if (manager->CountJobs() == 0) 3054 break; 3055 } 3056 } else 3057 dprintf("KDiskDeviceManager::InitialDeviceScan() failed: %s\n", strerror(status)); 3058 3059 file_system_module_info *bootfs; 3060 if ((bootfs = get_file_system("bootfs")) == NULL) { 3061 // no bootfs there, yet 3062 3063 // ToDo: do this for real! It will currently only use the partition offset; 3064 // it does not yet use the disk_identifier information. 3065 3066 KPartition *bootPartition = NULL; 3067 3068 struct BootPartitionVisitor : KPartitionVisitor { 3069 BootPartitionVisitor(off_t offset) : fOffset(offset) {} 3070 3071 virtual bool VisitPre(KPartition *partition) 3072 { 3073 return (partition->ContainsFileSystem() 3074 && partition->Offset() == fOffset); 3075 } 3076 private: 3077 off_t fOffset; 3078 } visitor(args->boot_disk.partition_offset); 3079 3080 KDiskDevice *device; 3081 int32 cookie = 0; 3082 while ((device = manager->NextDevice(&cookie)) != NULL) { 3083 bootPartition = device->VisitEachDescendant(&visitor); 3084 if (bootPartition) 3085 break; 3086 } 3087 3088 KPath path; 3089 if (bootPartition == NULL 3090 || bootPartition->GetPath(&path) != B_OK 3091 || _kern_mount("/boot", path.Path(), "bfs", 0, NULL) < B_OK) 3092 panic("could not get boot device!\n"); 3093 } else 3094 put_file_system(bootfs); 3095 3096 gBootDevice = sNextMountID - 1; 3097 3098 // create link for the name of the boot device 3099 3100 fs_info info; 3101 if (_kern_read_fs_info(gBootDevice, &info) == B_OK) { 3102 char path[B_FILE_NAME_LENGTH + 1]; 3103 snprintf(path, sizeof(path), "/%s", info.volume_name); 3104 3105 _kern_create_symlink(-1, path, "/boot", 0); 3106 } 3107 3108 file_cache_init_post_boot_device(); 3109 return B_OK; 3110 } 3111 3112 3113 status_t 3114 vfs_init(kernel_args *args) 3115 { 3116 sVnodeTable = hash_init(VNODE_HASH_TABLE_SIZE, offsetof(struct vnode, next), 3117 &vnode_compare, &vnode_hash); 3118 if (sVnodeTable == NULL) 3119 panic("vfs_init: error creating vnode hash table\n"); 3120 3121 list_init_etc(&sUnusedVnodeList, offsetof(struct vnode, unused_link)); 3122 3123 sMountsTable = hash_init(MOUNTS_HASH_TABLE_SIZE, offsetof(struct fs_mount, next), 3124 &mount_compare, &mount_hash); 3125 if (sMountsTable == NULL) 3126 panic("vfs_init: error creating mounts hash table\n"); 3127 3128 node_monitor_init(); 3129 3130 sRoot = NULL; 3131 3132 if (mutex_init(&sFileSystemsMutex, "vfs_lock") < 0) 3133 panic("vfs_init: error allocating file systems lock\n"); 3134 3135 if (recursive_lock_init(&sMountOpLock, "vfs_mount_op_lock") < 0) 3136 panic("vfs_init: error allocating mount op lock\n"); 3137 3138 if (mutex_init(&sMountMutex, "vfs_mount_lock") < 0) 3139 panic("vfs_init: error allocating mount lock\n"); 3140 3141 if (mutex_init(&sVnodeMutex, "vfs_vnode_lock") < 0) 3142 panic("vfs_init: error allocating vnode lock\n"); 3143 3144 if (block_cache_init() != B_OK) 3145 return B_ERROR; 3146 3147 #ifdef ADD_DEBUGGER_COMMANDS 3148 // add some debugger commands 3149 add_debugger_command("vnode", &dump_vnode, "info about the specified vnode"); 3150 add_debugger_command("vnodes", &dump_vnodes, "list all vnodes (from the specified device)"); 3151 add_debugger_command("vnode_caches", &dump_vnode_caches, "list all vnode caches"); 3152 add_debugger_command("mount", &dump_mount, "info about the specified fs_mount"); 3153 add_debugger_command("mounts", &dump_mounts, "list all fs_mounts"); 3154 #endif 3155 3156 return file_cache_init(); 3157 } 3158 3159 3160 // #pragma mark - 3161 // The filetype-dependent implementations (fd_ops + open/create/rename/remove, ...) 3162 3163 3164 /** Calls fs_open() on the given vnode and returns a new 3165 * file descriptor for it 3166 */ 3167 3168 static int 3169 create_vnode(struct vnode *directory, const char *name, int openMode, int perms, bool kernel) 3170 { 3171 struct vnode *vnode; 3172 fs_cookie cookie; 3173 vnode_id newID; 3174 int status; 3175 3176 if (FS_CALL(directory, create) == NULL) 3177 return EROFS; 3178 3179 status = FS_CALL(directory, create)(directory->mount->cookie, directory->private_node, name, openMode, perms, &cookie, &newID); 3180 if (status < B_OK) 3181 return status; 3182 3183 mutex_lock(&sVnodeMutex); 3184 vnode = lookup_vnode(directory->device, newID); 3185 mutex_unlock(&sVnodeMutex); 3186 3187 if (vnode == NULL) { 3188 dprintf("vfs: fs_create() returned success but there is no vnode!"); 3189 return EINVAL; 3190 } 3191 3192 if ((status = get_new_fd(FDTYPE_FILE, NULL, vnode, cookie, openMode, kernel)) >= 0) 3193 return status; 3194 3195 // something went wrong, clean up 3196 3197 FS_CALL(vnode, close)(vnode->mount->cookie, vnode->private_node, cookie); 3198 FS_CALL(vnode, free_cookie)(vnode->mount->cookie, vnode->private_node, cookie); 3199 put_vnode(vnode); 3200 3201 FS_CALL(directory, unlink)(directory->mount->cookie, directory->private_node, name); 3202 3203 return status; 3204 } 3205 3206 3207 /** Calls fs_open() on the given vnode and returns a new 3208 * file descriptor for it 3209 */ 3210 3211 static int 3212 open_vnode(struct vnode *vnode, int openMode, bool kernel) 3213 { 3214 fs_cookie cookie; 3215 int status; 3216 3217 status = FS_CALL(vnode, open)(vnode->mount->cookie, vnode->private_node, openMode, &cookie); 3218 if (status < 0) 3219 return status; 3220 3221 status = get_new_fd(FDTYPE_FILE, NULL, vnode, cookie, openMode, kernel); 3222 if (status < 0) { 3223 FS_CALL(vnode, close)(vnode->mount->cookie, vnode->private_node, cookie); 3224 FS_CALL(vnode, free_cookie)(vnode->mount->cookie, vnode->private_node, cookie); 3225 } 3226 return status; 3227 } 3228 3229 3230 /** Calls fs open_dir() on the given vnode and returns a new 3231 * file descriptor for it 3232 */ 3233 3234 static int 3235 open_dir_vnode(struct vnode *vnode, bool kernel) 3236 { 3237 fs_cookie cookie; 3238 int status; 3239 3240 status = FS_CALL(vnode, open_dir)(vnode->mount->cookie, vnode->private_node, &cookie); 3241 if (status < B_OK) 3242 return status; 3243 3244 // file is opened, create a fd 3245 status = get_new_fd(FDTYPE_DIR, NULL, vnode, cookie, 0, kernel); 3246 if (status >= 0) 3247 return status; 3248 3249 FS_CALL(vnode, close_dir)(vnode->mount->cookie, vnode->private_node, cookie); 3250 FS_CALL(vnode, free_dir_cookie)(vnode->mount->cookie, vnode->private_node, cookie); 3251 3252 return status; 3253 } 3254 3255 3256 /** Calls fs open_attr_dir() on the given vnode and returns a new 3257 * file descriptor for it. 3258 * Used by attr_dir_open(), and attr_dir_open_fd(). 3259 */ 3260 3261 static int 3262 open_attr_dir_vnode(struct vnode *vnode, bool kernel) 3263 { 3264 fs_cookie cookie; 3265 int status; 3266 3267 if (FS_CALL(vnode, open_attr_dir) == NULL) 3268 return EOPNOTSUPP; 3269 3270 status = FS_CALL(vnode, open_attr_dir)(vnode->mount->cookie, vnode->private_node, &cookie); 3271 if (status < 0) 3272 return status; 3273 3274 // file is opened, create a fd 3275 status = get_new_fd(FDTYPE_ATTR_DIR, NULL, vnode, cookie, 0, kernel); 3276 if (status >= 0) 3277 return status; 3278 3279 FS_CALL(vnode, close_attr_dir)(vnode->mount->cookie, vnode->private_node, cookie); 3280 FS_CALL(vnode, free_attr_dir_cookie)(vnode->mount->cookie, vnode->private_node, cookie); 3281 3282 return status; 3283 } 3284 3285 3286 static int 3287 file_create_entry_ref(mount_id mountID, vnode_id directoryID, const char *name, int openMode, int perms, bool kernel) 3288 { 3289 struct vnode *directory; 3290 int status; 3291 3292 FUNCTION(("file_create_entry_ref: name = '%s', omode %x, perms %d, kernel %d\n", name, openMode, perms, kernel)); 3293 3294 // get directory to put the new file in 3295 status = get_vnode(mountID, directoryID, &directory, false); 3296 if (status < B_OK) 3297 return status; 3298 3299 status = create_vnode(directory, name, openMode, perms, kernel); 3300 put_vnode(directory); 3301 3302 return status; 3303 } 3304 3305 3306 static int 3307 file_create(int fd, char *path, int openMode, int perms, bool kernel) 3308 { 3309 char name[B_FILE_NAME_LENGTH]; 3310 struct vnode *directory; 3311 int status; 3312 3313 FUNCTION(("file_create: path '%s', omode %x, perms %d, kernel %d\n", path, openMode, perms, kernel)); 3314 3315 // get directory to put the new file in 3316 status = fd_and_path_to_dir_vnode(fd, path, &directory, name, kernel); 3317 if (status < 0) 3318 return status; 3319 3320 status = create_vnode(directory, name, openMode, perms, kernel); 3321 3322 put_vnode(directory); 3323 return status; 3324 } 3325 3326 3327 static int 3328 file_open_entry_ref(mount_id mountID, vnode_id directoryID, const char *name, int openMode, bool kernel) 3329 { 3330 struct vnode *vnode; 3331 int status; 3332 3333 if (name == NULL || *name == '\0') 3334 return B_BAD_VALUE; 3335 3336 FUNCTION(("file_open_entry_ref(ref = (%ld, %Ld, %s), openMode = %d)\n", 3337 mountID, directoryID, name, openMode)); 3338 3339 // get the vnode matching the entry_ref 3340 status = entry_ref_to_vnode(mountID, directoryID, name, &vnode); 3341 if (status < B_OK) 3342 return status; 3343 3344 status = open_vnode(vnode, openMode, kernel); 3345 if (status < B_OK) 3346 put_vnode(vnode); 3347 3348 cache_node_opened(vnode, FDTYPE_FILE, vnode->cache, mountID, directoryID, vnode->id, name); 3349 return status; 3350 } 3351 3352 3353 static int 3354 file_open(int fd, char *path, int openMode, bool kernel) 3355 { 3356 int status = B_OK; 3357 bool traverse = ((openMode & O_NOTRAVERSE) == 0); 3358 3359 FUNCTION(("file_open: fd: %d, entry path = '%s', omode %d, kernel %d\n", 3360 fd, path, openMode, kernel)); 3361 3362 // get the vnode matching the vnode + path combination 3363 struct vnode *vnode = NULL; 3364 vnode_id parentID; 3365 status = fd_and_path_to_vnode(fd, path, traverse, &vnode, &parentID, kernel); 3366 if (status != B_OK) 3367 return status; 3368 3369 // open the vnode 3370 status = open_vnode(vnode, openMode, kernel); 3371 // put only on error -- otherwise our reference was transferred to the FD 3372 if (status < B_OK) 3373 put_vnode(vnode); 3374 3375 cache_node_opened(vnode, FDTYPE_FILE, vnode->cache, 3376 vnode->device, parentID, vnode->id, NULL); 3377 3378 return status; 3379 } 3380 3381 3382 static status_t 3383 file_close(struct file_descriptor *descriptor) 3384 { 3385 struct vnode *vnode = descriptor->u.vnode; 3386 status_t status = B_OK; 3387 3388 FUNCTION(("file_close(descriptor = %p)\n", descriptor)); 3389 3390 cache_node_closed(vnode, FDTYPE_FILE, vnode->cache, vnode->device, vnode->id); 3391 if (FS_CALL(vnode, close)) 3392 status = FS_CALL(vnode, close)(vnode->mount->cookie, vnode->private_node, descriptor->cookie); 3393 3394 if (status == B_OK) { 3395 // remove all outstanding locks for this team 3396 release_advisory_lock(vnode, NULL); 3397 } 3398 return status; 3399 } 3400 3401 3402 static void 3403 file_free_fd(struct file_descriptor *descriptor) 3404 { 3405 struct vnode *vnode = descriptor->u.vnode; 3406 3407 if (vnode != NULL) { 3408 FS_CALL(vnode, free_cookie)(vnode->mount->cookie, vnode->private_node, descriptor->cookie); 3409 put_vnode(vnode); 3410 } 3411 } 3412 3413 3414 static status_t 3415 file_read(struct file_descriptor *descriptor, off_t pos, void *buffer, size_t *length) 3416 { 3417 struct vnode *vnode = descriptor->u.vnode; 3418 3419 FUNCTION(("file_read: buf %p, pos %Ld, len %p = %ld\n", buffer, pos, length, *length)); 3420 return FS_CALL(vnode, read)(vnode->mount->cookie, vnode->private_node, descriptor->cookie, pos, buffer, length); 3421 } 3422 3423 3424 static status_t 3425 file_write(struct file_descriptor *descriptor, off_t pos, const void *buffer, size_t *length) 3426 { 3427 struct vnode *vnode = descriptor->u.vnode; 3428 3429 FUNCTION(("file_write: buf %p, pos %Ld, len %p\n", buffer, pos, length)); 3430 return FS_CALL(vnode, write)(vnode->mount->cookie, vnode->private_node, descriptor->cookie, pos, buffer, length); 3431 } 3432 3433 3434 static off_t 3435 file_seek(struct file_descriptor *descriptor, off_t pos, int seekType) 3436 { 3437 off_t offset; 3438 3439 FUNCTION(("file_seek(pos = %Ld, seekType = %d)\n", pos, seekType)); 3440 // ToDo: seek should fail for pipes and FIFOs... 3441 3442 switch (seekType) { 3443 case SEEK_SET: 3444 offset = 0; 3445 break; 3446 case SEEK_CUR: 3447 offset = descriptor->pos; 3448 break; 3449 case SEEK_END: 3450 { 3451 struct vnode *vnode = descriptor->u.vnode; 3452 struct stat stat; 3453 status_t status; 3454 3455 if (FS_CALL(vnode, read_stat) == NULL) 3456 return EOPNOTSUPP; 3457 3458 status = FS_CALL(vnode, read_stat)(vnode->mount->cookie, vnode->private_node, &stat); 3459 if (status < B_OK) 3460 return status; 3461 3462 offset = stat.st_size; 3463 break; 3464 } 3465 default: 3466 return B_BAD_VALUE; 3467 } 3468 3469 // assumes off_t is 64 bits wide 3470 if (offset > 0 && LONGLONG_MAX - offset < pos) 3471 return EOVERFLOW; 3472 3473 pos += offset; 3474 if (pos < 0) 3475 return B_BAD_VALUE; 3476 3477 return descriptor->pos = pos; 3478 } 3479 3480 3481 static status_t 3482 file_select(struct file_descriptor *descriptor, uint8 event, uint32 ref, 3483 struct select_sync *sync) 3484 { 3485 FUNCTION(("file_select(%p, %u, %lu, %p)\n", descriptor, event, ref, sync)); 3486 3487 struct vnode *vnode = descriptor->u.vnode; 3488 3489 // If the FS has no select() hook, notify select() now. 3490 if (FS_CALL(vnode, select) == NULL) 3491 return notify_select_event((selectsync*)sync, ref, event); 3492 3493 return FS_CALL(vnode, select)(vnode->mount->cookie, vnode->private_node, 3494 descriptor->cookie, event, ref, (selectsync*)sync); 3495 } 3496 3497 3498 static status_t 3499 file_deselect(struct file_descriptor *descriptor, uint8 event, 3500 struct select_sync *sync) 3501 { 3502 struct vnode *vnode = descriptor->u.vnode; 3503 3504 if (FS_CALL(vnode, deselect) == NULL) 3505 return B_OK; 3506 3507 return FS_CALL(vnode, deselect)(vnode->mount->cookie, vnode->private_node, 3508 descriptor->cookie, event, (selectsync*)sync); 3509 } 3510 3511 3512 static status_t 3513 dir_create_entry_ref(mount_id mountID, vnode_id parentID, const char *name, int perms, bool kernel) 3514 { 3515 struct vnode *vnode; 3516 vnode_id newID; 3517 status_t status; 3518 3519 if (name == NULL || *name == '\0') 3520 return B_BAD_VALUE; 3521 3522 FUNCTION(("dir_create_entry_ref(dev = %ld, ino = %Ld, name = '%s', perms = %d)\n", mountID, parentID, name, perms)); 3523 3524 status = get_vnode(mountID, parentID, &vnode, kernel); 3525 if (status < B_OK) 3526 return status; 3527 3528 if (FS_CALL(vnode, create_dir)) 3529 status = FS_CALL(vnode, create_dir)(vnode->mount->cookie, vnode->private_node, name, perms, &newID); 3530 else 3531 status = EROFS; 3532 3533 put_vnode(vnode); 3534 return status; 3535 } 3536 3537 3538 static status_t 3539 dir_create(int fd, char *path, int perms, bool kernel) 3540 { 3541 char filename[B_FILE_NAME_LENGTH]; 3542 struct vnode *vnode; 3543 vnode_id newID; 3544 status_t status; 3545 3546 FUNCTION(("dir_create: path '%s', perms %d, kernel %d\n", path, perms, kernel)); 3547 3548 status = fd_and_path_to_dir_vnode(fd, path, &vnode, filename, kernel); 3549 if (status < 0) 3550 return status; 3551 3552 if (FS_CALL(vnode, create_dir)) 3553 status = FS_CALL(vnode, create_dir)(vnode->mount->cookie, vnode->private_node, filename, perms, &newID); 3554 else 3555 status = EROFS; 3556 3557 put_vnode(vnode); 3558 return status; 3559 } 3560 3561 3562 static int 3563 dir_open_entry_ref(mount_id mountID, vnode_id parentID, const char *name, bool kernel) 3564 { 3565 struct vnode *vnode; 3566 int status; 3567 3568 FUNCTION(("dir_open_entry_ref()\n")); 3569 3570 if (name && *name == '\0') 3571 return B_BAD_VALUE; 3572 3573 // get the vnode matching the entry_ref/node_ref 3574 if (name) 3575 status = entry_ref_to_vnode(mountID, parentID, name, &vnode); 3576 else 3577 status = get_vnode(mountID, parentID, &vnode, false); 3578 if (status < B_OK) 3579 return status; 3580 3581 status = open_dir_vnode(vnode, kernel); 3582 if (status < B_OK) 3583 put_vnode(vnode); 3584 3585 cache_node_opened(vnode, FDTYPE_DIR, vnode->cache, mountID, parentID, vnode->id, name); 3586 return status; 3587 } 3588 3589 3590 static int 3591 dir_open(int fd, char *path, bool kernel) 3592 { 3593 int status = B_OK; 3594 3595 FUNCTION(("dir_open: fd: %d, entry path = '%s', kernel %d\n", fd, path, kernel)); 3596 3597 // get the vnode matching the vnode + path combination 3598 struct vnode *vnode = NULL; 3599 vnode_id parentID; 3600 status = fd_and_path_to_vnode(fd, path, true, &vnode, &parentID, kernel); 3601 if (status != B_OK) 3602 return status; 3603 3604 // open the dir 3605 status = open_dir_vnode(vnode, kernel); 3606 if (status < B_OK) 3607 put_vnode(vnode); 3608 3609 cache_node_opened(vnode, FDTYPE_DIR, vnode->cache, vnode->device, parentID, vnode->id, NULL); 3610 return status; 3611 } 3612 3613 3614 static status_t 3615 dir_close(struct file_descriptor *descriptor) 3616 { 3617 struct vnode *vnode = descriptor->u.vnode; 3618 3619 FUNCTION(("dir_close(descriptor = %p)\n", descriptor)); 3620 3621 cache_node_closed(vnode, FDTYPE_DIR, vnode->cache, vnode->device, vnode->id); 3622 if (FS_CALL(vnode, close_dir)) 3623 return FS_CALL(vnode, close_dir)(vnode->mount->cookie, vnode->private_node, descriptor->cookie); 3624 3625 return B_OK; 3626 } 3627 3628 3629 static void 3630 dir_free_fd(struct file_descriptor *descriptor) 3631 { 3632 struct vnode *vnode = descriptor->u.vnode; 3633 3634 if (vnode != NULL) { 3635 FS_CALL(vnode, free_dir_cookie)(vnode->mount->cookie, vnode->private_node, descriptor->cookie); 3636 put_vnode(vnode); 3637 } 3638 } 3639 3640 3641 static status_t 3642 dir_read(struct file_descriptor *descriptor, struct dirent *buffer, size_t bufferSize, uint32 *_count) 3643 { 3644 return dir_read(descriptor->u.vnode, descriptor->cookie, buffer, bufferSize, _count); 3645 } 3646 3647 3648 static void 3649 fix_dirent(struct vnode *parent, struct dirent *entry) 3650 { 3651 // set d_pdev and d_pino 3652 entry->d_pdev = parent->device; 3653 entry->d_pino = parent->id; 3654 3655 // If this is the ".." entry and the directory is the root of a FS, 3656 // we need to replace d_dev and d_ino with the actual values. 3657 if (strcmp(entry->d_name, "..") == 0 3658 && parent->mount->root_vnode == parent 3659 && parent->mount->covers_vnode) { 3660 3661 inc_vnode_ref_count(parent); // vnode_path_to_vnode() puts the node 3662 3663 struct vnode *vnode; 3664 status_t status = vnode_path_to_vnode(parent, "..", false, 0, &vnode, 3665 NULL, NULL); 3666 3667 if (status == B_OK) { 3668 entry->d_dev = vnode->device; 3669 entry->d_ino = vnode->id; 3670 } 3671 } else { 3672 // resolve mount points 3673 struct vnode *vnode = NULL; 3674 status_t status = get_vnode(entry->d_dev, entry->d_ino, &vnode, false); 3675 if (status != B_OK) 3676 return; 3677 3678 recursive_lock_lock(&sMountOpLock); 3679 if (vnode->covered_by) { 3680 entry->d_dev = vnode->covered_by->device; 3681 entry->d_ino = vnode->covered_by->id; 3682 } 3683 recursive_lock_unlock(&sMountOpLock); 3684 3685 put_vnode(vnode); 3686 } 3687 } 3688 3689 3690 static status_t 3691 dir_read(struct vnode *vnode, fs_cookie cookie, struct dirent *buffer, size_t bufferSize, uint32 *_count) 3692 { 3693 if (!FS_CALL(vnode, read_dir)) 3694 return EOPNOTSUPP; 3695 3696 status_t error = FS_CALL(vnode, read_dir)(vnode->mount->cookie,vnode->private_node,cookie,buffer,bufferSize,_count); 3697 if (error != B_OK) 3698 return error; 3699 3700 // we need to adjust the read dirents 3701 if (*_count > 0) { 3702 // XXX: Currently reading only one dirent is supported. Make this a loop! 3703 fix_dirent(vnode, buffer); 3704 } 3705 3706 return error; 3707 } 3708 3709 3710 static status_t 3711 dir_rewind(struct file_descriptor *descriptor) 3712 { 3713 struct vnode *vnode = descriptor->u.vnode; 3714 3715 if (FS_CALL(vnode, rewind_dir)) 3716 return FS_CALL(vnode, rewind_dir)(vnode->mount->cookie,vnode->private_node,descriptor->cookie); 3717 3718 return EOPNOTSUPP; 3719 } 3720 3721 3722 static status_t 3723 dir_remove(char *path, bool kernel) 3724 { 3725 char name[B_FILE_NAME_LENGTH]; 3726 struct vnode *directory; 3727 status_t status; 3728 3729 status = path_to_dir_vnode(path, &directory, name, kernel); 3730 if (status < B_OK) 3731 return status; 3732 3733 if (FS_CALL(directory, remove_dir)) 3734 status = FS_CALL(directory, remove_dir)(directory->mount->cookie, directory->private_node, name); 3735 else 3736 status = EROFS; 3737 3738 put_vnode(directory); 3739 return status; 3740 } 3741 3742 3743 static status_t 3744 common_ioctl(struct file_descriptor *descriptor, ulong op, void *buffer, size_t length) 3745 { 3746 struct vnode *vnode = descriptor->u.vnode; 3747 3748 if (FS_CALL(vnode, ioctl)) { 3749 return FS_CALL(vnode, ioctl)(vnode->mount->cookie, vnode->private_node, 3750 descriptor->cookie, op, buffer, length); 3751 } 3752 3753 return EOPNOTSUPP; 3754 } 3755 3756 3757 static status_t 3758 common_fcntl(int fd, int op, uint32 argument, bool kernel) 3759 { 3760 struct file_descriptor *descriptor; 3761 struct vnode *vnode; 3762 struct flock flock; 3763 status_t status; 3764 3765 FUNCTION(("common_fcntl(fd = %d, op = %d, argument = %lx, %s)\n", 3766 fd, op, argument, kernel ? "kernel" : "user")); 3767 3768 descriptor = get_fd_and_vnode(fd, &vnode, kernel); 3769 if (descriptor == NULL) 3770 return B_FILE_ERROR; 3771 3772 if (op == F_SETLK || op == F_SETLKW || op == F_GETLK) { 3773 if (descriptor->type != FDTYPE_FILE) 3774 return B_BAD_VALUE; 3775 if (user_memcpy(&flock, (struct flock *)argument, sizeof(struct flock)) < B_OK) 3776 return B_BAD_ADDRESS; 3777 } 3778 3779 switch (op) { 3780 case F_SETFD: 3781 // Set file descriptor flags 3782 3783 // O_CLOEXEC is the only flag available at this time 3784 if (argument == FD_CLOEXEC) 3785 atomic_or(&descriptor->open_mode, O_CLOEXEC); 3786 else 3787 atomic_and(&descriptor->open_mode, O_CLOEXEC); 3788 3789 status = B_OK; 3790 break; 3791 3792 case F_GETFD: 3793 // Get file descriptor flags 3794 status = (descriptor->open_mode & O_CLOEXEC) ? FD_CLOEXEC : 0; 3795 break; 3796 3797 case F_SETFL: 3798 // Set file descriptor open mode 3799 if (FS_CALL(vnode, set_flags)) { 3800 // we only accept changes to O_APPEND and O_NONBLOCK 3801 argument &= O_APPEND | O_NONBLOCK; 3802 3803 status = FS_CALL(vnode, set_flags)(vnode->mount->cookie, vnode->private_node, descriptor->cookie, (int)argument); 3804 if (status == B_OK) { 3805 // update this descriptor's open_mode field 3806 descriptor->open_mode = (descriptor->open_mode & ~(O_APPEND | O_NONBLOCK)) | argument; 3807 } 3808 } else 3809 status = EOPNOTSUPP; 3810 break; 3811 3812 case F_GETFL: 3813 // Get file descriptor open mode 3814 status = descriptor->open_mode; 3815 break; 3816 3817 case F_DUPFD: 3818 status = new_fd_etc(get_current_io_context(kernel), descriptor, (int)argument); 3819 if (status >= 0) 3820 atomic_add(&descriptor->ref_count, 1); 3821 break; 3822 3823 case F_GETLK: 3824 status = get_advisory_lock(descriptor->u.vnode, &flock); 3825 if (status == B_OK) { 3826 // copy back flock structure 3827 status = user_memcpy((struct flock *)argument, &flock, sizeof(struct flock)); 3828 } 3829 break; 3830 3831 case F_SETLK: 3832 case F_SETLKW: 3833 status = normalize_flock(descriptor, &flock); 3834 if (status < B_OK) 3835 break; 3836 3837 if (flock.l_type == F_UNLCK) 3838 status = release_advisory_lock(descriptor->u.vnode, &flock); 3839 else { 3840 // the open mode must match the lock type 3841 if ((descriptor->open_mode & O_RWMASK) == O_RDONLY && flock.l_type == F_WRLCK 3842 || (descriptor->open_mode & O_RWMASK) == O_WRONLY && flock.l_type == F_RDLCK) 3843 status = B_FILE_ERROR; 3844 else 3845 status = acquire_advisory_lock(descriptor->u.vnode, &flock, op == F_SETLKW); 3846 } 3847 break; 3848 3849 // ToDo: add support for more ops? 3850 3851 default: 3852 status = B_BAD_VALUE; 3853 } 3854 3855 put_fd(descriptor); 3856 return status; 3857 } 3858 3859 3860 static status_t 3861 common_sync(int fd, bool kernel) 3862 { 3863 struct file_descriptor *descriptor; 3864 struct vnode *vnode; 3865 status_t status; 3866 3867 FUNCTION(("common_fsync: entry. fd %d kernel %d\n", fd, kernel)); 3868 3869 descriptor = get_fd_and_vnode(fd, &vnode, kernel); 3870 if (descriptor == NULL) 3871 return B_FILE_ERROR; 3872 3873 if (FS_CALL(vnode, fsync) != NULL) 3874 status = FS_CALL(vnode, fsync)(vnode->mount->cookie, vnode->private_node); 3875 else 3876 status = EOPNOTSUPP; 3877 3878 put_fd(descriptor); 3879 return status; 3880 } 3881 3882 3883 static status_t 3884 common_lock_node(int fd, bool kernel) 3885 { 3886 // TODO: Implement! 3887 return EOPNOTSUPP; 3888 } 3889 3890 3891 static status_t 3892 common_unlock_node(int fd, bool kernel) 3893 { 3894 // TODO: Implement! 3895 return EOPNOTSUPP; 3896 } 3897 3898 3899 static status_t 3900 common_read_link(int fd, char *path, char *buffer, size_t *_bufferSize, 3901 bool kernel) 3902 { 3903 struct vnode *vnode; 3904 status_t status; 3905 3906 status = fd_and_path_to_vnode(fd, path, false, &vnode, NULL, kernel); 3907 if (status < B_OK) 3908 return status; 3909 3910 if (FS_CALL(vnode, read_link) != NULL) { 3911 status = FS_CALL(vnode, read_link)(vnode->mount->cookie, 3912 vnode->private_node, buffer, _bufferSize); 3913 } else 3914 status = B_BAD_VALUE; 3915 3916 put_vnode(vnode); 3917 return status; 3918 } 3919 3920 3921 static status_t 3922 common_write_link(char *path, char *toPath, bool kernel) 3923 { 3924 struct vnode *vnode; 3925 status_t status; 3926 3927 status = path_to_vnode(path, false, &vnode, NULL, kernel); 3928 if (status < B_OK) 3929 return status; 3930 3931 if (FS_CALL(vnode, write_link) != NULL) 3932 status = FS_CALL(vnode, write_link)(vnode->mount->cookie, vnode->private_node, toPath); 3933 else 3934 status = EOPNOTSUPP; 3935 3936 put_vnode(vnode); 3937 3938 return status; 3939 } 3940 3941 3942 static status_t 3943 common_create_symlink(int fd, char *path, const char *toPath, int mode, 3944 bool kernel) 3945 { 3946 // path validity checks have to be in the calling function! 3947 char name[B_FILE_NAME_LENGTH]; 3948 struct vnode *vnode; 3949 status_t status; 3950 3951 FUNCTION(("common_create_symlink(fd = %d, path = %s, toPath = %s, mode = %d, kernel = %d)\n", fd, path, toPath, mode, kernel)); 3952 3953 status = fd_and_path_to_dir_vnode(fd, path, &vnode, name, kernel); 3954 if (status < B_OK) 3955 return status; 3956 3957 if (FS_CALL(vnode, create_symlink) != NULL) 3958 status = FS_CALL(vnode, create_symlink)(vnode->mount->cookie, vnode->private_node, name, toPath, mode); 3959 else 3960 status = EROFS; 3961 3962 put_vnode(vnode); 3963 3964 return status; 3965 } 3966 3967 3968 static status_t 3969 common_create_link(char *path, char *toPath, bool kernel) 3970 { 3971 // path validity checks have to be in the calling function! 3972 char name[B_FILE_NAME_LENGTH]; 3973 struct vnode *directory, *vnode; 3974 status_t status; 3975 3976 FUNCTION(("common_create_link(path = %s, toPath = %s, kernel = %d)\n", path, toPath, kernel)); 3977 3978 status = path_to_dir_vnode(path, &directory, name, kernel); 3979 if (status < B_OK) 3980 return status; 3981 3982 status = path_to_vnode(toPath, true, &vnode, NULL, kernel); 3983 if (status < B_OK) 3984 goto err; 3985 3986 if (directory->mount != vnode->mount) { 3987 status = B_CROSS_DEVICE_LINK; 3988 goto err1; 3989 } 3990 3991 if (FS_CALL(vnode, link) != NULL) 3992 status = FS_CALL(vnode, link)(directory->mount->cookie, directory->private_node, name, vnode->private_node); 3993 else 3994 status = EROFS; 3995 3996 err1: 3997 put_vnode(vnode); 3998 err: 3999 put_vnode(directory); 4000 4001 return status; 4002 } 4003 4004 4005 static status_t 4006 common_unlink(int fd, char *path, bool kernel) 4007 { 4008 char filename[B_FILE_NAME_LENGTH]; 4009 struct vnode *vnode; 4010 status_t status; 4011 4012 FUNCTION(("common_unlink: fd: %d, path '%s', kernel %d\n", fd, path, kernel)); 4013 4014 status = fd_and_path_to_dir_vnode(fd, path, &vnode, filename, kernel); 4015 if (status < 0) 4016 return status; 4017 4018 if (FS_CALL(vnode, unlink) != NULL) 4019 status = FS_CALL(vnode, unlink)(vnode->mount->cookie, vnode->private_node, filename); 4020 else 4021 status = EROFS; 4022 4023 put_vnode(vnode); 4024 4025 return status; 4026 } 4027 4028 4029 static status_t 4030 common_access(char *path, int mode, bool kernel) 4031 { 4032 struct vnode *vnode; 4033 status_t status; 4034 4035 status = path_to_vnode(path, true, &vnode, NULL, kernel); 4036 if (status < B_OK) 4037 return status; 4038 4039 if (FS_CALL(vnode, access) != NULL) 4040 status = FS_CALL(vnode, access)(vnode->mount->cookie, vnode->private_node, mode); 4041 else 4042 status = EOPNOTSUPP; 4043 4044 put_vnode(vnode); 4045 4046 return status; 4047 } 4048 4049 4050 static status_t 4051 common_rename(int fd, char *path, int newFD, char *newPath, bool kernel) 4052 { 4053 struct vnode *fromVnode, *toVnode; 4054 char fromName[B_FILE_NAME_LENGTH]; 4055 char toName[B_FILE_NAME_LENGTH]; 4056 status_t status; 4057 4058 FUNCTION(("common_rename(fd = %d, path = %s, newFD = %d, newPath = %s, kernel = %d)\n", fd, path, newFD, newPath, kernel)); 4059 4060 status = fd_and_path_to_dir_vnode(fd, path, &fromVnode, fromName, kernel); 4061 if (status < 0) 4062 return status; 4063 4064 status = fd_and_path_to_dir_vnode(newFD, newPath, &toVnode, toName, kernel); 4065 if (status < 0) 4066 goto err; 4067 4068 if (fromVnode->device != toVnode->device) { 4069 status = B_CROSS_DEVICE_LINK; 4070 goto err1; 4071 } 4072 4073 if (FS_CALL(fromVnode, rename) != NULL) 4074 status = FS_CALL(fromVnode, rename)(fromVnode->mount->cookie, fromVnode->private_node, fromName, toVnode->private_node, toName); 4075 else 4076 status = EROFS; 4077 4078 err1: 4079 put_vnode(toVnode); 4080 err: 4081 put_vnode(fromVnode); 4082 4083 return status; 4084 } 4085 4086 4087 static status_t 4088 common_read_stat(struct file_descriptor *descriptor, struct stat *stat) 4089 { 4090 struct vnode *vnode = descriptor->u.vnode; 4091 4092 FUNCTION(("common_read_stat: stat %p\n", stat)); 4093 4094 status_t status = FS_CALL(vnode, read_stat)(vnode->mount->cookie, 4095 vnode->private_node, stat); 4096 4097 // fill in the st_dev and st_ino fields 4098 if (status == B_OK) { 4099 stat->st_dev = vnode->device; 4100 stat->st_ino = vnode->id; 4101 } 4102 4103 return status; 4104 } 4105 4106 4107 static status_t 4108 common_write_stat(struct file_descriptor *descriptor, const struct stat *stat, int statMask) 4109 { 4110 struct vnode *vnode = descriptor->u.vnode; 4111 4112 FUNCTION(("common_write_stat(vnode = %p, stat = %p, statMask = %d)\n", vnode, stat, statMask)); 4113 if (!FS_CALL(vnode, write_stat)) 4114 return EROFS; 4115 4116 return FS_CALL(vnode, write_stat)(vnode->mount->cookie, vnode->private_node, stat, statMask); 4117 } 4118 4119 4120 static status_t 4121 common_path_read_stat(int fd, char *path, bool traverseLeafLink, 4122 struct stat *stat, bool kernel) 4123 { 4124 struct vnode *vnode; 4125 status_t status; 4126 4127 FUNCTION(("common_path_read_stat: fd: %d, path '%s', stat %p,\n", fd, path, stat)); 4128 4129 status = fd_and_path_to_vnode(fd, path, traverseLeafLink, &vnode, NULL, kernel); 4130 if (status < 0) 4131 return status; 4132 4133 status = FS_CALL(vnode, read_stat)(vnode->mount->cookie, vnode->private_node, stat); 4134 4135 // fill in the st_dev and st_ino fields 4136 if (status == B_OK) { 4137 stat->st_dev = vnode->device; 4138 stat->st_ino = vnode->id; 4139 } 4140 4141 put_vnode(vnode); 4142 return status; 4143 } 4144 4145 4146 static status_t 4147 common_path_write_stat(int fd, char *path, bool traverseLeafLink, 4148 const struct stat *stat, int statMask, bool kernel) 4149 { 4150 struct vnode *vnode; 4151 status_t status; 4152 4153 FUNCTION(("common_write_stat: fd: %d, path '%s', stat %p, stat_mask %d, kernel %d\n", fd, path, stat, statMask, kernel)); 4154 4155 status = fd_and_path_to_vnode(fd, path, traverseLeafLink, &vnode, NULL, kernel); 4156 if (status < 0) 4157 return status; 4158 4159 if (FS_CALL(vnode, write_stat)) 4160 status = FS_CALL(vnode, write_stat)(vnode->mount->cookie, vnode->private_node, stat, statMask); 4161 else 4162 status = EROFS; 4163 4164 put_vnode(vnode); 4165 4166 return status; 4167 } 4168 4169 4170 static int 4171 attr_dir_open(int fd, char *path, bool kernel) 4172 { 4173 struct vnode *vnode; 4174 int status; 4175 4176 FUNCTION(("attr_dir_open(fd = %d, path = '%s', kernel = %d)\n", fd, path, kernel)); 4177 4178 status = fd_and_path_to_vnode(fd, path, true, &vnode, NULL, kernel); 4179 if (status < B_OK) 4180 return status; 4181 4182 status = open_attr_dir_vnode(vnode, kernel); 4183 if (status < 0) 4184 put_vnode(vnode); 4185 4186 return status; 4187 } 4188 4189 4190 static status_t 4191 attr_dir_close(struct file_descriptor *descriptor) 4192 { 4193 struct vnode *vnode = descriptor->u.vnode; 4194 4195 FUNCTION(("attr_dir_close(descriptor = %p)\n", descriptor)); 4196 4197 if (FS_CALL(vnode, close_attr_dir)) 4198 return FS_CALL(vnode, close_attr_dir)(vnode->mount->cookie, vnode->private_node, descriptor->cookie); 4199 4200 return B_OK; 4201 } 4202 4203 4204 static void 4205 attr_dir_free_fd(struct file_descriptor *descriptor) 4206 { 4207 struct vnode *vnode = descriptor->u.vnode; 4208 4209 if (vnode != NULL) { 4210 FS_CALL(vnode, free_attr_dir_cookie)(vnode->mount->cookie, vnode->private_node, descriptor->cookie); 4211 put_vnode(vnode); 4212 } 4213 } 4214 4215 4216 static status_t 4217 attr_dir_read(struct file_descriptor *descriptor, struct dirent *buffer, size_t bufferSize, uint32 *_count) 4218 { 4219 struct vnode *vnode = descriptor->u.vnode; 4220 4221 FUNCTION(("attr_dir_read(descriptor = %p)\n", descriptor)); 4222 4223 if (FS_CALL(vnode, read_attr_dir)) 4224 return FS_CALL(vnode, read_attr_dir)(vnode->mount->cookie, vnode->private_node, descriptor->cookie, buffer, bufferSize, _count); 4225 4226 return EOPNOTSUPP; 4227 } 4228 4229 4230 static status_t 4231 attr_dir_rewind(struct file_descriptor *descriptor) 4232 { 4233 struct vnode *vnode = descriptor->u.vnode; 4234 4235 FUNCTION(("attr_dir_rewind(descriptor = %p)\n", descriptor)); 4236 4237 if (FS_CALL(vnode, rewind_attr_dir)) 4238 return FS_CALL(vnode, rewind_attr_dir)(vnode->mount->cookie, vnode->private_node, descriptor->cookie); 4239 4240 return EOPNOTSUPP; 4241 } 4242 4243 4244 static int 4245 attr_create(int fd, const char *name, uint32 type, int openMode, bool kernel) 4246 { 4247 struct vnode *vnode; 4248 fs_cookie cookie; 4249 int status; 4250 4251 if (name == NULL || *name == '\0') 4252 return B_BAD_VALUE; 4253 4254 vnode = get_vnode_from_fd(fd, kernel); 4255 if (vnode == NULL) 4256 return B_FILE_ERROR; 4257 4258 if (FS_CALL(vnode, create_attr) == NULL) { 4259 status = EROFS; 4260 goto err; 4261 } 4262 4263 status = FS_CALL(vnode, create_attr)(vnode->mount->cookie, vnode->private_node, name, type, openMode, &cookie); 4264 if (status < B_OK) 4265 goto err; 4266 4267 if ((status = get_new_fd(FDTYPE_ATTR, NULL, vnode, cookie, openMode, kernel)) >= 0) 4268 return status; 4269 4270 FS_CALL(vnode, close_attr)(vnode->mount->cookie, vnode->private_node, cookie); 4271 FS_CALL(vnode, free_attr_cookie)(vnode->mount->cookie, vnode->private_node, cookie); 4272 4273 FS_CALL(vnode, remove_attr)(vnode->mount->cookie, vnode->private_node, name); 4274 4275 err: 4276 put_vnode(vnode); 4277 4278 return status; 4279 } 4280 4281 4282 static int 4283 attr_open(int fd, const char *name, int openMode, bool kernel) 4284 { 4285 struct vnode *vnode; 4286 fs_cookie cookie; 4287 int status; 4288 4289 if (name == NULL || *name == '\0') 4290 return B_BAD_VALUE; 4291 4292 vnode = get_vnode_from_fd(fd, kernel); 4293 if (vnode == NULL) 4294 return B_FILE_ERROR; 4295 4296 if (FS_CALL(vnode, open_attr) == NULL) { 4297 status = EOPNOTSUPP; 4298 goto err; 4299 } 4300 4301 status = FS_CALL(vnode, open_attr)(vnode->mount->cookie, vnode->private_node, name, openMode, &cookie); 4302 if (status < B_OK) 4303 goto err; 4304 4305 // now we only need a file descriptor for this attribute and we're done 4306 if ((status = get_new_fd(FDTYPE_ATTR, NULL, vnode, cookie, openMode, kernel)) >= 0) 4307 return status; 4308 4309 FS_CALL(vnode, close_attr)(vnode->mount->cookie, vnode->private_node, cookie); 4310 FS_CALL(vnode, free_attr_cookie)(vnode->mount->cookie, vnode->private_node, cookie); 4311 4312 err: 4313 put_vnode(vnode); 4314 4315 return status; 4316 } 4317 4318 4319 static status_t 4320 attr_close(struct file_descriptor *descriptor) 4321 { 4322 struct vnode *vnode = descriptor->u.vnode; 4323 4324 FUNCTION(("attr_close(descriptor = %p)\n", descriptor)); 4325 4326 if (FS_CALL(vnode, close_attr)) 4327 return FS_CALL(vnode, close_attr)(vnode->mount->cookie, vnode->private_node, descriptor->cookie); 4328 4329 return B_OK; 4330 } 4331 4332 4333 static void 4334 attr_free_fd(struct file_descriptor *descriptor) 4335 { 4336 struct vnode *vnode = descriptor->u.vnode; 4337 4338 if (vnode != NULL) { 4339 FS_CALL(vnode, free_attr_cookie)(vnode->mount->cookie, vnode->private_node, descriptor->cookie); 4340 put_vnode(vnode); 4341 } 4342 } 4343 4344 4345 static status_t 4346 attr_read(struct file_descriptor *descriptor, off_t pos, void *buffer, size_t *length) 4347 { 4348 struct vnode *vnode = descriptor->u.vnode; 4349 4350 FUNCTION(("attr_read: buf %p, pos %Ld, len %p = %ld\n", buffer, pos, length, *length)); 4351 if (!FS_CALL(vnode, read_attr)) 4352 return EOPNOTSUPP; 4353 4354 return FS_CALL(vnode, read_attr)(vnode->mount->cookie, vnode->private_node, descriptor->cookie, pos, buffer, length); 4355 } 4356 4357 4358 static status_t 4359 attr_write(struct file_descriptor *descriptor, off_t pos, const void *buffer, size_t *length) 4360 { 4361 struct vnode *vnode = descriptor->u.vnode; 4362 4363 FUNCTION(("attr_write: buf %p, pos %Ld, len %p\n", buffer, pos, length)); 4364 if (!FS_CALL(vnode, write_attr)) 4365 return EOPNOTSUPP; 4366 4367 return FS_CALL(vnode, write_attr)(vnode->mount->cookie, vnode->private_node, descriptor->cookie, pos, buffer, length); 4368 } 4369 4370 4371 static off_t 4372 attr_seek(struct file_descriptor *descriptor, off_t pos, int seekType) 4373 { 4374 off_t offset; 4375 4376 switch (seekType) { 4377 case SEEK_SET: 4378 offset = 0; 4379 break; 4380 case SEEK_CUR: 4381 offset = descriptor->pos; 4382 break; 4383 case SEEK_END: 4384 { 4385 struct vnode *vnode = descriptor->u.vnode; 4386 struct stat stat; 4387 status_t status; 4388 4389 if (FS_CALL(vnode, read_stat) == NULL) 4390 return EOPNOTSUPP; 4391 4392 status = FS_CALL(vnode, read_attr_stat)(vnode->mount->cookie, vnode->private_node, descriptor->cookie, &stat); 4393 if (status < B_OK) 4394 return status; 4395 4396 offset = stat.st_size; 4397 break; 4398 } 4399 default: 4400 return B_BAD_VALUE; 4401 } 4402 4403 // assumes off_t is 64 bits wide 4404 if (offset > 0 && LONGLONG_MAX - offset < pos) 4405 return EOVERFLOW; 4406 4407 pos += offset; 4408 if (pos < 0) 4409 return B_BAD_VALUE; 4410 4411 return descriptor->pos = pos; 4412 } 4413 4414 4415 static status_t 4416 attr_read_stat(struct file_descriptor *descriptor, struct stat *stat) 4417 { 4418 struct vnode *vnode = descriptor->u.vnode; 4419 4420 FUNCTION(("attr_read_stat: stat 0x%p\n", stat)); 4421 4422 if (!FS_CALL(vnode, read_attr_stat)) 4423 return EOPNOTSUPP; 4424 4425 return FS_CALL(vnode, read_attr_stat)(vnode->mount->cookie, vnode->private_node, descriptor->cookie, stat); 4426 } 4427 4428 4429 static status_t 4430 attr_write_stat(struct file_descriptor *descriptor, const struct stat *stat, int statMask) 4431 { 4432 struct vnode *vnode = descriptor->u.vnode; 4433 4434 FUNCTION(("attr_write_stat: stat = %p, statMask %d\n", stat, statMask)); 4435 4436 if (!FS_CALL(vnode, write_attr_stat)) 4437 return EROFS; 4438 4439 return FS_CALL(vnode, write_attr_stat)(vnode->mount->cookie, vnode->private_node, descriptor->cookie, stat, statMask); 4440 } 4441 4442 4443 static status_t 4444 attr_remove(int fd, const char *name, bool kernel) 4445 { 4446 struct file_descriptor *descriptor; 4447 struct vnode *vnode; 4448 status_t status; 4449 4450 if (name == NULL || *name == '\0') 4451 return B_BAD_VALUE; 4452 4453 FUNCTION(("attr_remove: fd = %d, name = \"%s\", kernel %d\n", fd, name, kernel)); 4454 4455 descriptor = get_fd_and_vnode(fd, &vnode, kernel); 4456 if (descriptor == NULL) 4457 return B_FILE_ERROR; 4458 4459 if (FS_CALL(vnode, remove_attr)) 4460 status = FS_CALL(vnode, remove_attr)(vnode->mount->cookie, vnode->private_node, name); 4461 else 4462 status = EROFS; 4463 4464 put_fd(descriptor); 4465 4466 return status; 4467 } 4468 4469 4470 static status_t 4471 attr_rename(int fromfd, const char *fromName, int tofd, const char *toName, bool kernel) 4472 { 4473 struct file_descriptor *fromDescriptor, *toDescriptor; 4474 struct vnode *fromVnode, *toVnode; 4475 status_t status; 4476 4477 if (fromName == NULL || *fromName == '\0' || toName == NULL || *toName == '\0') 4478 return B_BAD_VALUE; 4479 4480 FUNCTION(("attr_rename: from fd = %d, from name = \"%s\", to fd = %d, to name = \"%s\", kernel %d\n", fromfd, fromName, tofd, toName, kernel)); 4481 4482 fromDescriptor = get_fd_and_vnode(fromfd, &fromVnode, kernel); 4483 if (fromDescriptor == NULL) 4484 return B_FILE_ERROR; 4485 4486 toDescriptor = get_fd_and_vnode(tofd, &toVnode, kernel); 4487 if (toDescriptor == NULL) { 4488 status = B_FILE_ERROR; 4489 goto err; 4490 } 4491 4492 // are the files on the same volume? 4493 if (fromVnode->device != toVnode->device) { 4494 status = B_CROSS_DEVICE_LINK; 4495 goto err1; 4496 } 4497 4498 if (FS_CALL(fromVnode, rename_attr)) 4499 status = FS_CALL(fromVnode, rename_attr)(fromVnode->mount->cookie, fromVnode->private_node, fromName, toVnode->private_node, toName); 4500 else 4501 status = EROFS; 4502 4503 err1: 4504 put_fd(toDescriptor); 4505 err: 4506 put_fd(fromDescriptor); 4507 4508 return status; 4509 } 4510 4511 4512 static status_t 4513 index_dir_open(mount_id mountID, bool kernel) 4514 { 4515 struct fs_mount *mount; 4516 fs_cookie cookie; 4517 status_t status; 4518 4519 FUNCTION(("index_dir_open(mountID = %ld, kernel = %d)\n", mountID, kernel)); 4520 4521 mount = get_mount(mountID); 4522 if (mount == NULL) 4523 return B_BAD_VALUE; 4524 4525 if (FS_MOUNT_CALL(mount, open_index_dir) == NULL) { 4526 status = EOPNOTSUPP; 4527 goto out; 4528 } 4529 4530 status = FS_MOUNT_CALL(mount, open_index_dir)(mount->cookie, &cookie); 4531 if (status < B_OK) 4532 goto out; 4533 4534 // get fd for the index directory 4535 status = get_new_fd(FDTYPE_INDEX_DIR, mount, NULL, cookie, 0, kernel); 4536 if (status >= 0) 4537 goto out; 4538 4539 // something went wrong 4540 FS_MOUNT_CALL(mount, close_index_dir)(mount->cookie, cookie); 4541 FS_MOUNT_CALL(mount, free_index_dir_cookie)(mount->cookie, cookie); 4542 4543 out: 4544 put_mount(mount); 4545 return status; 4546 } 4547 4548 4549 static status_t 4550 index_dir_close(struct file_descriptor *descriptor) 4551 { 4552 struct fs_mount *mount = descriptor->u.mount; 4553 4554 FUNCTION(("index_dir_close(descriptor = %p)\n", descriptor)); 4555 4556 if (FS_MOUNT_CALL(mount, close_index_dir)) 4557 return FS_MOUNT_CALL(mount, close_index_dir)(mount->cookie, descriptor->cookie); 4558 4559 return B_OK; 4560 } 4561 4562 4563 static void 4564 index_dir_free_fd(struct file_descriptor *descriptor) 4565 { 4566 struct fs_mount *mount = descriptor->u.mount; 4567 4568 if (mount != NULL) { 4569 FS_MOUNT_CALL(mount, free_index_dir_cookie)(mount->cookie, descriptor->cookie); 4570 // ToDo: find a replacement ref_count object - perhaps the root dir? 4571 //put_vnode(vnode); 4572 } 4573 } 4574 4575 4576 static status_t 4577 index_dir_read(struct file_descriptor *descriptor, struct dirent *buffer, size_t bufferSize, uint32 *_count) 4578 { 4579 struct fs_mount *mount = descriptor->u.mount; 4580 4581 if (FS_MOUNT_CALL(mount, read_index_dir)) 4582 return FS_MOUNT_CALL(mount, read_index_dir)(mount->cookie, descriptor->cookie, buffer, bufferSize, _count); 4583 4584 return EOPNOTSUPP; 4585 } 4586 4587 4588 static status_t 4589 index_dir_rewind(struct file_descriptor *descriptor) 4590 { 4591 struct fs_mount *mount = descriptor->u.mount; 4592 4593 if (FS_MOUNT_CALL(mount, rewind_index_dir)) 4594 return FS_MOUNT_CALL(mount, rewind_index_dir)(mount->cookie, descriptor->cookie); 4595 4596 return EOPNOTSUPP; 4597 } 4598 4599 4600 static status_t 4601 index_create(mount_id mountID, const char *name, uint32 type, uint32 flags, bool kernel) 4602 { 4603 struct fs_mount *mount; 4604 status_t status; 4605 4606 FUNCTION(("index_create(mountID = %ld, name = %s, kernel = %d)\n", mountID, name, kernel)); 4607 4608 mount = get_mount(mountID); 4609 if (mount == NULL) 4610 return B_BAD_VALUE; 4611 4612 if (FS_MOUNT_CALL(mount, create_index) == NULL) { 4613 status = EROFS; 4614 goto out; 4615 } 4616 4617 status = FS_MOUNT_CALL(mount, create_index)(mount->cookie, name, type, flags); 4618 4619 out: 4620 put_mount(mount); 4621 return status; 4622 } 4623 4624 4625 #if 0 4626 static status_t 4627 index_read_stat(struct file_descriptor *descriptor, struct stat *stat) 4628 { 4629 struct vnode *vnode = descriptor->u.vnode; 4630 4631 // ToDo: currently unused! 4632 FUNCTION(("index_read_stat: stat 0x%p\n", stat)); 4633 if (!FS_CALL(vnode, read_index_stat)) 4634 return EOPNOTSUPP; 4635 4636 return EOPNOTSUPP; 4637 //return FS_CALL(vnode, read_index_stat)(vnode->mount->cookie, vnode->private_node, descriptor->cookie, stat); 4638 } 4639 4640 4641 static void 4642 index_free_fd(struct file_descriptor *descriptor) 4643 { 4644 struct vnode *vnode = descriptor->u.vnode; 4645 4646 if (vnode != NULL) { 4647 FS_CALL(vnode, free_index_cookie)(vnode->mount->cookie, vnode->private_node, descriptor->cookie); 4648 put_vnode(vnode); 4649 } 4650 } 4651 #endif 4652 4653 4654 static status_t 4655 index_name_read_stat(mount_id mountID, const char *name, struct stat *stat, bool kernel) 4656 { 4657 struct fs_mount *mount; 4658 status_t status; 4659 4660 FUNCTION(("index_remove(mountID = %ld, name = %s, kernel = %d)\n", mountID, name, kernel)); 4661 4662 mount = get_mount(mountID); 4663 if (mount == NULL) 4664 return B_BAD_VALUE; 4665 4666 if (FS_MOUNT_CALL(mount, read_index_stat) == NULL) { 4667 status = EOPNOTSUPP; 4668 goto out; 4669 } 4670 4671 status = FS_MOUNT_CALL(mount, read_index_stat)(mount->cookie, name, stat); 4672 4673 out: 4674 put_mount(mount); 4675 return status; 4676 } 4677 4678 4679 static status_t 4680 index_remove(mount_id mountID, const char *name, bool kernel) 4681 { 4682 struct fs_mount *mount; 4683 status_t status; 4684 4685 FUNCTION(("index_remove(mountID = %ld, name = %s, kernel = %d)\n", mountID, name, kernel)); 4686 4687 mount = get_mount(mountID); 4688 if (mount == NULL) 4689 return B_BAD_VALUE; 4690 4691 if (FS_MOUNT_CALL(mount, remove_index) == NULL) { 4692 status = EROFS; 4693 goto out; 4694 } 4695 4696 status = FS_MOUNT_CALL(mount, remove_index)(mount->cookie, name); 4697 4698 out: 4699 put_mount(mount); 4700 return status; 4701 } 4702 4703 4704 /** ToDo: the query FS API is still the pretty much the same as in R5. 4705 * It would be nice if the FS would find some more kernel support 4706 * for them. 4707 * For example, query parsing should be moved into the kernel. 4708 */ 4709 4710 static int 4711 query_open(dev_t device, const char *query, uint32 flags, 4712 port_id port, int32 token, bool kernel) 4713 { 4714 struct fs_mount *mount; 4715 fs_cookie cookie; 4716 status_t status; 4717 4718 FUNCTION(("query_open(device = %ld, query = \"%s\", kernel = %d)\n", device, query, kernel)); 4719 4720 mount = get_mount(device); 4721 if (mount == NULL) 4722 return B_BAD_VALUE; 4723 4724 if (FS_MOUNT_CALL(mount, open_query) == NULL) { 4725 status = EOPNOTSUPP; 4726 goto out; 4727 } 4728 4729 status = FS_MOUNT_CALL(mount, open_query)(mount->cookie, query, flags, port, token, &cookie); 4730 if (status < B_OK) 4731 goto out; 4732 4733 // get fd for the index directory 4734 status = get_new_fd(FDTYPE_QUERY, mount, NULL, cookie, 0, kernel); 4735 if (status >= 0) 4736 goto out; 4737 4738 // something went wrong 4739 FS_MOUNT_CALL(mount, close_query)(mount->cookie, cookie); 4740 FS_MOUNT_CALL(mount, free_query_cookie)(mount->cookie, cookie); 4741 4742 out: 4743 put_mount(mount); 4744 return status; 4745 } 4746 4747 4748 static status_t 4749 query_close(struct file_descriptor *descriptor) 4750 { 4751 struct fs_mount *mount = descriptor->u.mount; 4752 4753 FUNCTION(("query_close(descriptor = %p)\n", descriptor)); 4754 4755 if (FS_MOUNT_CALL(mount, close_query)) 4756 return FS_MOUNT_CALL(mount, close_query)(mount->cookie, descriptor->cookie); 4757 4758 return B_OK; 4759 } 4760 4761 4762 static void 4763 query_free_fd(struct file_descriptor *descriptor) 4764 { 4765 struct fs_mount *mount = descriptor->u.mount; 4766 4767 if (mount != NULL) { 4768 FS_MOUNT_CALL(mount, free_query_cookie)(mount->cookie, descriptor->cookie); 4769 // ToDo: find a replacement ref_count object - perhaps the root dir? 4770 //put_vnode(vnode); 4771 } 4772 } 4773 4774 4775 static status_t 4776 query_read(struct file_descriptor *descriptor, struct dirent *buffer, size_t bufferSize, uint32 *_count) 4777 { 4778 struct fs_mount *mount = descriptor->u.mount; 4779 4780 if (FS_MOUNT_CALL(mount, read_query)) 4781 return FS_MOUNT_CALL(mount, read_query)(mount->cookie, descriptor->cookie, buffer, bufferSize, _count); 4782 4783 return EOPNOTSUPP; 4784 } 4785 4786 4787 static status_t 4788 query_rewind(struct file_descriptor *descriptor) 4789 { 4790 struct fs_mount *mount = descriptor->u.mount; 4791 4792 if (FS_MOUNT_CALL(mount, rewind_query)) 4793 return FS_MOUNT_CALL(mount, rewind_query)(mount->cookie, descriptor->cookie); 4794 4795 return EOPNOTSUPP; 4796 } 4797 4798 4799 // #pragma mark - 4800 // General File System functions 4801 4802 4803 static status_t 4804 fs_mount(char *path, const char *device, const char *fsName, uint32 flags, 4805 const char *args, bool kernel) 4806 { 4807 struct fs_mount *mount; 4808 status_t status = 0; 4809 4810 FUNCTION(("fs_mount: entry. path = '%s', fs_name = '%s'\n", path, fsName)); 4811 4812 // The path is always safe, we just have to make sure that fsName is 4813 // almost valid - we can't make any assumptions about args, though. 4814 // A NULL fsName is OK, if a device was given and the FS is not virtual. 4815 // We'll get it from the DDM later. 4816 if (fsName == NULL) { 4817 if (!device || flags & B_MOUNT_VIRTUAL_DEVICE) 4818 return B_BAD_VALUE; 4819 } else if (fsName[0] == '\0') 4820 return B_BAD_VALUE; 4821 4822 RecursiveLocker mountOpLocker(sMountOpLock); 4823 4824 // Helper to delete a newly created file device on failure. 4825 // Not exactly beautiful, but helps to keep the code below cleaner. 4826 struct FileDeviceDeleter { 4827 FileDeviceDeleter() : id(-1) {} 4828 ~FileDeviceDeleter() 4829 { 4830 KDiskDeviceManager::Default()->DeleteFileDevice(id); 4831 } 4832 4833 partition_id id; 4834 } fileDeviceDeleter; 4835 4836 // If the file system is not a "virtual" one, the device argument should 4837 // point to a real file/device (if given at all). 4838 // get the partition 4839 KDiskDeviceManager *ddm = KDiskDeviceManager::Default(); 4840 KPartition *partition = NULL; 4841 bool newlyCreatedFileDevice = false; 4842 if (!(flags & B_MOUNT_VIRTUAL_DEVICE) && device) { 4843 // normalize the device path 4844 KPath normalizedDevice; 4845 status = normalizedDevice.SetTo(device, true); 4846 if (status != B_OK) 4847 return status; 4848 4849 // get a corresponding partition from the DDM 4850 partition = ddm->RegisterPartition(normalizedDevice.Path(), true); 4851 4852 if (!partition) { 4853 // Partition not found: This either means, the user supplied 4854 // an invalid path, or the path refers to an image file. We try 4855 // to let the DDM create a file device for the path. 4856 partition_id deviceID = ddm->CreateFileDevice( 4857 normalizedDevice.Path(), &newlyCreatedFileDevice); 4858 if (deviceID >= 0) { 4859 partition = ddm->RegisterPartition(deviceID, true); 4860 if (newlyCreatedFileDevice) 4861 fileDeviceDeleter.id = deviceID; 4862 // TODO: We must wait here, until the partition scan job is done. 4863 } 4864 } 4865 4866 if (!partition) { 4867 PRINT(("fs_mount(): Partition `%s' not found.\n", 4868 normalizedDevice.Path())); 4869 return B_ENTRY_NOT_FOUND; 4870 } 4871 } 4872 PartitionRegistrar partitionRegistrar(partition, true); 4873 4874 // Write lock the partition's device. For the time being, we keep the lock 4875 // until we're done mounting -- not nice, but ensure, that no-one is 4876 // interfering. 4877 // TODO: Find a better solution. 4878 KDiskDevice *diskDevice = NULL; 4879 if (partition) { 4880 diskDevice = ddm->WriteLockDevice(partition->Device()->ID()); 4881 if (!diskDevice) { 4882 PRINT(("fs_mount(): Failed to lock disk device!\n")); 4883 return B_ERROR; 4884 } 4885 } 4886 DeviceWriteLocker writeLocker(diskDevice, true); 4887 4888 if (partition) { 4889 // make sure, that the partition is not busy 4890 if (partition->IsBusy() || partition->IsDescendantBusy()) { 4891 PRINT(("fs_mount(): Partition is busy.\n")); 4892 return B_BUSY; 4893 } 4894 4895 // if no FS name had been supplied, we get it from the partition 4896 if (!fsName) { 4897 KDiskSystem *diskSystem = partition->DiskSystem(); 4898 if (!diskSystem) { 4899 PRINT(("fs_mount(): No FS name was given, and the DDM didn't " 4900 "recognize it.\n")); 4901 return B_BAD_VALUE; 4902 } 4903 4904 if (!diskSystem->IsFileSystem()) { 4905 PRINT(("fs_mount(): No FS name was given, and the DDM found a " 4906 "partitioning system.\n")); 4907 return B_BAD_VALUE; 4908 } 4909 4910 // The disk system name will not change, and the KDiskSystem 4911 // object will not go away while the disk device is locked (and 4912 // the partition has a reference to it), so this is safe. 4913 fsName = diskSystem->Name(); 4914 } 4915 } 4916 4917 mount = (struct fs_mount *)malloc(sizeof(struct fs_mount)); 4918 if (mount == NULL) 4919 return B_NO_MEMORY; 4920 4921 list_init_etc(&mount->vnodes, offsetof(struct vnode, mount_link)); 4922 4923 mount->fs_name = get_file_system_name(fsName); 4924 if (mount->fs_name == NULL) { 4925 status = B_NO_MEMORY; 4926 goto err1; 4927 } 4928 4929 mount->device_name = strdup(device); 4930 // "device" can be NULL 4931 4932 mount->fs = get_file_system(fsName); 4933 if (mount->fs == NULL) { 4934 status = ENODEV; 4935 goto err3; 4936 } 4937 4938 status = recursive_lock_init(&mount->rlock, "mount rlock"); 4939 if (status < B_OK) 4940 goto err4; 4941 4942 mount->id = sNextMountID++; 4943 mount->partition = NULL; 4944 mount->unmounting = false; 4945 mount->owns_file_device = false; 4946 4947 // insert mount struct into list before we call fs mount() 4948 mutex_lock(&sMountMutex); 4949 hash_insert(sMountsTable, mount); 4950 mutex_unlock(&sMountMutex); 4951 4952 vnode_id rootID; 4953 4954 if (!sRoot) { 4955 // we haven't mounted anything yet 4956 if (strcmp(path, "/") != 0) { 4957 status = B_ERROR; 4958 goto err5; 4959 } 4960 4961 status = FS_MOUNT_CALL(mount, mount)(mount->id, device, flags, args, &mount->cookie, &rootID); 4962 if (status < 0) { 4963 // ToDo: why should we hide the error code from the file system here? 4964 //status = ERR_VFS_GENERAL; 4965 goto err5; 4966 } 4967 4968 mount->covers_vnode = NULL; // this is the root mount 4969 } else { 4970 struct vnode *coveredVnode; 4971 status = path_to_vnode(path, true, &coveredVnode, NULL, kernel); 4972 if (status < B_OK) 4973 goto err5; 4974 4975 // make sure covered_vnode is a DIR 4976 struct stat coveredNodeStat; 4977 status = FS_CALL(coveredVnode, read_stat)(coveredVnode->mount->cookie, 4978 coveredVnode->private_node, &coveredNodeStat); 4979 if (status < B_OK) 4980 goto err5; 4981 4982 if (!S_ISDIR(coveredNodeStat.st_mode)) { 4983 status = B_NOT_A_DIRECTORY; 4984 goto err5; 4985 } 4986 4987 if (coveredVnode->mount->root_vnode == coveredVnode) { 4988 // this is already a mount point 4989 status = B_BUSY; 4990 goto err5; 4991 } 4992 4993 mount->covers_vnode = coveredVnode; 4994 4995 // mount it 4996 status = FS_MOUNT_CALL(mount, mount)(mount->id, device, flags, args, &mount->cookie, &rootID); 4997 if (status < B_OK) 4998 goto err6; 4999 } 5000 5001 // the root node is supposed to be owned by the file system - it must 5002 // exist at this point 5003 mount->root_vnode = lookup_vnode(mount->id, rootID); 5004 if (mount->root_vnode == NULL || mount->root_vnode->ref_count != 1) { 5005 panic("fs_mount: file system does not own its root node!\n"); 5006 status = B_ERROR; 5007 goto err7; 5008 } 5009 5010 // No race here, since fs_mount() is the only function changing 5011 // covers_vnode (and holds sMountOpLock at that time). 5012 if (mount->covers_vnode) 5013 mount->covers_vnode->covered_by = mount->root_vnode; 5014 5015 if (!sRoot) 5016 sRoot = mount->root_vnode; 5017 5018 // supply the partition (if any) with the mount cookie and mark it mounted 5019 if (partition) { 5020 partition->SetMountCookie(mount->cookie); 5021 partition->SetVolumeID(mount->id); 5022 5023 // keep a partition reference as long as the partition is mounted 5024 partitionRegistrar.Detach(); 5025 mount->partition = partition; 5026 mount->owns_file_device = newlyCreatedFileDevice; 5027 fileDeviceDeleter.id = -1; 5028 } 5029 5030 return B_OK; 5031 5032 err7: 5033 FS_MOUNT_CALL(mount, unmount)(mount->cookie); 5034 err6: 5035 if (mount->covers_vnode) 5036 put_vnode(mount->covers_vnode); 5037 err5: 5038 mutex_lock(&sMountMutex); 5039 hash_remove(sMountsTable, mount); 5040 mutex_unlock(&sMountMutex); 5041 5042 recursive_lock_destroy(&mount->rlock); 5043 err4: 5044 put_file_system(mount->fs); 5045 free(mount->device_name); 5046 err3: 5047 free(mount->fs_name); 5048 err1: 5049 free(mount); 5050 5051 return status; 5052 } 5053 5054 5055 static status_t 5056 fs_unmount(char *path, uint32 flags, bool kernel) 5057 { 5058 struct fs_mount *mount; 5059 struct vnode *vnode; 5060 status_t err; 5061 5062 FUNCTION(("vfs_unmount: entry. path = '%s', kernel %d\n", path, kernel)); 5063 5064 err = path_to_vnode(path, true, &vnode, NULL, kernel); 5065 if (err < 0) 5066 return B_ENTRY_NOT_FOUND; 5067 5068 RecursiveLocker mountOpLocker(sMountOpLock); 5069 5070 mount = find_mount(vnode->device); 5071 if (!mount) 5072 panic("vfs_unmount: find_mount() failed on root vnode @%p of mount\n", vnode); 5073 5074 if (mount->root_vnode != vnode) { 5075 // not mountpoint 5076 put_vnode(vnode); 5077 return B_BAD_VALUE; 5078 } 5079 5080 // if the volume is associated with a partition, lock the device of the 5081 // partition as long as we are unmounting 5082 KDiskDeviceManager* ddm = KDiskDeviceManager::Default(); 5083 KPartition *partition = mount->partition; 5084 KDiskDevice *diskDevice = NULL; 5085 if (partition) { 5086 diskDevice = ddm->WriteLockDevice(partition->Device()->ID()); 5087 if (!diskDevice) { 5088 PRINT(("fs_unmount(): Failed to lock disk device!\n")); 5089 return B_ERROR; 5090 } 5091 } 5092 DeviceWriteLocker writeLocker(diskDevice, true); 5093 5094 // make sure, that the partition is not busy 5095 if (partition) { 5096 if (partition->IsBusy() || partition->IsDescendantBusy()) { 5097 PRINT(("fs_unmount(): Partition is busy.\n")); 5098 return B_BUSY; 5099 } 5100 } 5101 5102 // grab the vnode master mutex to keep someone from creating 5103 // a vnode while we're figuring out if we can continue 5104 mutex_lock(&sVnodeMutex); 5105 5106 // simplify the loop below: we decrement the root vnode ref_count 5107 // by the known number of references: one for the file system, one 5108 // from the path_to_vnode() call above 5109 mount->root_vnode->ref_count -= 2; 5110 5111 // cycle through the list of vnodes associated with this mount and 5112 // make sure all of them are not busy or have refs on them 5113 vnode = NULL; 5114 while ((vnode = (struct vnode *)list_get_next_item(&mount->vnodes, vnode)) != NULL) { 5115 if (vnode->busy || vnode->ref_count != 0) { 5116 // there are still vnodes in use on this mount, so we cannot unmount yet 5117 // ToDo: cut read/write access file descriptors, depending on the B_FORCE_UNMOUNT flag 5118 mount->root_vnode->ref_count += 2; 5119 mutex_unlock(&sVnodeMutex); 5120 put_vnode(mount->root_vnode); 5121 5122 return B_BUSY; 5123 } 5124 } 5125 5126 // we can safely continue, mark all of the vnodes busy and this mount 5127 // structure in unmounting state 5128 mount->unmounting = true; 5129 5130 while ((vnode = (struct vnode *)list_get_next_item(&mount->vnodes, vnode)) != NULL) { 5131 vnode->busy = true; 5132 } 5133 5134 mutex_unlock(&sVnodeMutex); 5135 5136 mount->covers_vnode->covered_by = NULL; 5137 put_vnode(mount->covers_vnode); 5138 5139 // Free all vnodes associated with this mount. 5140 // They will be removed from the mount list by free_vnode(), so 5141 // we don't have to do this. 5142 while ((vnode = (struct vnode *)list_get_first_item(&mount->vnodes)) != NULL) { 5143 free_vnode(vnode, false); 5144 } 5145 5146 // remove the mount structure from the hash table 5147 mutex_lock(&sMountMutex); 5148 hash_remove(sMountsTable, mount); 5149 mutex_unlock(&sMountMutex); 5150 5151 mountOpLocker.Unlock(); 5152 5153 FS_MOUNT_CALL(mount, unmount)(mount->cookie); 5154 5155 // release the file system 5156 put_file_system(mount->fs); 5157 5158 // dereference the partition and mark it unmounted 5159 if (partition) { 5160 partition->SetVolumeID(-1); 5161 partition->SetMountCookie(NULL); 5162 5163 if (mount->owns_file_device) 5164 KDiskDeviceManager::Default()->DeleteFileDevice(partition->ID()); 5165 partition->Unregister(); 5166 } 5167 5168 free(mount->device_name); 5169 free(mount->fs_name); 5170 free(mount); 5171 5172 return B_OK; 5173 } 5174 5175 5176 static status_t 5177 fs_sync(dev_t device) 5178 { 5179 struct fs_mount *mount; 5180 5181 mount = get_mount(device); 5182 if (mount == NULL) 5183 return B_BAD_VALUE; 5184 5185 mutex_lock(&sMountMutex); 5186 5187 status_t status = B_OK; 5188 if (FS_MOUNT_CALL(mount, sync)) 5189 status = FS_MOUNT_CALL(mount, sync)(mount->cookie); 5190 5191 mutex_unlock(&sMountMutex); 5192 5193 // synchronize all vnodes 5194 recursive_lock_lock(&mount->rlock); 5195 5196 struct vnode *vnode = NULL; 5197 while ((vnode = (struct vnode *)list_get_next_item(&mount->vnodes, vnode)) != NULL) { 5198 if (vnode->cache) 5199 vm_cache_write_modified(vnode->cache); 5200 } 5201 5202 recursive_lock_unlock(&mount->rlock); 5203 put_mount(mount); 5204 return status; 5205 } 5206 5207 5208 static status_t 5209 fs_read_info(dev_t device, struct fs_info *info) 5210 { 5211 struct fs_mount *mount; 5212 status_t status = B_OK; 5213 5214 mount = get_mount(device); 5215 if (mount == NULL) 5216 return B_BAD_VALUE; 5217 5218 // fill in info the file system doesn't (have to) know about 5219 memset(info, 0, sizeof(struct fs_info)); 5220 info->dev = mount->id; 5221 info->root = mount->root_vnode->id; 5222 strlcpy(info->fsh_name, mount->fs_name, sizeof(info->fsh_name)); 5223 if (mount->device_name != NULL) 5224 strlcpy(info->device_name, mount->device_name, sizeof(info->device_name)); 5225 5226 if (FS_MOUNT_CALL(mount, read_fs_info)) 5227 status = FS_MOUNT_CALL(mount, read_fs_info)(mount->cookie, info); 5228 5229 // if the call is not supported by the file system, there are still 5230 // the parts that we filled out ourselves 5231 5232 put_mount(mount); 5233 return status; 5234 } 5235 5236 5237 static status_t 5238 fs_write_info(dev_t device, const struct fs_info *info, int mask) 5239 { 5240 struct fs_mount *mount; 5241 status_t status; 5242 5243 mount = get_mount(device); 5244 if (mount == NULL) 5245 return B_BAD_VALUE; 5246 5247 if (FS_MOUNT_CALL(mount, write_fs_info)) 5248 status = FS_MOUNT_CALL(mount, write_fs_info)(mount->cookie, info, mask); 5249 else 5250 status = EROFS; 5251 5252 put_mount(mount); 5253 return status; 5254 } 5255 5256 5257 static dev_t 5258 fs_next_device(int32 *_cookie) 5259 { 5260 struct fs_mount *mount = NULL; 5261 dev_t device = *_cookie; 5262 5263 mutex_lock(&sMountMutex); 5264 5265 // Since device IDs are assigned sequentially, this algorithm 5266 // does work good enough. It makes sure that the device list 5267 // returned is sorted, and that no device is skipped when an 5268 // already visited device got unmounted. 5269 5270 while (device < sNextMountID) { 5271 mount = find_mount(device++); 5272 if (mount != NULL) 5273 break; 5274 } 5275 5276 *_cookie = device; 5277 5278 if (mount != NULL) 5279 device = mount->id; 5280 else 5281 device = B_BAD_VALUE; 5282 5283 mutex_unlock(&sMountMutex); 5284 5285 return device; 5286 } 5287 5288 5289 static status_t 5290 get_cwd(char *buffer, size_t size, bool kernel) 5291 { 5292 // Get current working directory from io context 5293 struct io_context *context = get_current_io_context(kernel); 5294 status_t status; 5295 5296 FUNCTION(("vfs_get_cwd: buf %p, size %ld\n", buffer, size)); 5297 5298 mutex_lock(&context->io_mutex); 5299 5300 if (context->cwd) 5301 status = dir_vnode_to_path(context->cwd, buffer, size); 5302 else 5303 status = B_ERROR; 5304 5305 mutex_unlock(&context->io_mutex); 5306 return status; 5307 } 5308 5309 5310 static status_t 5311 set_cwd(int fd, char *path, bool kernel) 5312 { 5313 struct io_context *context; 5314 struct vnode *vnode = NULL; 5315 struct vnode *oldDirectory; 5316 struct stat stat; 5317 status_t status; 5318 5319 FUNCTION(("set_cwd: path = \'%s\'\n", path)); 5320 5321 // Get vnode for passed path, and bail if it failed 5322 status = fd_and_path_to_vnode(fd, path, true, &vnode, NULL, kernel); 5323 if (status < 0) 5324 return status; 5325 5326 status = FS_CALL(vnode, read_stat)(vnode->mount->cookie, vnode->private_node, &stat); 5327 if (status < 0) 5328 goto err; 5329 5330 if (!S_ISDIR(stat.st_mode)) { 5331 // nope, can't cwd to here 5332 status = B_NOT_A_DIRECTORY; 5333 goto err; 5334 } 5335 5336 // Get current io context and lock 5337 context = get_current_io_context(kernel); 5338 mutex_lock(&context->io_mutex); 5339 5340 // save the old current working directory first 5341 oldDirectory = context->cwd; 5342 context->cwd = vnode; 5343 5344 mutex_unlock(&context->io_mutex); 5345 5346 if (oldDirectory) 5347 put_vnode(oldDirectory); 5348 5349 return B_NO_ERROR; 5350 5351 err: 5352 put_vnode(vnode); 5353 return status; 5354 } 5355 5356 5357 // #pragma mark - 5358 // Calls from within the kernel 5359 5360 5361 status_t 5362 _kern_mount(const char *path, const char *device, const char *fsName, 5363 uint32 flags, const char *args) 5364 { 5365 KPath pathBuffer(path, false, B_PATH_NAME_LENGTH + 1); 5366 if (pathBuffer.InitCheck() != B_OK) 5367 return B_NO_MEMORY; 5368 5369 return fs_mount(pathBuffer.LockBuffer(), device, fsName, flags, args, true); 5370 } 5371 5372 5373 status_t 5374 _kern_unmount(const char *path, uint32 flags) 5375 { 5376 KPath pathBuffer(path, false, B_PATH_NAME_LENGTH + 1); 5377 if (pathBuffer.InitCheck() != B_OK) 5378 return B_NO_MEMORY; 5379 5380 return fs_unmount(pathBuffer.LockBuffer(), flags, true); 5381 } 5382 5383 5384 status_t 5385 _kern_read_fs_info(dev_t device, struct fs_info *info) 5386 { 5387 if (info == NULL) 5388 return B_BAD_VALUE; 5389 5390 return fs_read_info(device, info); 5391 } 5392 5393 5394 status_t 5395 _kern_write_fs_info(dev_t device, const struct fs_info *info, int mask) 5396 { 5397 if (info == NULL) 5398 return B_BAD_VALUE; 5399 5400 return fs_write_info(device, info, mask); 5401 } 5402 5403 5404 status_t 5405 _kern_sync(void) 5406 { 5407 // Note: _kern_sync() is also called from _user_sync() 5408 int32 cookie = 0; 5409 dev_t device; 5410 while ((device = next_dev(&cookie)) >= 0) { 5411 status_t status = fs_sync(device); 5412 if (status != B_OK && status != B_BAD_VALUE) 5413 dprintf("sync: device %ld couldn't sync: %s\n", device, strerror(status)); 5414 } 5415 5416 return B_OK; 5417 } 5418 5419 5420 dev_t 5421 _kern_next_device(int32 *_cookie) 5422 { 5423 return fs_next_device(_cookie); 5424 } 5425 5426 5427 int 5428 _kern_open_entry_ref(dev_t device, ino_t inode, const char *name, int openMode, int perms) 5429 { 5430 if (openMode & O_CREAT) 5431 return file_create_entry_ref(device, inode, name, openMode, perms, true); 5432 5433 return file_open_entry_ref(device, inode, name, openMode, true); 5434 } 5435 5436 5437 /** \brief Opens a node specified by a FD + path pair. 5438 * 5439 * At least one of \a fd and \a path must be specified. 5440 * If only \a fd is given, the function opens the node identified by this 5441 * FD. If only a path is given, this path is opened. If both are given and 5442 * the path is absolute, \a fd is ignored; a relative path is reckoned off 5443 * of the directory (!) identified by \a fd. 5444 * 5445 * \param fd The FD. May be < 0. 5446 * \param path The absolute or relative path. May be \c NULL. 5447 * \param openMode The open mode. 5448 * \return A FD referring to the newly opened node, or an error code, 5449 * if an error occurs. 5450 */ 5451 5452 int 5453 _kern_open(int fd, const char *path, int openMode, int perms) 5454 { 5455 KPath pathBuffer(path, false, B_PATH_NAME_LENGTH + 1); 5456 if (pathBuffer.InitCheck() != B_OK) 5457 return B_NO_MEMORY; 5458 5459 if (openMode & O_CREAT) 5460 return file_create(fd, pathBuffer.LockBuffer(), openMode, perms, true); 5461 5462 return file_open(fd, pathBuffer.LockBuffer(), openMode, true); 5463 } 5464 5465 5466 /** \brief Opens a directory specified by entry_ref or node_ref. 5467 * 5468 * The supplied name may be \c NULL, in which case directory identified 5469 * by \a device and \a inode will be opened. Otherwise \a device and 5470 * \a inode identify the parent directory of the directory to be opened 5471 * and \a name its entry name. 5472 * 5473 * \param device If \a name is specified the ID of the device the parent 5474 * directory of the directory to be opened resides on, otherwise 5475 * the device of the directory itself. 5476 * \param inode If \a name is specified the node ID of the parent 5477 * directory of the directory to be opened, otherwise node ID of the 5478 * directory itself. 5479 * \param name The entry name of the directory to be opened. If \c NULL, 5480 * the \a device + \a inode pair identify the node to be opened. 5481 * \return The FD of the newly opened directory or an error code, if 5482 * something went wrong. 5483 */ 5484 5485 int 5486 _kern_open_dir_entry_ref(dev_t device, ino_t inode, const char *name) 5487 { 5488 return dir_open_entry_ref(device, inode, name, true); 5489 } 5490 5491 5492 /** \brief Opens a directory specified by a FD + path pair. 5493 * 5494 * At least one of \a fd and \a path must be specified. 5495 * If only \a fd is given, the function opens the directory identified by this 5496 * FD. If only a path is given, this path is opened. If both are given and 5497 * the path is absolute, \a fd is ignored; a relative path is reckoned off 5498 * of the directory (!) identified by \a fd. 5499 * 5500 * \param fd The FD. May be < 0. 5501 * \param path The absolute or relative path. May be \c NULL. 5502 * \return A FD referring to the newly opened directory, or an error code, 5503 * if an error occurs. 5504 */ 5505 5506 int 5507 _kern_open_dir(int fd, const char *path) 5508 { 5509 KPath pathBuffer(path, false, B_PATH_NAME_LENGTH + 1); 5510 if (pathBuffer.InitCheck() != B_OK) 5511 return B_NO_MEMORY; 5512 5513 return dir_open(fd, pathBuffer.LockBuffer(), true); 5514 } 5515 5516 5517 status_t 5518 _kern_fcntl(int fd, int op, uint32 argument) 5519 { 5520 return common_fcntl(fd, op, argument, true); 5521 } 5522 5523 5524 status_t 5525 _kern_fsync(int fd) 5526 { 5527 return common_sync(fd, true); 5528 } 5529 5530 5531 status_t 5532 _kern_lock_node(int fd) 5533 { 5534 return common_lock_node(fd, true); 5535 } 5536 5537 5538 status_t 5539 _kern_unlock_node(int fd) 5540 { 5541 return common_unlock_node(fd, true); 5542 } 5543 5544 5545 status_t 5546 _kern_create_dir_entry_ref(dev_t device, ino_t inode, const char *name, int perms) 5547 { 5548 return dir_create_entry_ref(device, inode, name, perms, true); 5549 } 5550 5551 5552 /** \brief Creates a directory specified by a FD + path pair. 5553 * 5554 * \a path must always be specified (it contains the name of the new directory 5555 * at least). If only a path is given, this path identifies the location at 5556 * which the directory shall be created. If both \a fd and \a path are given and 5557 * the path is absolute, \a fd is ignored; a relative path is reckoned off 5558 * of the directory (!) identified by \a fd. 5559 * 5560 * \param fd The FD. May be < 0. 5561 * \param path The absolute or relative path. Must not be \c NULL. 5562 * \param perms The access permissions the new directory shall have. 5563 * \return \c B_OK, if the directory has been created successfully, another 5564 * error code otherwise. 5565 */ 5566 5567 status_t 5568 _kern_create_dir(int fd, const char *path, int perms) 5569 { 5570 KPath pathBuffer(path, false, B_PATH_NAME_LENGTH + 1); 5571 if (pathBuffer.InitCheck() != B_OK) 5572 return B_NO_MEMORY; 5573 5574 return dir_create(fd, pathBuffer.LockBuffer(), perms, true); 5575 } 5576 5577 5578 status_t 5579 _kern_remove_dir(const char *path) 5580 { 5581 KPath pathBuffer(path, false, B_PATH_NAME_LENGTH + 1); 5582 if (pathBuffer.InitCheck() != B_OK) 5583 return B_NO_MEMORY; 5584 5585 return dir_remove(pathBuffer.LockBuffer(), true); 5586 } 5587 5588 5589 /** \brief Reads the contents of a symlink referred to by a FD + path pair. 5590 * 5591 * At least one of \a fd and \a path must be specified. 5592 * If only \a fd is given, the function the symlink to be read is the node 5593 * identified by this FD. If only a path is given, this path identifies the 5594 * symlink to be read. If both are given and the path is absolute, \a fd is 5595 * ignored; a relative path is reckoned off of the directory (!) identified 5596 * by \a fd. 5597 * If this function fails with B_BUFFER_OVERFLOW, the \a _bufferSize pointer 5598 * will still be updated to reflect the required buffer size. 5599 * 5600 * \param fd The FD. May be < 0. 5601 * \param path The absolute or relative path. May be \c NULL. 5602 * \param buffer The buffer into which the contents of the symlink shall be 5603 * written. 5604 * \param _bufferSize A pointer to the size of the supplied buffer. 5605 * \return The length of the link on success or an appropriate error code 5606 */ 5607 5608 status_t 5609 _kern_read_link(int fd, const char *path, char *buffer, size_t *_bufferSize) 5610 { 5611 status_t status; 5612 5613 if (path) { 5614 KPath pathBuffer(path, false, B_PATH_NAME_LENGTH + 1); 5615 if (pathBuffer.InitCheck() != B_OK) 5616 return B_NO_MEMORY; 5617 5618 return common_read_link(fd, pathBuffer.LockBuffer(), 5619 buffer, _bufferSize, true); 5620 } 5621 5622 return common_read_link(fd, NULL, buffer, _bufferSize, true); 5623 } 5624 5625 5626 status_t 5627 _kern_write_link(const char *path, const char *toPath) 5628 { 5629 KPath pathBuffer(path, false, B_PATH_NAME_LENGTH + 1); 5630 KPath toPathBuffer(toPath, false, B_PATH_NAME_LENGTH + 1); 5631 if (pathBuffer.InitCheck() != B_OK || toPathBuffer.InitCheck() != B_OK) 5632 return B_NO_MEMORY; 5633 5634 char *toBuffer = toPathBuffer.LockBuffer(); 5635 5636 status_t status = check_path(toBuffer); 5637 if (status < B_OK) 5638 return status; 5639 5640 return common_write_link(pathBuffer.LockBuffer(), toBuffer, true); 5641 } 5642 5643 5644 /** \brief Creates a symlink specified by a FD + path pair. 5645 * 5646 * \a path must always be specified (it contains the name of the new symlink 5647 * at least). If only a path is given, this path identifies the location at 5648 * which the symlink shall be created. If both \a fd and \a path are given and 5649 * the path is absolute, \a fd is ignored; a relative path is reckoned off 5650 * of the directory (!) identified by \a fd. 5651 * 5652 * \param fd The FD. May be < 0. 5653 * \param toPath The absolute or relative path. Must not be \c NULL. 5654 * \param mode The access permissions the new symlink shall have. 5655 * \return \c B_OK, if the symlink has been created successfully, another 5656 * error code otherwise. 5657 */ 5658 5659 status_t 5660 _kern_create_symlink(int fd, const char *path, const char *toPath, int mode) 5661 { 5662 KPath pathBuffer(path, false, B_PATH_NAME_LENGTH + 1); 5663 KPath toPathBuffer(toPath, false, B_PATH_NAME_LENGTH + 1); 5664 if (pathBuffer.InitCheck() != B_OK || toPathBuffer.InitCheck() != B_OK) 5665 return B_NO_MEMORY; 5666 5667 char *toBuffer = toPathBuffer.LockBuffer(); 5668 5669 status_t status = check_path(toBuffer); 5670 if (status < B_OK) 5671 return status; 5672 5673 return common_create_symlink(fd, pathBuffer.LockBuffer(), 5674 toBuffer, mode, true); 5675 } 5676 5677 5678 status_t 5679 _kern_create_link(const char *path, const char *toPath) 5680 { 5681 KPath pathBuffer(path, false, B_PATH_NAME_LENGTH + 1); 5682 KPath toPathBuffer(toPath, false, B_PATH_NAME_LENGTH + 1); 5683 if (pathBuffer.InitCheck() != B_OK || toPathBuffer.InitCheck() != B_OK) 5684 return B_NO_MEMORY; 5685 5686 return common_create_link(pathBuffer.LockBuffer(), 5687 toPathBuffer.LockBuffer(), true); 5688 } 5689 5690 5691 /** \brief Removes an entry specified by a FD + path pair from its directory. 5692 * 5693 * \a path must always be specified (it contains at least the name of the entry 5694 * to be deleted). If only a path is given, this path identifies the entry 5695 * directly. If both \a fd and \a path are given and the path is absolute, 5696 * \a fd is ignored; a relative path is reckoned off of the directory (!) 5697 * identified by \a fd. 5698 * 5699 * \param fd The FD. May be < 0. 5700 * \param path The absolute or relative path. Must not be \c NULL. 5701 * \return \c B_OK, if the entry has been removed successfully, another 5702 * error code otherwise. 5703 */ 5704 5705 status_t 5706 _kern_unlink(int fd, const char *path) 5707 { 5708 KPath pathBuffer(path, false, B_PATH_NAME_LENGTH + 1); 5709 if (pathBuffer.InitCheck() != B_OK) 5710 return B_NO_MEMORY; 5711 5712 return common_unlink(fd, pathBuffer.LockBuffer(), true); 5713 } 5714 5715 5716 /** \brief Moves an entry specified by a FD + path pair to a an entry specified 5717 * by another FD + path pair. 5718 * 5719 * \a oldPath and \a newPath must always be specified (they contain at least 5720 * the name of the entry). If only a path is given, this path identifies the 5721 * entry directly. If both a FD and a path are given and the path is absolute, 5722 * the FD is ignored; a relative path is reckoned off of the directory (!) 5723 * identified by the respective FD. 5724 * 5725 * \param oldFD The FD of the old location. May be < 0. 5726 * \param oldPath The absolute or relative path of the old location. Must not 5727 * be \c NULL. 5728 * \param newFD The FD of the new location. May be < 0. 5729 * \param newPath The absolute or relative path of the new location. Must not 5730 * be \c NULL. 5731 * \return \c B_OK, if the entry has been moved successfully, another 5732 * error code otherwise. 5733 */ 5734 5735 status_t 5736 _kern_rename(int oldFD, const char *oldPath, int newFD, const char *newPath) 5737 { 5738 KPath oldPathBuffer(oldPath, false, B_PATH_NAME_LENGTH + 1); 5739 KPath newPathBuffer(newPath, false, B_PATH_NAME_LENGTH + 1); 5740 if (oldPathBuffer.InitCheck() != B_OK || newPathBuffer.InitCheck() != B_OK) 5741 return B_NO_MEMORY; 5742 5743 return common_rename(oldFD, oldPathBuffer.LockBuffer(), 5744 newFD, newPathBuffer.LockBuffer(), true); 5745 } 5746 5747 5748 status_t 5749 _kern_access(const char *path, int mode) 5750 { 5751 KPath pathBuffer(path, false, B_PATH_NAME_LENGTH + 1); 5752 if (pathBuffer.InitCheck() != B_OK) 5753 return B_NO_MEMORY; 5754 5755 return common_access(pathBuffer.LockBuffer(), mode, true); 5756 } 5757 5758 5759 /** \brief Reads stat data of an entity specified by a FD + path pair. 5760 * 5761 * If only \a fd is given, the stat operation associated with the type 5762 * of the FD (node, attr, attr dir etc.) is performed. If only \a path is 5763 * given, this path identifies the entry for whose node to retrieve the 5764 * stat data. If both \a fd and \a path are given and the path is absolute, 5765 * \a fd is ignored; a relative path is reckoned off of the directory (!) 5766 * identified by \a fd and specifies the entry whose stat data shall be 5767 * retrieved. 5768 * 5769 * \param fd The FD. May be < 0. 5770 * \param path The absolute or relative path. Must not be \c NULL. 5771 * \param traverseLeafLink If \a path is given, \c true specifies that the 5772 * function shall not stick to symlinks, but traverse them. 5773 * \param stat The buffer the stat data shall be written into. 5774 * \param statSize The size of the supplied stat buffer. 5775 * \return \c B_OK, if the the stat data have been read successfully, another 5776 * error code otherwise. 5777 */ 5778 5779 status_t 5780 _kern_read_stat(int fd, const char *path, bool traverseLeafLink, 5781 struct stat *stat, size_t statSize) 5782 { 5783 struct stat completeStat; 5784 struct stat *originalStat = NULL; 5785 status_t status; 5786 5787 if (statSize > sizeof(struct stat)) 5788 return B_BAD_VALUE; 5789 5790 // this supports different stat extensions 5791 if (statSize < sizeof(struct stat)) { 5792 originalStat = stat; 5793 stat = &completeStat; 5794 } 5795 5796 if (path) { 5797 // path given: get the stat of the node referred to by (fd, path) 5798 KPath pathBuffer(path, false, B_PATH_NAME_LENGTH + 1); 5799 if (pathBuffer.InitCheck() != B_OK) 5800 return B_NO_MEMORY; 5801 5802 status = common_path_read_stat(fd, pathBuffer.LockBuffer(), 5803 traverseLeafLink, stat, true); 5804 } else { 5805 // no path given: get the FD and use the FD operation 5806 struct file_descriptor *descriptor 5807 = get_fd(get_current_io_context(true), fd); 5808 if (descriptor == NULL) 5809 return B_FILE_ERROR; 5810 5811 if (descriptor->ops->fd_read_stat) 5812 status = descriptor->ops->fd_read_stat(descriptor, stat); 5813 else 5814 status = EOPNOTSUPP; 5815 5816 put_fd(descriptor); 5817 } 5818 5819 if (status == B_OK && originalStat != NULL) 5820 memcpy(originalStat, stat, statSize); 5821 5822 return status; 5823 } 5824 5825 5826 /** \brief Writes stat data of an entity specified by a FD + path pair. 5827 * 5828 * If only \a fd is given, the stat operation associated with the type 5829 * of the FD (node, attr, attr dir etc.) is performed. If only \a path is 5830 * given, this path identifies the entry for whose node to write the 5831 * stat data. If both \a fd and \a path are given and the path is absolute, 5832 * \a fd is ignored; a relative path is reckoned off of the directory (!) 5833 * identified by \a fd and specifies the entry whose stat data shall be 5834 * written. 5835 * 5836 * \param fd The FD. May be < 0. 5837 * \param path The absolute or relative path. Must not be \c NULL. 5838 * \param traverseLeafLink If \a path is given, \c true specifies that the 5839 * function shall not stick to symlinks, but traverse them. 5840 * \param stat The buffer containing the stat data to be written. 5841 * \param statSize The size of the supplied stat buffer. 5842 * \param statMask A mask specifying which parts of the stat data shall be 5843 * written. 5844 * \return \c B_OK, if the the stat data have been written successfully, 5845 * another error code otherwise. 5846 */ 5847 5848 status_t 5849 _kern_write_stat(int fd, const char *path, bool traverseLeafLink, 5850 const struct stat *stat, size_t statSize, int statMask) 5851 { 5852 struct stat completeStat; 5853 5854 if (statSize > sizeof(struct stat)) 5855 return B_BAD_VALUE; 5856 5857 // this supports different stat extensions 5858 if (statSize < sizeof(struct stat)) { 5859 memset((uint8 *)&completeStat + statSize, 0, sizeof(struct stat) - statSize); 5860 memcpy(&completeStat, stat, statSize); 5861 stat = &completeStat; 5862 } 5863 5864 status_t status; 5865 5866 if (path) { 5867 // path given: write the stat of the node referred to by (fd, path) 5868 KPath pathBuffer(path, false, B_PATH_NAME_LENGTH + 1); 5869 if (pathBuffer.InitCheck() != B_OK) 5870 return B_NO_MEMORY; 5871 5872 status = common_path_write_stat(fd, pathBuffer.LockBuffer(), 5873 traverseLeafLink, stat, statMask, true); 5874 } else { 5875 // no path given: get the FD and use the FD operation 5876 struct file_descriptor *descriptor 5877 = get_fd(get_current_io_context(true), fd); 5878 if (descriptor == NULL) 5879 return B_FILE_ERROR; 5880 5881 if (descriptor->ops->fd_write_stat) 5882 status = descriptor->ops->fd_write_stat(descriptor, stat, statMask); 5883 else 5884 status = EOPNOTSUPP; 5885 5886 put_fd(descriptor); 5887 } 5888 5889 return status; 5890 } 5891 5892 5893 int 5894 _kern_open_attr_dir(int fd, const char *path) 5895 { 5896 KPath pathBuffer(B_PATH_NAME_LENGTH + 1); 5897 if (pathBuffer.InitCheck() != B_OK) 5898 return B_NO_MEMORY; 5899 5900 if (path != NULL) 5901 pathBuffer.SetTo(path); 5902 5903 return attr_dir_open(fd, path ? pathBuffer.LockBuffer() : NULL, true); 5904 } 5905 5906 5907 int 5908 _kern_create_attr(int fd, const char *name, uint32 type, int openMode) 5909 { 5910 return attr_create(fd, name, type, openMode, true); 5911 } 5912 5913 5914 int 5915 _kern_open_attr(int fd, const char *name, int openMode) 5916 { 5917 return attr_open(fd, name, openMode, true); 5918 } 5919 5920 5921 status_t 5922 _kern_remove_attr(int fd, const char *name) 5923 { 5924 return attr_remove(fd, name, true); 5925 } 5926 5927 5928 status_t 5929 _kern_rename_attr(int fromFile, const char *fromName, int toFile, const char *toName) 5930 { 5931 return attr_rename(fromFile, fromName, toFile, toName, true); 5932 } 5933 5934 5935 int 5936 _kern_open_index_dir(dev_t device) 5937 { 5938 return index_dir_open(device, true); 5939 } 5940 5941 5942 status_t 5943 _kern_create_index(dev_t device, const char *name, uint32 type, uint32 flags) 5944 { 5945 return index_create(device, name, type, flags, true); 5946 } 5947 5948 5949 status_t 5950 _kern_read_index_stat(dev_t device, const char *name, struct stat *stat) 5951 { 5952 return index_name_read_stat(device, name, stat, true); 5953 } 5954 5955 5956 status_t 5957 _kern_remove_index(dev_t device, const char *name) 5958 { 5959 return index_remove(device, name, true); 5960 } 5961 5962 5963 status_t 5964 _kern_getcwd(char *buffer, size_t size) 5965 { 5966 PRINT(("_kern_getcwd: buf %p, %ld\n", buffer, size)); 5967 5968 // Call vfs to get current working directory 5969 return get_cwd(buffer, size, true); 5970 } 5971 5972 5973 status_t 5974 _kern_setcwd(int fd, const char *path) 5975 { 5976 KPath pathBuffer(B_PATH_NAME_LENGTH + 1); 5977 if (pathBuffer.InitCheck() != B_OK) 5978 return B_NO_MEMORY; 5979 5980 if (path != NULL) 5981 pathBuffer.SetTo(path); 5982 5983 return set_cwd(fd, path != NULL ? pathBuffer.LockBuffer() : NULL, true); 5984 } 5985 5986 5987 // #pragma mark - 5988 // Calls from userland (with extra address checks) 5989 5990 5991 status_t 5992 _user_mount(const char *userPath, const char *userDevice, const char *userFileSystem, 5993 uint32 flags, const char *userArgs) 5994 { 5995 char fileSystem[B_OS_NAME_LENGTH]; 5996 KPath path, device; 5997 char *args = NULL; 5998 status_t status; 5999 6000 if (!IS_USER_ADDRESS(userPath) 6001 || !IS_USER_ADDRESS(userFileSystem) 6002 || !IS_USER_ADDRESS(userDevice)) 6003 return B_BAD_ADDRESS; 6004 6005 if (path.InitCheck() != B_OK || device.InitCheck() != B_OK) 6006 return B_NO_MEMORY; 6007 6008 if (user_strlcpy(path.LockBuffer(), userPath, B_PATH_NAME_LENGTH) < B_OK) 6009 return B_BAD_ADDRESS; 6010 6011 if (userFileSystem != NULL 6012 && user_strlcpy(fileSystem, userFileSystem, sizeof(fileSystem)) < B_OK) 6013 return B_BAD_ADDRESS; 6014 6015 if (userDevice != NULL 6016 && user_strlcpy(device.LockBuffer(), userDevice, B_PATH_NAME_LENGTH) < B_OK) 6017 return B_BAD_ADDRESS; 6018 6019 if (userArgs != NULL) { 6020 // We have no real length restriction, so we need to create 6021 // a buffer large enough to hold the argument string 6022 // ToDo: we could think about determinung the length of the string 6023 // in userland :) 6024 ssize_t length = user_strlcpy(args, userArgs, 0); 6025 if (length < B_OK) 6026 return B_BAD_ADDRESS; 6027 6028 // this is a safety restriction 6029 if (length > 32 * 1024) 6030 return B_NAME_TOO_LONG; 6031 6032 if (length > 0) { 6033 args = (char *)malloc(length + 1); 6034 if (args == NULL) 6035 return B_NO_MEMORY; 6036 6037 if (user_strlcpy(args, userArgs, length + 1) < B_OK) { 6038 free(args); 6039 return B_BAD_ADDRESS; 6040 } 6041 } 6042 } 6043 path.UnlockBuffer(); 6044 device.UnlockBuffer(); 6045 6046 status = fs_mount(path.LockBuffer(), userDevice != NULL ? device.Path() : NULL, 6047 userFileSystem ? fileSystem : NULL, flags, args, false); 6048 6049 free(args); 6050 return status; 6051 } 6052 6053 6054 status_t 6055 _user_unmount(const char *userPath, uint32 flags) 6056 { 6057 KPath pathBuffer(B_PATH_NAME_LENGTH + 1); 6058 if (pathBuffer.InitCheck() != B_OK) 6059 return B_NO_MEMORY; 6060 6061 char *path = pathBuffer.LockBuffer(); 6062 6063 if (user_strlcpy(path, userPath, B_PATH_NAME_LENGTH) < B_OK) 6064 return B_BAD_ADDRESS; 6065 6066 return fs_unmount(path, flags, false); 6067 } 6068 6069 6070 status_t 6071 _user_read_fs_info(dev_t device, struct fs_info *userInfo) 6072 { 6073 struct fs_info info; 6074 status_t status; 6075 6076 if (userInfo == NULL) 6077 return B_BAD_VALUE; 6078 6079 if (!IS_USER_ADDRESS(userInfo)) 6080 return B_BAD_ADDRESS; 6081 6082 status = fs_read_info(device, &info); 6083 if (status != B_OK) 6084 return status; 6085 6086 if (user_memcpy(userInfo, &info, sizeof(struct fs_info)) < B_OK) 6087 return B_BAD_ADDRESS; 6088 6089 return B_OK; 6090 } 6091 6092 6093 status_t 6094 _user_write_fs_info(dev_t device, const struct fs_info *userInfo, int mask) 6095 { 6096 struct fs_info info; 6097 6098 if (userInfo == NULL) 6099 return B_BAD_VALUE; 6100 6101 if (!IS_USER_ADDRESS(userInfo) 6102 || user_memcpy(&info, userInfo, sizeof(struct fs_info)) < B_OK) 6103 return B_BAD_ADDRESS; 6104 6105 return fs_write_info(device, &info, mask); 6106 } 6107 6108 6109 dev_t 6110 _user_next_device(int32 *_userCookie) 6111 { 6112 int32 cookie; 6113 dev_t device; 6114 6115 if (!IS_USER_ADDRESS(_userCookie) 6116 || user_memcpy(&cookie, _userCookie, sizeof(int32)) < B_OK) 6117 return B_BAD_ADDRESS; 6118 6119 device = fs_next_device(&cookie); 6120 6121 if (device >= B_OK) { 6122 // update user cookie 6123 if (user_memcpy(_userCookie, &cookie, sizeof(int32)) < B_OK) 6124 return B_BAD_ADDRESS; 6125 } 6126 6127 return device; 6128 } 6129 6130 6131 status_t 6132 _user_sync(void) 6133 { 6134 return _kern_sync(); 6135 } 6136 6137 6138 status_t 6139 _user_entry_ref_to_path(dev_t device, ino_t inode, const char *leaf, 6140 char *userPath, size_t pathLength) 6141 { 6142 char path[B_PATH_NAME_LENGTH + 1]; 6143 struct vnode *vnode; 6144 status_t status; 6145 6146 if (!IS_USER_ADDRESS(userPath)) 6147 return B_BAD_ADDRESS; 6148 6149 // copy the leaf name onto the stack 6150 char stackLeaf[B_FILE_NAME_LENGTH]; 6151 if (leaf) { 6152 if (!IS_USER_ADDRESS(leaf)) 6153 return B_BAD_ADDRESS; 6154 6155 int len = user_strlcpy(stackLeaf, leaf, B_FILE_NAME_LENGTH); 6156 if (len < 0) 6157 return len; 6158 if (len >= B_FILE_NAME_LENGTH) 6159 return B_NAME_TOO_LONG; 6160 leaf = stackLeaf; 6161 6162 // filter invalid leaf names 6163 if (leaf[0] == '\0' || strchr(leaf, '/')) 6164 return B_BAD_VALUE; 6165 } 6166 6167 // get the vnode matching the dir's node_ref 6168 if (leaf && (strcmp(leaf, ".") == 0 || strcmp(leaf, "..") == 0)) { 6169 // special cases "." and "..": we can directly get the vnode of the 6170 // referenced directory 6171 status = entry_ref_to_vnode(device, inode, leaf, &vnode); 6172 leaf = NULL; 6173 } else 6174 status = get_vnode(device, inode, &vnode, false); 6175 if (status < B_OK) 6176 return status; 6177 6178 // get the directory path 6179 status = dir_vnode_to_path(vnode, path, sizeof(path)); 6180 put_vnode(vnode); 6181 // we don't need the vnode anymore 6182 if (status < B_OK) 6183 return status; 6184 6185 // append the leaf name 6186 if (leaf) { 6187 // insert a directory separator if this is not the file system root 6188 if ((strcmp(path, "/") && strlcat(path, "/", sizeof(path)) >= sizeof(path)) 6189 || strlcat(path, leaf, sizeof(path)) >= sizeof(path)) { 6190 return B_NAME_TOO_LONG; 6191 } 6192 } 6193 6194 int len = user_strlcpy(userPath, path, pathLength); 6195 if (len < 0) 6196 return len; 6197 if (len >= (int)pathLength) 6198 return B_BUFFER_OVERFLOW; 6199 return B_OK; 6200 } 6201 6202 6203 int 6204 _user_open_entry_ref(dev_t device, ino_t inode, const char *userName, 6205 int openMode, int perms) 6206 { 6207 char name[B_FILE_NAME_LENGTH]; 6208 int status; 6209 6210 if (!IS_USER_ADDRESS(userName)) 6211 return B_BAD_ADDRESS; 6212 6213 status = user_strlcpy(name, userName, sizeof(name)); 6214 if (status < B_OK) 6215 return status; 6216 6217 if (openMode & O_CREAT) 6218 return file_create_entry_ref(device, inode, name, openMode, perms, false); 6219 6220 return file_open_entry_ref(device, inode, name, openMode, false); 6221 } 6222 6223 6224 int 6225 _user_open(int fd, const char *userPath, int openMode, int perms) 6226 { 6227 char path[B_PATH_NAME_LENGTH + 1]; 6228 int status; 6229 6230 if (!IS_USER_ADDRESS(userPath)) 6231 return B_BAD_ADDRESS; 6232 6233 status = user_strlcpy(path, userPath, B_PATH_NAME_LENGTH); 6234 if (status < 0) 6235 return status; 6236 6237 if (openMode & O_CREAT) 6238 return file_create(fd, path, openMode, perms, false); 6239 6240 return file_open(fd, path, openMode, false); 6241 } 6242 6243 6244 int 6245 _user_open_dir_entry_ref(dev_t device, ino_t inode, const char *uname) 6246 { 6247 if (uname) { 6248 char name[B_FILE_NAME_LENGTH]; 6249 6250 if (!IS_USER_ADDRESS(uname)) 6251 return B_BAD_ADDRESS; 6252 6253 int status = user_strlcpy(name, uname, sizeof(name)); 6254 if (status < B_OK) 6255 return status; 6256 6257 return dir_open_entry_ref(device, inode, name, false); 6258 } 6259 return dir_open_entry_ref(device, inode, NULL, false); 6260 } 6261 6262 6263 int 6264 _user_open_dir(int fd, const char *userPath) 6265 { 6266 char path[B_PATH_NAME_LENGTH + 1]; 6267 int status; 6268 6269 if (!IS_USER_ADDRESS(userPath)) 6270 return B_BAD_ADDRESS; 6271 6272 status = user_strlcpy(path, userPath, B_PATH_NAME_LENGTH); 6273 if (status < 0) 6274 return status; 6275 6276 return dir_open(fd, path, false); 6277 } 6278 6279 6280 /** \brief Opens a directory's parent directory and returns the entry name 6281 * of the former. 6282 * 6283 * Aside from that is returns the directory's entry name, this method is 6284 * equivalent to \code _user_open_dir(fd, "..") \endcode. It really is 6285 * equivalent, if \a userName is \c NULL. 6286 * 6287 * If a name buffer is supplied and the name does not fit the buffer, the 6288 * function fails. A buffer of size \c B_FILE_NAME_LENGTH should be safe. 6289 * 6290 * \param fd A FD referring to a directory. 6291 * \param userName Buffer the directory's entry name shall be written into. 6292 * May be \c NULL. 6293 * \param nameLength Size of the name buffer. 6294 * \return The file descriptor of the opened parent directory, if everything 6295 * went fine, an error code otherwise. 6296 */ 6297 6298 int 6299 _user_open_parent_dir(int fd, char *userName, size_t nameLength) 6300 { 6301 bool kernel = false; 6302 6303 if (userName && !IS_USER_ADDRESS(userName)) 6304 return B_BAD_ADDRESS; 6305 6306 // open the parent dir 6307 int parentFD = dir_open(fd, "..", kernel); 6308 if (parentFD < 0) 6309 return parentFD; 6310 FDCloser fdCloser(parentFD, kernel); 6311 6312 if (userName) { 6313 // get the vnodes 6314 struct vnode *parentVNode = get_vnode_from_fd(parentFD, kernel); 6315 struct vnode *dirVNode = get_vnode_from_fd(fd, kernel); 6316 VNodePutter parentVNodePutter(parentVNode); 6317 VNodePutter dirVNodePutter(dirVNode); 6318 if (!parentVNode || !dirVNode) 6319 return B_FILE_ERROR; 6320 6321 // get the vnode name 6322 char name[B_FILE_NAME_LENGTH]; 6323 status_t status = get_vnode_name(dirVNode, parentVNode, 6324 name, sizeof(name)); 6325 if (status != B_OK) 6326 return status; 6327 6328 // copy the name to the userland buffer 6329 int len = user_strlcpy(userName, name, nameLength); 6330 if (len < 0) 6331 return len; 6332 if (len >= (int)nameLength) 6333 return B_BUFFER_OVERFLOW; 6334 } 6335 6336 return fdCloser.Detach(); 6337 } 6338 6339 6340 status_t 6341 _user_fcntl(int fd, int op, uint32 argument) 6342 { 6343 return common_fcntl(fd, op, argument, false); 6344 } 6345 6346 6347 status_t 6348 _user_fsync(int fd) 6349 { 6350 return common_sync(fd, false); 6351 } 6352 6353 6354 status_t 6355 _user_lock_node(int fd) 6356 { 6357 return common_lock_node(fd, false); 6358 } 6359 6360 6361 status_t 6362 _user_unlock_node(int fd) 6363 { 6364 return common_unlock_node(fd, false); 6365 } 6366 6367 6368 status_t 6369 _user_create_dir_entry_ref(dev_t device, ino_t inode, const char *userName, int perms) 6370 { 6371 char name[B_FILE_NAME_LENGTH]; 6372 status_t status; 6373 6374 if (!IS_USER_ADDRESS(userName)) 6375 return B_BAD_ADDRESS; 6376 6377 status = user_strlcpy(name, userName, sizeof(name)); 6378 if (status < 0) 6379 return status; 6380 6381 return dir_create_entry_ref(device, inode, name, perms, false); 6382 } 6383 6384 6385 status_t 6386 _user_create_dir(int fd, const char *userPath, int perms) 6387 { 6388 char path[B_PATH_NAME_LENGTH + 1]; 6389 status_t status; 6390 6391 if (!IS_USER_ADDRESS(userPath)) 6392 return B_BAD_ADDRESS; 6393 6394 status = user_strlcpy(path, userPath, B_PATH_NAME_LENGTH); 6395 if (status < 0) 6396 return status; 6397 6398 return dir_create(fd, path, perms, false); 6399 } 6400 6401 6402 status_t 6403 _user_remove_dir(const char *userPath) 6404 { 6405 char path[B_PATH_NAME_LENGTH + 1]; 6406 status_t status; 6407 6408 if (!IS_USER_ADDRESS(userPath)) 6409 return B_BAD_ADDRESS; 6410 6411 status = user_strlcpy(path, userPath, B_PATH_NAME_LENGTH); 6412 if (status < 0) 6413 return status; 6414 6415 return dir_remove(path, false); 6416 } 6417 6418 6419 status_t 6420 _user_read_link(int fd, const char *userPath, char *userBuffer, size_t *userBufferSize) 6421 { 6422 char path[B_PATH_NAME_LENGTH + 1]; 6423 char buffer[B_PATH_NAME_LENGTH]; 6424 size_t bufferSize; 6425 status_t status; 6426 6427 if (!IS_USER_ADDRESS(userBuffer) || !IS_USER_ADDRESS(userBufferSize) 6428 || user_memcpy(&bufferSize, userBufferSize, sizeof(size_t)) < B_OK) 6429 return B_BAD_ADDRESS; 6430 6431 if (userPath) { 6432 if (!IS_USER_ADDRESS(userPath)) 6433 return B_BAD_ADDRESS; 6434 6435 status = user_strlcpy(path, userPath, B_PATH_NAME_LENGTH); 6436 if (status < 0) 6437 return status; 6438 6439 if (bufferSize > B_PATH_NAME_LENGTH) 6440 bufferSize = B_PATH_NAME_LENGTH; 6441 } 6442 6443 status = common_read_link(fd, userPath ? path : NULL, buffer, &bufferSize, false); 6444 6445 // we also update the bufferSize in case of errors 6446 // (the real length will be returned in case of B_BUFFER_OVERFLOW) 6447 if (user_memcpy(userBufferSize, &bufferSize, sizeof(size_t)) < B_OK) 6448 return B_BAD_ADDRESS; 6449 6450 if (status < B_OK) 6451 return status; 6452 6453 if (user_strlcpy(userBuffer, buffer, bufferSize) < 0) 6454 return B_BAD_ADDRESS; 6455 6456 return B_OK; 6457 } 6458 6459 6460 status_t 6461 _user_write_link(const char *userPath, const char *userToPath) 6462 { 6463 char path[B_PATH_NAME_LENGTH + 1]; 6464 char toPath[B_PATH_NAME_LENGTH + 1]; 6465 status_t status; 6466 6467 if (!IS_USER_ADDRESS(userPath) 6468 || !IS_USER_ADDRESS(userToPath)) 6469 return B_BAD_ADDRESS; 6470 6471 status = user_strlcpy(path, userPath, B_PATH_NAME_LENGTH); 6472 if (status < 0) 6473 return status; 6474 6475 status = user_strlcpy(toPath, userToPath, B_PATH_NAME_LENGTH); 6476 if (status < 0) 6477 return status; 6478 6479 status = check_path(toPath); 6480 if (status < B_OK) 6481 return status; 6482 6483 return common_write_link(path, toPath, false); 6484 } 6485 6486 6487 status_t 6488 _user_create_symlink(int fd, const char *userPath, const char *userToPath, 6489 int mode) 6490 { 6491 char path[B_PATH_NAME_LENGTH + 1]; 6492 char toPath[B_PATH_NAME_LENGTH + 1]; 6493 status_t status; 6494 6495 if (!IS_USER_ADDRESS(userPath) 6496 || !IS_USER_ADDRESS(userToPath)) 6497 return B_BAD_ADDRESS; 6498 6499 status = user_strlcpy(path, userPath, B_PATH_NAME_LENGTH); 6500 if (status < 0) 6501 return status; 6502 6503 status = user_strlcpy(toPath, userToPath, B_PATH_NAME_LENGTH); 6504 if (status < 0) 6505 return status; 6506 6507 status = check_path(toPath); 6508 if (status < B_OK) 6509 return status; 6510 6511 return common_create_symlink(fd, path, toPath, mode, false); 6512 } 6513 6514 6515 status_t 6516 _user_create_link(const char *userPath, const char *userToPath) 6517 { 6518 char path[B_PATH_NAME_LENGTH + 1]; 6519 char toPath[B_PATH_NAME_LENGTH + 1]; 6520 status_t status; 6521 6522 if (!IS_USER_ADDRESS(userPath) 6523 || !IS_USER_ADDRESS(userToPath)) 6524 return B_BAD_ADDRESS; 6525 6526 status = user_strlcpy(path, userPath, B_PATH_NAME_LENGTH); 6527 if (status < 0) 6528 return status; 6529 6530 status = user_strlcpy(toPath, userToPath, B_PATH_NAME_LENGTH); 6531 if (status < 0) 6532 return status; 6533 6534 status = check_path(toPath); 6535 if (status < B_OK) 6536 return status; 6537 6538 return common_create_link(path, toPath, false); 6539 } 6540 6541 6542 status_t 6543 _user_unlink(int fd, const char *userPath) 6544 { 6545 char path[B_PATH_NAME_LENGTH + 1]; 6546 status_t status; 6547 6548 if (!IS_USER_ADDRESS(userPath)) 6549 return B_BAD_ADDRESS; 6550 6551 status = user_strlcpy(path, userPath, B_PATH_NAME_LENGTH); 6552 if (status < 0) 6553 return status; 6554 6555 return common_unlink(fd, path, false); 6556 } 6557 6558 6559 status_t 6560 _user_rename(int oldFD, const char *userOldPath, int newFD, 6561 const char *userNewPath) 6562 { 6563 char oldPath[B_PATH_NAME_LENGTH + 1]; 6564 char newPath[B_PATH_NAME_LENGTH + 1]; 6565 status_t status; 6566 6567 if (!IS_USER_ADDRESS(userOldPath) || !IS_USER_ADDRESS(userNewPath)) 6568 return B_BAD_ADDRESS; 6569 6570 status = user_strlcpy(oldPath, userOldPath, B_PATH_NAME_LENGTH); 6571 if (status < 0) 6572 return status; 6573 6574 status = user_strlcpy(newPath, userNewPath, B_PATH_NAME_LENGTH); 6575 if (status < 0) 6576 return status; 6577 6578 return common_rename(oldFD, oldPath, newFD, newPath, false); 6579 } 6580 6581 6582 status_t 6583 _user_access(const char *userPath, int mode) 6584 { 6585 char path[B_PATH_NAME_LENGTH + 1]; 6586 status_t status; 6587 6588 if (!IS_USER_ADDRESS(userPath)) 6589 return B_BAD_ADDRESS; 6590 6591 status = user_strlcpy(path, userPath, B_PATH_NAME_LENGTH); 6592 if (status < 0) 6593 return status; 6594 6595 return common_access(path, mode, false); 6596 } 6597 6598 6599 status_t 6600 _user_read_stat(int fd, const char *userPath, bool traverseLink, 6601 struct stat *userStat, size_t statSize) 6602 { 6603 struct stat stat; 6604 status_t status; 6605 6606 if (statSize > sizeof(struct stat)) 6607 return B_BAD_VALUE; 6608 6609 if (!IS_USER_ADDRESS(userStat)) 6610 return B_BAD_ADDRESS; 6611 6612 if (userPath) { 6613 // path given: get the stat of the node referred to by (fd, path) 6614 char path[B_PATH_NAME_LENGTH + 1]; 6615 if (!IS_USER_ADDRESS(userPath)) 6616 return B_BAD_ADDRESS; 6617 int len = user_strlcpy(path, userPath, B_PATH_NAME_LENGTH); 6618 if (len < 0) 6619 return len; 6620 if (len >= B_PATH_NAME_LENGTH) 6621 return B_NAME_TOO_LONG; 6622 6623 status = common_path_read_stat(fd, path, traverseLink, &stat, false); 6624 } else { 6625 // no path given: get the FD and use the FD operation 6626 struct file_descriptor *descriptor 6627 = get_fd(get_current_io_context(false), fd); 6628 if (descriptor == NULL) 6629 return B_FILE_ERROR; 6630 6631 if (descriptor->ops->fd_read_stat) 6632 status = descriptor->ops->fd_read_stat(descriptor, &stat); 6633 else 6634 status = EOPNOTSUPP; 6635 6636 put_fd(descriptor); 6637 } 6638 6639 if (status < B_OK) 6640 return status; 6641 6642 return user_memcpy(userStat, &stat, statSize); 6643 } 6644 6645 6646 status_t 6647 _user_write_stat(int fd, const char *userPath, bool traverseLeafLink, 6648 const struct stat *userStat, size_t statSize, int statMask) 6649 { 6650 char path[B_PATH_NAME_LENGTH + 1]; 6651 struct stat stat; 6652 6653 if (statSize > sizeof(struct stat)) 6654 return B_BAD_VALUE; 6655 6656 if (!IS_USER_ADDRESS(userStat) 6657 || user_memcpy(&stat, userStat, statSize) < B_OK) 6658 return B_BAD_ADDRESS; 6659 6660 // clear additional stat fields 6661 if (statSize < sizeof(struct stat)) 6662 memset((uint8 *)&stat + statSize, 0, sizeof(struct stat) - statSize); 6663 6664 status_t status; 6665 6666 if (userPath) { 6667 // path given: write the stat of the node referred to by (fd, path) 6668 if (!IS_USER_ADDRESS(userPath)) 6669 return B_BAD_ADDRESS; 6670 int len = user_strlcpy(path, userPath, B_PATH_NAME_LENGTH); 6671 if (len < 0) 6672 return len; 6673 if (len >= B_PATH_NAME_LENGTH) 6674 return B_NAME_TOO_LONG; 6675 6676 status = common_path_write_stat(fd, path, traverseLeafLink, &stat, 6677 statMask, false); 6678 } else { 6679 // no path given: get the FD and use the FD operation 6680 struct file_descriptor *descriptor 6681 = get_fd(get_current_io_context(false), fd); 6682 if (descriptor == NULL) 6683 return B_FILE_ERROR; 6684 6685 if (descriptor->ops->fd_write_stat) 6686 status = descriptor->ops->fd_write_stat(descriptor, &stat, statMask); 6687 else 6688 status = EOPNOTSUPP; 6689 6690 put_fd(descriptor); 6691 } 6692 6693 return status; 6694 } 6695 6696 6697 int 6698 _user_open_attr_dir(int fd, const char *userPath) 6699 { 6700 char pathBuffer[B_PATH_NAME_LENGTH + 1]; 6701 6702 if (userPath != NULL) { 6703 if (!IS_USER_ADDRESS(userPath) 6704 || user_strlcpy(pathBuffer, userPath, B_PATH_NAME_LENGTH) < B_OK) 6705 return B_BAD_ADDRESS; 6706 } 6707 6708 return attr_dir_open(fd, userPath ? pathBuffer : NULL, false); 6709 } 6710 6711 6712 int 6713 _user_create_attr(int fd, const char *userName, uint32 type, int openMode) 6714 { 6715 char name[B_FILE_NAME_LENGTH]; 6716 6717 if (!IS_USER_ADDRESS(userName) 6718 || user_strlcpy(name, userName, B_FILE_NAME_LENGTH) < B_OK) 6719 return B_BAD_ADDRESS; 6720 6721 return attr_create(fd, name, type, openMode, false); 6722 } 6723 6724 6725 int 6726 _user_open_attr(int fd, const char *userName, int openMode) 6727 { 6728 char name[B_FILE_NAME_LENGTH]; 6729 6730 if (!IS_USER_ADDRESS(userName) 6731 || user_strlcpy(name, userName, B_FILE_NAME_LENGTH) < B_OK) 6732 return B_BAD_ADDRESS; 6733 6734 return attr_open(fd, name, openMode, false); 6735 } 6736 6737 6738 status_t 6739 _user_remove_attr(int fd, const char *userName) 6740 { 6741 char name[B_FILE_NAME_LENGTH]; 6742 6743 if (!IS_USER_ADDRESS(userName) 6744 || user_strlcpy(name, userName, B_FILE_NAME_LENGTH) < B_OK) 6745 return B_BAD_ADDRESS; 6746 6747 return attr_remove(fd, name, false); 6748 } 6749 6750 6751 status_t 6752 _user_rename_attr(int fromFile, const char *userFromName, int toFile, const char *userToName) 6753 { 6754 char fromName[B_FILE_NAME_LENGTH]; 6755 char toName[B_FILE_NAME_LENGTH]; 6756 6757 if (!IS_USER_ADDRESS(userFromName) 6758 || !IS_USER_ADDRESS(userToName)) 6759 return B_BAD_ADDRESS; 6760 6761 if (user_strlcpy(fromName, userFromName, B_FILE_NAME_LENGTH) < B_OK 6762 || user_strlcpy(toName, userToName, B_FILE_NAME_LENGTH) < B_OK) 6763 return B_BAD_ADDRESS; 6764 6765 return attr_rename(fromFile, fromName, toFile, toName, false); 6766 } 6767 6768 6769 int 6770 _user_open_index_dir(dev_t device) 6771 { 6772 return index_dir_open(device, false); 6773 } 6774 6775 6776 status_t 6777 _user_create_index(dev_t device, const char *userName, uint32 type, uint32 flags) 6778 { 6779 char name[B_FILE_NAME_LENGTH]; 6780 6781 if (!IS_USER_ADDRESS(userName) 6782 || user_strlcpy(name, userName, B_FILE_NAME_LENGTH) < B_OK) 6783 return B_BAD_ADDRESS; 6784 6785 return index_create(device, name, type, flags, false); 6786 } 6787 6788 6789 status_t 6790 _user_read_index_stat(dev_t device, const char *userName, struct stat *userStat) 6791 { 6792 char name[B_FILE_NAME_LENGTH]; 6793 struct stat stat; 6794 status_t status; 6795 6796 if (!IS_USER_ADDRESS(userName) 6797 || !IS_USER_ADDRESS(userStat) 6798 || user_strlcpy(name, userName, B_FILE_NAME_LENGTH) < B_OK) 6799 return B_BAD_ADDRESS; 6800 6801 status = index_name_read_stat(device, name, &stat, false); 6802 if (status == B_OK) { 6803 if (user_memcpy(userStat, &stat, sizeof(stat)) < B_OK) 6804 return B_BAD_ADDRESS; 6805 } 6806 6807 return status; 6808 } 6809 6810 6811 status_t 6812 _user_remove_index(dev_t device, const char *userName) 6813 { 6814 char name[B_FILE_NAME_LENGTH]; 6815 6816 if (!IS_USER_ADDRESS(userName) 6817 || user_strlcpy(name, userName, B_FILE_NAME_LENGTH) < B_OK) 6818 return B_BAD_ADDRESS; 6819 6820 return index_remove(device, name, false); 6821 } 6822 6823 6824 status_t 6825 _user_getcwd(char *userBuffer, size_t size) 6826 { 6827 char buffer[B_PATH_NAME_LENGTH]; 6828 status_t status; 6829 6830 PRINT(("user_getcwd: buf %p, %ld\n", userBuffer, size)); 6831 6832 if (!IS_USER_ADDRESS(userBuffer)) 6833 return B_BAD_ADDRESS; 6834 6835 if (size > B_PATH_NAME_LENGTH) 6836 size = B_PATH_NAME_LENGTH; 6837 6838 status = get_cwd(buffer, size, false); 6839 if (status < 0) 6840 return status; 6841 6842 // Copy back the result 6843 if (user_strlcpy(userBuffer, buffer, size) < B_OK) 6844 return B_BAD_ADDRESS; 6845 6846 return status; 6847 } 6848 6849 6850 status_t 6851 _user_setcwd(int fd, const char *userPath) 6852 { 6853 char path[B_PATH_NAME_LENGTH]; 6854 6855 PRINT(("user_setcwd: path = %p\n", userPath)); 6856 6857 if (userPath != NULL) { 6858 if (!IS_USER_ADDRESS(userPath) 6859 || user_strlcpy(path, userPath, B_PATH_NAME_LENGTH) < B_OK) 6860 return B_BAD_ADDRESS; 6861 } 6862 6863 return set_cwd(fd, userPath != NULL ? path : NULL, false); 6864 } 6865 6866 6867 int 6868 _user_open_query(dev_t device, const char *userQuery, size_t queryLength, 6869 uint32 flags, port_id port, int32 token) 6870 { 6871 char *query; 6872 6873 if (device < 0 || userQuery == NULL || queryLength == 0 || queryLength >= 65536) 6874 return B_BAD_VALUE; 6875 6876 query = (char *)malloc(queryLength + 1); 6877 if (query == NULL) 6878 return B_NO_MEMORY; 6879 if (user_strlcpy(query, userQuery, queryLength + 1) < B_OK) { 6880 free(query); 6881 return B_BAD_ADDRESS; 6882 } 6883 6884 int fd = query_open(device, query, flags, port, token, false); 6885 6886 free(query); 6887 return fd; 6888 } 6889