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