1 /* 2 * Copyright 2005-2013, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Copyright 2002-2018, Axel Dörfler, axeld@pinc-software.de. 4 * Distributed under the terms of the MIT License. 5 * 6 * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. 7 * Distributed under the terms of the NewOS License. 8 */ 9 10 11 /*! Virtual File System and File System Interface Layer */ 12 13 14 #include <ctype.h> 15 #include <fcntl.h> 16 #include <limits.h> 17 #include <stddef.h> 18 #include <stdio.h> 19 #include <string.h> 20 #include <sys/file.h> 21 #include <sys/ioctl.h> 22 #include <sys/resource.h> 23 #include <sys/stat.h> 24 #include <unistd.h> 25 26 #include <fs_attr.h> 27 #include <fs_info.h> 28 #include <fs_interface.h> 29 #include <fs_volume.h> 30 #include <NodeMonitor.h> 31 #include <OS.h> 32 #include <StorageDefs.h> 33 34 #include <AutoDeleter.h> 35 #include <block_cache.h> 36 #include <boot/kernel_args.h> 37 #include <debug_heap.h> 38 #include <disk_device_manager/KDiskDevice.h> 39 #include <disk_device_manager/KDiskDeviceManager.h> 40 #include <disk_device_manager/KDiskDeviceUtils.h> 41 #include <disk_device_manager/KDiskSystem.h> 42 #include <fd.h> 43 #include <file_cache.h> 44 #include <fs/node_monitor.h> 45 #include <KPath.h> 46 #include <lock.h> 47 #include <low_resource_manager.h> 48 #include <slab/Slab.h> 49 #include <StackOrHeapArray.h> 50 #include <syscalls.h> 51 #include <syscall_restart.h> 52 #include <tracing.h> 53 #include <util/atomic.h> 54 #include <util/AutoLock.h> 55 #include <util/ThreadAutoLock.h> 56 #include <util/DoublyLinkedList.h> 57 #include <vfs.h> 58 #include <vm/vm.h> 59 #include <vm/VMCache.h> 60 #include <wait_for_objects.h> 61 62 #include "EntryCache.h" 63 #include "fifo.h" 64 #include "IORequest.h" 65 #include "unused_vnodes.h" 66 #include "vfs_tracing.h" 67 #include "Vnode.h" 68 #include "../cache/vnode_store.h" 69 70 71 //#define TRACE_VFS 72 #ifdef TRACE_VFS 73 # define TRACE(x) dprintf x 74 # define FUNCTION(x) dprintf x 75 #else 76 # define TRACE(x) ; 77 # define FUNCTION(x) ; 78 #endif 79 80 #define ADD_DEBUGGER_COMMANDS 81 82 83 #define HAS_FS_CALL(vnode, op) (vnode->ops->op != NULL) 84 #define HAS_FS_MOUNT_CALL(mount, op) (mount->volume->ops->op != NULL) 85 86 #if KDEBUG 87 # define FS_CALL(vnode, op, params...) \ 88 ( HAS_FS_CALL(vnode, op) ? \ 89 vnode->ops->op(vnode->mount->volume, vnode, params) \ 90 : (panic("FS_CALL op " #op " is NULL"), 0)) 91 # define FS_CALL_NO_PARAMS(vnode, op) \ 92 ( HAS_FS_CALL(vnode, op) ? \ 93 vnode->ops->op(vnode->mount->volume, vnode) \ 94 : (panic("FS_CALL_NO_PARAMS op " #op " is NULL"), 0)) 95 # define FS_MOUNT_CALL(mount, op, params...) \ 96 ( HAS_FS_MOUNT_CALL(mount, op) ? \ 97 mount->volume->ops->op(mount->volume, params) \ 98 : (panic("FS_MOUNT_CALL op " #op " is NULL"), 0)) 99 # define FS_MOUNT_CALL_NO_PARAMS(mount, op) \ 100 ( HAS_FS_MOUNT_CALL(mount, op) ? \ 101 mount->volume->ops->op(mount->volume) \ 102 : (panic("FS_MOUNT_CALL_NO_PARAMS op " #op " is NULL"), 0)) 103 #else 104 # define FS_CALL(vnode, op, params...) \ 105 vnode->ops->op(vnode->mount->volume, vnode, params) 106 # define FS_CALL_NO_PARAMS(vnode, op) \ 107 vnode->ops->op(vnode->mount->volume, vnode) 108 # define FS_MOUNT_CALL(mount, op, params...) \ 109 mount->volume->ops->op(mount->volume, params) 110 # define FS_MOUNT_CALL_NO_PARAMS(mount, op) \ 111 mount->volume->ops->op(mount->volume) 112 #endif 113 114 115 const static size_t kMaxPathLength = 65536; 116 // The absolute maximum path length (for getcwd() - this is not depending 117 // on PATH_MAX 118 119 120 typedef DoublyLinkedList<vnode> VnodeList; 121 122 /*! \brief Structure to manage a mounted file system 123 124 Note: The root_vnode and root_vnode->covers fields (what others?) are 125 initialized in fs_mount() and not changed afterwards. That is as soon 126 as the mount is mounted and it is made sure it won't be unmounted 127 (e.g. by holding a reference to a vnode of that mount) (read) access 128 to those fields is always safe, even without additional locking. Morever 129 while mounted the mount holds a reference to the root_vnode->covers vnode, 130 and thus making the access path vnode->mount->root_vnode->covers->mount->... 131 safe if a reference to vnode is held (note that for the root mount 132 root_vnode->covers is NULL, though). 133 */ 134 struct fs_mount { 135 fs_mount() 136 : 137 volume(NULL), 138 device_name(NULL) 139 { 140 mutex_init(&lock, "mount lock"); 141 } 142 143 ~fs_mount() 144 { 145 mutex_destroy(&lock); 146 free(device_name); 147 148 while (volume) { 149 fs_volume* superVolume = volume->super_volume; 150 151 if (volume->file_system != NULL) 152 put_module(volume->file_system->info.name); 153 154 free(volume->file_system_name); 155 free(volume); 156 volume = superVolume; 157 } 158 } 159 160 struct fs_mount* next; 161 dev_t id; 162 fs_volume* volume; 163 char* device_name; 164 mutex lock; // guards the vnodes list 165 struct vnode* root_vnode; 166 struct vnode* covers_vnode; // immutable 167 KPartition* partition; 168 VnodeList vnodes; 169 EntryCache entry_cache; 170 bool unmounting; 171 bool owns_file_device; 172 }; 173 174 175 namespace { 176 177 struct advisory_lock : public DoublyLinkedListLinkImpl<advisory_lock> { 178 list_link link; 179 void* bound_to; 180 team_id team; 181 pid_t session; 182 off_t start; 183 off_t end; 184 bool shared; 185 }; 186 187 typedef DoublyLinkedList<advisory_lock> LockList; 188 189 } // namespace 190 191 192 struct advisory_locking { 193 sem_id lock; 194 sem_id wait_sem; 195 LockList locks; 196 197 advisory_locking() 198 : 199 lock(-1), 200 wait_sem(-1) 201 { 202 } 203 204 ~advisory_locking() 205 { 206 if (lock >= 0) 207 delete_sem(lock); 208 if (wait_sem >= 0) 209 delete_sem(wait_sem); 210 } 211 }; 212 213 /*! \brief Guards sMountsTable. 214 215 The holder is allowed to read/write access the sMountsTable. 216 Manipulation of the fs_mount structures themselves 217 (and their destruction) requires different locks though. 218 */ 219 static rw_lock sMountLock = RW_LOCK_INITIALIZER("vfs_mount_lock"); 220 221 /*! \brief Guards mount/unmount operations. 222 223 The fs_mount() and fs_unmount() hold the lock during their whole operation. 224 That is locking the lock ensures that no FS is mounted/unmounted. In 225 particular this means that 226 - sMountsTable will not be modified, 227 - the fields immutable after initialization of the fs_mount structures in 228 sMountsTable will not be modified, 229 230 The thread trying to lock the lock must not hold sVnodeLock or 231 sMountLock. 232 */ 233 static recursive_lock sMountOpLock; 234 235 /*! \brief Guards sVnodeTable. 236 237 The holder is allowed read/write access to sVnodeTable and to 238 any unbusy vnode in that table, save to the immutable fields (device, id, 239 private_node, mount) to which only read-only access is allowed. 240 The mutable fields advisory_locking, mandatory_locked_by, and ref_count, as 241 well as the busy, removed, unused flags, and the vnode's type can also be 242 write accessed when holding a read lock to sVnodeLock *and* having the vnode 243 locked. Write access to covered_by and covers requires to write lock 244 sVnodeLock. 245 246 The thread trying to acquire the lock must not hold sMountLock. 247 You must not hold this lock when calling create_sem(), as this might call 248 vfs_free_unused_vnodes() and thus cause a deadlock. 249 */ 250 static rw_lock sVnodeLock = RW_LOCK_INITIALIZER("vfs_vnode_lock"); 251 252 /*! \brief Guards io_context::root. 253 254 Must be held when setting or getting the io_context::root field. 255 The only operation allowed while holding this lock besides getting or 256 setting the field is inc_vnode_ref_count() on io_context::root. 257 */ 258 static mutex sIOContextRootLock = MUTEX_INITIALIZER("io_context::root lock"); 259 260 261 namespace { 262 263 struct vnode_hash_key { 264 dev_t device; 265 ino_t vnode; 266 }; 267 268 struct VnodeHash { 269 typedef vnode_hash_key KeyType; 270 typedef struct vnode ValueType; 271 272 #define VHASH(mountid, vnodeid) \ 273 (((uint32)((vnodeid) >> 32) + (uint32)(vnodeid)) ^ (uint32)(mountid)) 274 275 size_t HashKey(KeyType key) const 276 { 277 return VHASH(key.device, key.vnode); 278 } 279 280 size_t Hash(ValueType* vnode) const 281 { 282 return VHASH(vnode->device, vnode->id); 283 } 284 285 #undef VHASH 286 287 bool Compare(KeyType key, ValueType* vnode) const 288 { 289 return vnode->device == key.device && vnode->id == key.vnode; 290 } 291 292 ValueType*& GetLink(ValueType* value) const 293 { 294 return value->next; 295 } 296 }; 297 298 typedef BOpenHashTable<VnodeHash> VnodeTable; 299 300 301 struct MountHash { 302 typedef dev_t KeyType; 303 typedef struct fs_mount ValueType; 304 305 size_t HashKey(KeyType key) const 306 { 307 return key; 308 } 309 310 size_t Hash(ValueType* mount) const 311 { 312 return mount->id; 313 } 314 315 bool Compare(KeyType key, ValueType* mount) const 316 { 317 return mount->id == key; 318 } 319 320 ValueType*& GetLink(ValueType* value) const 321 { 322 return value->next; 323 } 324 }; 325 326 typedef BOpenHashTable<MountHash> MountTable; 327 328 } // namespace 329 330 331 object_cache* sPathNameCache; 332 object_cache* sVnodeCache; 333 object_cache* sFileDescriptorCache; 334 335 #define VNODE_HASH_TABLE_SIZE 1024 336 static VnodeTable* sVnodeTable; 337 static struct vnode* sRoot; 338 339 #define MOUNTS_HASH_TABLE_SIZE 16 340 static MountTable* sMountsTable; 341 static dev_t sNextMountID = 1; 342 343 #define MAX_TEMP_IO_VECS 8 344 345 // How long to wait for busy vnodes (10s) 346 #define BUSY_VNODE_RETRIES 2000 347 #define BUSY_VNODE_DELAY 5000 348 349 mode_t __gUmask = 022; 350 351 /* function declarations */ 352 353 static void free_unused_vnodes(); 354 355 // file descriptor operation prototypes 356 static status_t file_read(struct file_descriptor* descriptor, off_t pos, 357 void* buffer, size_t* _bytes); 358 static status_t file_write(struct file_descriptor* descriptor, off_t pos, 359 const void* buffer, size_t* _bytes); 360 static off_t file_seek(struct file_descriptor* descriptor, off_t pos, 361 int seekType); 362 static void file_free_fd(struct file_descriptor* descriptor); 363 static status_t file_close(struct file_descriptor* descriptor); 364 static status_t file_select(struct file_descriptor* descriptor, uint8 event, 365 struct selectsync* sync); 366 static status_t file_deselect(struct file_descriptor* descriptor, uint8 event, 367 struct selectsync* sync); 368 static status_t dir_read(struct io_context* context, 369 struct file_descriptor* descriptor, struct dirent* buffer, 370 size_t bufferSize, uint32* _count); 371 static status_t dir_read(struct io_context* ioContext, struct vnode* vnode, 372 void* cookie, struct dirent* buffer, size_t bufferSize, uint32* _count); 373 static status_t dir_rewind(struct file_descriptor* descriptor); 374 static void dir_free_fd(struct file_descriptor* descriptor); 375 static status_t dir_close(struct file_descriptor* descriptor); 376 static status_t attr_dir_read(struct io_context* context, 377 struct file_descriptor* descriptor, struct dirent* buffer, 378 size_t bufferSize, uint32* _count); 379 static status_t attr_dir_rewind(struct file_descriptor* descriptor); 380 static void attr_dir_free_fd(struct file_descriptor* descriptor); 381 static status_t attr_dir_close(struct file_descriptor* descriptor); 382 static status_t attr_read(struct file_descriptor* descriptor, off_t pos, 383 void* buffer, size_t* _bytes); 384 static status_t attr_write(struct file_descriptor* descriptor, off_t pos, 385 const void* buffer, size_t* _bytes); 386 static off_t attr_seek(struct file_descriptor* descriptor, off_t pos, 387 int seekType); 388 static void attr_free_fd(struct file_descriptor* descriptor); 389 static status_t attr_close(struct file_descriptor* descriptor); 390 static status_t attr_read_stat(struct file_descriptor* descriptor, 391 struct stat* statData); 392 static status_t attr_write_stat(struct file_descriptor* descriptor, 393 const struct stat* stat, int statMask); 394 static status_t index_dir_read(struct io_context* context, 395 struct file_descriptor* descriptor, struct dirent* buffer, 396 size_t bufferSize, uint32* _count); 397 static status_t index_dir_rewind(struct file_descriptor* descriptor); 398 static void index_dir_free_fd(struct file_descriptor* descriptor); 399 static status_t index_dir_close(struct file_descriptor* descriptor); 400 static status_t query_read(struct io_context* context, 401 struct file_descriptor* descriptor, struct dirent* buffer, 402 size_t bufferSize, uint32* _count); 403 static status_t query_rewind(struct file_descriptor* descriptor); 404 static void query_free_fd(struct file_descriptor* descriptor); 405 static status_t query_close(struct file_descriptor* descriptor); 406 407 static status_t common_ioctl(struct file_descriptor* descriptor, ulong op, 408 void* buffer, size_t length); 409 static status_t common_read_stat(struct file_descriptor* descriptor, 410 struct stat* statData); 411 static status_t common_write_stat(struct file_descriptor* descriptor, 412 const struct stat* statData, int statMask); 413 static status_t common_path_read_stat(int fd, char* path, bool traverseLeafLink, 414 struct stat* stat, bool kernel); 415 416 static status_t vnode_path_to_vnode(struct vnode* vnode, char* path, 417 bool traverseLeafLink, int count, bool kernel, 418 struct vnode** _vnode, ino_t* _parentID); 419 static status_t dir_vnode_to_path(struct vnode* vnode, char* buffer, 420 size_t bufferSize, bool kernel); 421 static status_t fd_and_path_to_vnode(int fd, char* path, bool traverseLeafLink, 422 struct vnode** _vnode, ino_t* _parentID, bool kernel); 423 static void inc_vnode_ref_count(struct vnode* vnode); 424 static status_t dec_vnode_ref_count(struct vnode* vnode, bool alwaysFree, 425 bool reenter); 426 static inline void put_vnode(struct vnode* vnode); 427 static status_t fs_unmount(char* path, dev_t mountID, uint32 flags, 428 bool kernel); 429 static int open_vnode(struct vnode* vnode, int openMode, bool kernel); 430 431 432 static struct fd_ops sFileOps = { 433 file_read, 434 file_write, 435 file_seek, 436 common_ioctl, 437 NULL, // set_flags 438 file_select, 439 file_deselect, 440 NULL, // read_dir() 441 NULL, // rewind_dir() 442 common_read_stat, 443 common_write_stat, 444 file_close, 445 file_free_fd 446 }; 447 448 static struct fd_ops sDirectoryOps = { 449 NULL, // read() 450 NULL, // write() 451 NULL, // seek() 452 common_ioctl, 453 NULL, // set_flags 454 NULL, // select() 455 NULL, // deselect() 456 dir_read, 457 dir_rewind, 458 common_read_stat, 459 common_write_stat, 460 dir_close, 461 dir_free_fd 462 }; 463 464 static struct fd_ops sAttributeDirectoryOps = { 465 NULL, // read() 466 NULL, // write() 467 NULL, // seek() 468 common_ioctl, 469 NULL, // set_flags 470 NULL, // select() 471 NULL, // deselect() 472 attr_dir_read, 473 attr_dir_rewind, 474 common_read_stat, 475 common_write_stat, 476 attr_dir_close, 477 attr_dir_free_fd 478 }; 479 480 static struct fd_ops sAttributeOps = { 481 attr_read, 482 attr_write, 483 attr_seek, 484 common_ioctl, 485 NULL, // set_flags 486 NULL, // select() 487 NULL, // deselect() 488 NULL, // read_dir() 489 NULL, // rewind_dir() 490 attr_read_stat, 491 attr_write_stat, 492 attr_close, 493 attr_free_fd 494 }; 495 496 static struct fd_ops sIndexDirectoryOps = { 497 NULL, // read() 498 NULL, // write() 499 NULL, // seek() 500 NULL, // ioctl() 501 NULL, // set_flags 502 NULL, // select() 503 NULL, // deselect() 504 index_dir_read, 505 index_dir_rewind, 506 NULL, // read_stat() 507 NULL, // write_stat() 508 index_dir_close, 509 index_dir_free_fd 510 }; 511 512 #if 0 513 static struct fd_ops sIndexOps = { 514 NULL, // read() 515 NULL, // write() 516 NULL, // seek() 517 NULL, // ioctl() 518 NULL, // set_flags 519 NULL, // select() 520 NULL, // deselect() 521 NULL, // dir_read() 522 NULL, // dir_rewind() 523 index_read_stat, // read_stat() 524 NULL, // write_stat() 525 NULL, // dir_close() 526 NULL // free_fd() 527 }; 528 #endif 529 530 static struct fd_ops sQueryOps = { 531 NULL, // read() 532 NULL, // write() 533 NULL, // seek() 534 NULL, // ioctl() 535 NULL, // set_flags 536 NULL, // select() 537 NULL, // deselect() 538 query_read, 539 query_rewind, 540 NULL, // read_stat() 541 NULL, // write_stat() 542 query_close, 543 query_free_fd 544 }; 545 546 547 namespace { 548 549 class VNodePutter { 550 public: 551 VNodePutter(struct vnode* vnode = NULL) : fVNode(vnode) {} 552 553 ~VNodePutter() 554 { 555 Put(); 556 } 557 558 void SetTo(struct vnode* vnode) 559 { 560 Put(); 561 fVNode = vnode; 562 } 563 564 void Put() 565 { 566 if (fVNode) { 567 put_vnode(fVNode); 568 fVNode = NULL; 569 } 570 } 571 572 struct vnode* Detach() 573 { 574 struct vnode* vnode = fVNode; 575 fVNode = NULL; 576 return vnode; 577 } 578 579 private: 580 struct vnode* fVNode; 581 }; 582 583 584 class FDCloser { 585 public: 586 FDCloser() : fFD(-1), fKernel(true) {} 587 588 FDCloser(int fd, bool kernel) : fFD(fd), fKernel(kernel) {} 589 590 ~FDCloser() 591 { 592 Close(); 593 } 594 595 void SetTo(int fd, bool kernel) 596 { 597 Close(); 598 fFD = fd; 599 fKernel = kernel; 600 } 601 602 void Close() 603 { 604 if (fFD >= 0) { 605 if (fKernel) 606 _kern_close(fFD); 607 else 608 _user_close(fFD); 609 fFD = -1; 610 } 611 } 612 613 int Detach() 614 { 615 int fd = fFD; 616 fFD = -1; 617 return fd; 618 } 619 620 private: 621 int fFD; 622 bool fKernel; 623 }; 624 625 } // namespace 626 627 628 #if VFS_PAGES_IO_TRACING 629 630 namespace VFSPagesIOTracing { 631 632 class PagesIOTraceEntry : public AbstractTraceEntry { 633 protected: 634 PagesIOTraceEntry(struct vnode* vnode, void* cookie, off_t pos, 635 const generic_io_vec* vecs, uint32 count, uint32 flags, 636 generic_size_t bytesRequested, status_t status, 637 generic_size_t bytesTransferred) 638 : 639 fVnode(vnode), 640 fMountID(vnode->mount->id), 641 fNodeID(vnode->id), 642 fCookie(cookie), 643 fPos(pos), 644 fCount(count), 645 fFlags(flags), 646 fBytesRequested(bytesRequested), 647 fStatus(status), 648 fBytesTransferred(bytesTransferred) 649 { 650 fVecs = (generic_io_vec*)alloc_tracing_buffer_memcpy(vecs, 651 sizeof(generic_io_vec) * count, false); 652 } 653 654 void AddDump(TraceOutput& out, const char* mode) 655 { 656 out.Print("vfs pages io %5s: vnode: %p (%" B_PRId32 ", %" B_PRId64 "), " 657 "cookie: %p, pos: %" B_PRIdOFF ", size: %" B_PRIu64 ", vecs: {", 658 mode, fVnode, fMountID, fNodeID, fCookie, fPos, 659 (uint64)fBytesRequested); 660 661 if (fVecs != NULL) { 662 for (uint32 i = 0; i < fCount; i++) { 663 if (i > 0) 664 out.Print(", "); 665 out.Print("(%" B_PRIx64 ", %" B_PRIu64 ")", (uint64)fVecs[i].base, 666 (uint64)fVecs[i].length); 667 } 668 } 669 670 out.Print("}, flags: %#" B_PRIx32 " -> status: %#" B_PRIx32 ", " 671 "transferred: %" B_PRIu64, fFlags, fStatus, 672 (uint64)fBytesTransferred); 673 } 674 675 protected: 676 struct vnode* fVnode; 677 dev_t fMountID; 678 ino_t fNodeID; 679 void* fCookie; 680 off_t fPos; 681 generic_io_vec* fVecs; 682 uint32 fCount; 683 uint32 fFlags; 684 generic_size_t fBytesRequested; 685 status_t fStatus; 686 generic_size_t fBytesTransferred; 687 }; 688 689 690 class ReadPages : public PagesIOTraceEntry { 691 public: 692 ReadPages(struct vnode* vnode, void* cookie, off_t pos, 693 const generic_io_vec* vecs, uint32 count, uint32 flags, 694 generic_size_t bytesRequested, status_t status, 695 generic_size_t bytesTransferred) 696 : 697 PagesIOTraceEntry(vnode, cookie, pos, vecs, count, flags, 698 bytesRequested, status, bytesTransferred) 699 { 700 Initialized(); 701 } 702 703 virtual void AddDump(TraceOutput& out) 704 { 705 PagesIOTraceEntry::AddDump(out, "read"); 706 } 707 }; 708 709 710 class WritePages : public PagesIOTraceEntry { 711 public: 712 WritePages(struct vnode* vnode, void* cookie, off_t pos, 713 const generic_io_vec* vecs, uint32 count, uint32 flags, 714 generic_size_t bytesRequested, status_t status, 715 generic_size_t bytesTransferred) 716 : 717 PagesIOTraceEntry(vnode, cookie, pos, vecs, count, flags, 718 bytesRequested, status, bytesTransferred) 719 { 720 Initialized(); 721 } 722 723 virtual void AddDump(TraceOutput& out) 724 { 725 PagesIOTraceEntry::AddDump(out, "write"); 726 } 727 }; 728 729 } // namespace VFSPagesIOTracing 730 731 # define TPIO(x) new(std::nothrow) VFSPagesIOTracing::x; 732 #else 733 # define TPIO(x) ; 734 #endif // VFS_PAGES_IO_TRACING 735 736 737 /*! Finds the mounted device (the fs_mount structure) with the given ID. 738 Note, you must hold the sMountLock lock when you call this function. 739 */ 740 static struct fs_mount* 741 find_mount(dev_t id) 742 { 743 ASSERT_READ_LOCKED_RW_LOCK(&sMountLock); 744 745 return sMountsTable->Lookup(id); 746 } 747 748 749 static status_t 750 get_mount(dev_t id, struct fs_mount** _mount) 751 { 752 struct fs_mount* mount; 753 754 ReadLocker nodeLocker(sVnodeLock); 755 ReadLocker mountLocker(sMountLock); 756 757 mount = find_mount(id); 758 if (mount == NULL) 759 return B_BAD_VALUE; 760 761 struct vnode* rootNode = mount->root_vnode; 762 if (mount->unmounting || rootNode == NULL || rootNode->IsBusy() 763 || rootNode->ref_count == 0) { 764 // might have been called during a mount/unmount operation 765 return B_BUSY; 766 } 767 768 inc_vnode_ref_count(rootNode); 769 *_mount = mount; 770 return B_OK; 771 } 772 773 774 static void 775 put_mount(struct fs_mount* mount) 776 { 777 if (mount) 778 put_vnode(mount->root_vnode); 779 } 780 781 782 /*! Tries to open the specified file system module. 783 Accepts a file system name of the form "bfs" or "file_systems/bfs/v1". 784 Returns a pointer to file system module interface, or NULL if it 785 could not open the module. 786 */ 787 static file_system_module_info* 788 get_file_system(const char* fsName) 789 { 790 char name[B_FILE_NAME_LENGTH]; 791 if (strncmp(fsName, "file_systems/", strlen("file_systems/"))) { 792 // construct module name if we didn't get one 793 // (we currently support only one API) 794 snprintf(name, sizeof(name), "file_systems/%s/v1", fsName); 795 fsName = NULL; 796 } 797 798 file_system_module_info* info; 799 if (get_module(fsName ? fsName : name, (module_info**)&info) != B_OK) 800 return NULL; 801 802 return info; 803 } 804 805 806 /*! Accepts a file system name of the form "bfs" or "file_systems/bfs/v1" 807 and returns a compatible fs_info.fsh_name name ("bfs" in both cases). 808 The name is allocated for you, and you have to free() it when you're 809 done with it. 810 Returns NULL if the required memory is not available. 811 */ 812 static char* 813 get_file_system_name(const char* fsName) 814 { 815 const size_t length = strlen("file_systems/"); 816 817 if (strncmp(fsName, "file_systems/", length)) { 818 // the name already seems to be the module's file name 819 return strdup(fsName); 820 } 821 822 fsName += length; 823 const char* end = strchr(fsName, '/'); 824 if (end == NULL) { 825 // this doesn't seem to be a valid name, but well... 826 return strdup(fsName); 827 } 828 829 // cut off the trailing /v1 830 831 char* name = (char*)malloc(end + 1 - fsName); 832 if (name == NULL) 833 return NULL; 834 835 strlcpy(name, fsName, end + 1 - fsName); 836 return name; 837 } 838 839 840 /*! Accepts a list of file system names separated by a colon, one for each 841 layer and returns the file system name for the specified layer. 842 The name is allocated for you, and you have to free() it when you're 843 done with it. 844 Returns NULL if the required memory is not available or if there is no 845 name for the specified layer. 846 */ 847 static char* 848 get_file_system_name_for_layer(const char* fsNames, int32 layer) 849 { 850 while (layer >= 0) { 851 const char* end = strchr(fsNames, ':'); 852 if (end == NULL) { 853 if (layer == 0) 854 return strdup(fsNames); 855 return NULL; 856 } 857 858 if (layer == 0) { 859 size_t length = end - fsNames + 1; 860 char* result = (char*)malloc(length); 861 strlcpy(result, fsNames, length); 862 return result; 863 } 864 865 fsNames = end + 1; 866 layer--; 867 } 868 869 return NULL; 870 } 871 872 873 static void 874 add_vnode_to_mount_list(struct vnode* vnode, struct fs_mount* mount) 875 { 876 MutexLocker _(mount->lock); 877 mount->vnodes.Add(vnode); 878 } 879 880 881 static void 882 remove_vnode_from_mount_list(struct vnode* vnode, struct fs_mount* mount) 883 { 884 MutexLocker _(mount->lock); 885 mount->vnodes.Remove(vnode); 886 } 887 888 889 /*! \brief Looks up a vnode by mount and node ID in the sVnodeTable. 890 891 The caller must hold the sVnodeLock (read lock at least). 892 893 \param mountID the mount ID. 894 \param vnodeID the node ID. 895 896 \return The vnode structure, if it was found in the hash table, \c NULL 897 otherwise. 898 */ 899 static struct vnode* 900 lookup_vnode(dev_t mountID, ino_t vnodeID) 901 { 902 struct vnode_hash_key key; 903 904 key.device = mountID; 905 key.vnode = vnodeID; 906 907 return sVnodeTable->Lookup(key); 908 } 909 910 911 /*! \brief Checks whether or not a busy vnode should be waited for (again). 912 913 This will also wait for BUSY_VNODE_DELAY before returning if one should 914 still wait for the vnode becoming unbusy. 915 916 \return \c true if one should retry, \c false if not. 917 */ 918 static bool 919 retry_busy_vnode(int32& tries, dev_t mountID, ino_t vnodeID) 920 { 921 if (--tries < 0) { 922 // vnode doesn't seem to become unbusy 923 dprintf("vnode %" B_PRIdDEV ":%" B_PRIdINO 924 " is not becoming unbusy!\n", mountID, vnodeID); 925 return false; 926 } 927 snooze(BUSY_VNODE_DELAY); 928 return true; 929 } 930 931 932 /*! Creates a new vnode with the given mount and node ID. 933 If the node already exists, it is returned instead and no new node is 934 created. In either case -- but not, if an error occurs -- the function write 935 locks \c sVnodeLock and keeps it locked for the caller when returning. On 936 error the lock is not held on return. 937 938 \param mountID The mount ID. 939 \param vnodeID The vnode ID. 940 \param _vnode Will be set to the new vnode on success. 941 \param _nodeCreated Will be set to \c true when the returned vnode has 942 been newly created, \c false when it already existed. Will not be 943 changed on error. 944 \return \c B_OK, when the vnode was successfully created and inserted or 945 a node with the given ID was found, \c B_NO_MEMORY or 946 \c B_ENTRY_NOT_FOUND on error. 947 */ 948 static status_t 949 create_new_vnode_and_lock(dev_t mountID, ino_t vnodeID, struct vnode*& _vnode, 950 bool& _nodeCreated) 951 { 952 FUNCTION(("create_new_vnode_and_lock()\n")); 953 954 struct vnode* vnode = (struct vnode*)object_cache_alloc(sVnodeCache, 0); 955 if (vnode == NULL) 956 return B_NO_MEMORY; 957 958 // initialize basic values 959 memset(vnode, 0, sizeof(struct vnode)); 960 vnode->device = mountID; 961 vnode->id = vnodeID; 962 vnode->ref_count = 1; 963 vnode->SetBusy(true); 964 965 // look up the node -- it might have been added by someone else in the 966 // meantime 967 rw_lock_write_lock(&sVnodeLock); 968 struct vnode* existingVnode = lookup_vnode(mountID, vnodeID); 969 if (existingVnode != NULL) { 970 object_cache_free(sVnodeCache, vnode, 0); 971 _vnode = existingVnode; 972 _nodeCreated = false; 973 return B_OK; 974 } 975 976 // get the mount structure 977 rw_lock_read_lock(&sMountLock); 978 vnode->mount = find_mount(mountID); 979 if (!vnode->mount || vnode->mount->unmounting) { 980 rw_lock_read_unlock(&sMountLock); 981 rw_lock_write_unlock(&sVnodeLock); 982 object_cache_free(sVnodeCache, vnode, 0); 983 return B_ENTRY_NOT_FOUND; 984 } 985 986 // add the vnode to the mount's node list and the hash table 987 sVnodeTable->Insert(vnode); 988 add_vnode_to_mount_list(vnode, vnode->mount); 989 990 rw_lock_read_unlock(&sMountLock); 991 992 _vnode = vnode; 993 _nodeCreated = true; 994 995 // keep the vnode lock locked 996 return B_OK; 997 } 998 999 1000 /*! Frees the vnode and all resources it has acquired, and removes 1001 it from the vnode hash as well as from its mount structure. 1002 Will also make sure that any cache modifications are written back. 1003 */ 1004 static void 1005 free_vnode(struct vnode* vnode, bool reenter) 1006 { 1007 ASSERT_PRINT(vnode->ref_count == 0 && vnode->IsBusy(), "vnode: %p\n", 1008 vnode); 1009 ASSERT_PRINT(vnode->advisory_locking == NULL, "vnode: %p\n", vnode); 1010 1011 // write back any changes in this vnode's cache -- but only 1012 // if the vnode won't be deleted, in which case the changes 1013 // will be discarded 1014 1015 if (!vnode->IsRemoved() && HAS_FS_CALL(vnode, fsync)) 1016 FS_CALL_NO_PARAMS(vnode, fsync); 1017 1018 // Note: If this vnode has a cache attached, there will still be two 1019 // references to that cache at this point. The last one belongs to the vnode 1020 // itself (cf. vfs_get_vnode_cache()) and one belongs to the node's file 1021 // cache. Each but the last reference to a cache also includes a reference 1022 // to the vnode. The file cache, however, released its reference (cf. 1023 // file_cache_create()), so that this vnode's ref count has the chance to 1024 // ever drop to 0. Deleting the file cache now, will cause the next to last 1025 // cache reference to be released, which will also release a (no longer 1026 // existing) vnode reference. To avoid problems, we set the vnode's ref 1027 // count, so that it will neither become negative nor 0. 1028 vnode->ref_count = 2; 1029 1030 if (!vnode->IsUnpublished()) { 1031 if (vnode->IsRemoved()) 1032 FS_CALL(vnode, remove_vnode, reenter); 1033 else 1034 FS_CALL(vnode, put_vnode, reenter); 1035 } 1036 1037 // If the vnode has a VMCache attached, make sure that it won't try to get 1038 // another reference via VMVnodeCache::AcquireUnreferencedStoreRef(). As 1039 // long as the vnode is busy and in the hash, that won't happen, but as 1040 // soon as we've removed it from the hash, it could reload the vnode -- with 1041 // a new cache attached! 1042 if (vnode->cache != NULL && vnode->cache->type == CACHE_TYPE_VNODE) 1043 ((VMVnodeCache*)vnode->cache)->VnodeDeleted(); 1044 1045 // The file system has removed the resources of the vnode now, so we can 1046 // make it available again (by removing the busy vnode from the hash). 1047 rw_lock_write_lock(&sVnodeLock); 1048 sVnodeTable->Remove(vnode); 1049 rw_lock_write_unlock(&sVnodeLock); 1050 1051 // if we have a VMCache attached, remove it 1052 if (vnode->cache) 1053 vnode->cache->ReleaseRef(); 1054 1055 vnode->cache = NULL; 1056 1057 remove_vnode_from_mount_list(vnode, vnode->mount); 1058 1059 object_cache_free(sVnodeCache, vnode, 0); 1060 } 1061 1062 1063 /*! \brief Decrements the reference counter of the given vnode and deletes it, 1064 if the counter dropped to 0. 1065 1066 The caller must, of course, own a reference to the vnode to call this 1067 function. 1068 The caller must not hold the sVnodeLock or the sMountLock. 1069 1070 \param vnode the vnode. 1071 \param alwaysFree don't move this vnode into the unused list, but really 1072 delete it if possible. 1073 \param reenter \c true, if this function is called (indirectly) from within 1074 a file system. This will be passed to file system hooks only. 1075 \return \c B_OK, if everything went fine, an error code otherwise. 1076 */ 1077 static status_t 1078 dec_vnode_ref_count(struct vnode* vnode, bool alwaysFree, bool reenter) 1079 { 1080 ReadLocker locker(sVnodeLock); 1081 AutoLocker<Vnode> nodeLocker(vnode); 1082 1083 int32 oldRefCount = atomic_add(&vnode->ref_count, -1); 1084 1085 ASSERT_PRINT(oldRefCount > 0, "vnode %p\n", vnode); 1086 1087 TRACE(("dec_vnode_ref_count: vnode %p, ref now %" B_PRId32 "\n", vnode, 1088 vnode->ref_count)); 1089 1090 if (oldRefCount != 1) 1091 return B_OK; 1092 1093 if (vnode->IsBusy()) 1094 panic("dec_vnode_ref_count: called on busy vnode %p\n", vnode); 1095 1096 bool freeNode = false; 1097 bool freeUnusedNodes = false; 1098 1099 // Just insert the vnode into an unused list if we don't need 1100 // to delete it 1101 if (vnode->IsRemoved() || alwaysFree) { 1102 vnode_to_be_freed(vnode); 1103 vnode->SetBusy(true); 1104 freeNode = true; 1105 } else 1106 freeUnusedNodes = vnode_unused(vnode); 1107 1108 nodeLocker.Unlock(); 1109 locker.Unlock(); 1110 1111 if (freeNode) 1112 free_vnode(vnode, reenter); 1113 else if (freeUnusedNodes) 1114 free_unused_vnodes(); 1115 1116 return B_OK; 1117 } 1118 1119 1120 /*! \brief Increments the reference counter of the given vnode. 1121 1122 The caller must make sure that the node isn't deleted while this function 1123 is called. This can be done either: 1124 - by ensuring that a reference to the node exists and remains in existence, 1125 or 1126 - by holding the vnode's lock (which also requires read locking sVnodeLock) 1127 or by holding sVnodeLock write locked. 1128 1129 In the second case the caller is responsible for dealing with the ref count 1130 0 -> 1 transition. That is 1. this function must not be invoked when the 1131 node is busy in the first place and 2. vnode_used() must be called for the 1132 node. 1133 1134 \param vnode the vnode. 1135 */ 1136 static void 1137 inc_vnode_ref_count(struct vnode* vnode) 1138 { 1139 atomic_add(&vnode->ref_count, 1); 1140 TRACE(("inc_vnode_ref_count: vnode %p, ref now %" B_PRId32 "\n", vnode, 1141 vnode->ref_count)); 1142 } 1143 1144 1145 static bool 1146 is_special_node_type(int type) 1147 { 1148 // at the moment only FIFOs are supported 1149 return S_ISFIFO(type); 1150 } 1151 1152 1153 static status_t 1154 create_special_sub_node(struct vnode* vnode, uint32 flags) 1155 { 1156 if (S_ISFIFO(vnode->Type())) 1157 return create_fifo_vnode(vnode->mount->volume, vnode); 1158 1159 return B_BAD_VALUE; 1160 } 1161 1162 1163 /*! \brief Retrieves a vnode for a given mount ID, node ID pair. 1164 1165 If the node is not yet in memory, it will be loaded. 1166 1167 The caller must not hold the sVnodeLock or the sMountLock. 1168 1169 \param mountID the mount ID. 1170 \param vnodeID the node ID. 1171 \param _vnode Pointer to a vnode* variable into which the pointer to the 1172 retrieved vnode structure shall be written. 1173 \param reenter \c true, if this function is called (indirectly) from within 1174 a file system. 1175 \return \c B_OK, if everything when fine, an error code otherwise. 1176 */ 1177 static status_t 1178 get_vnode(dev_t mountID, ino_t vnodeID, struct vnode** _vnode, bool canWait, 1179 int reenter) 1180 { 1181 FUNCTION(("get_vnode: mountid %" B_PRId32 " vnid 0x%" B_PRIx64 " %p\n", 1182 mountID, vnodeID, _vnode)); 1183 1184 rw_lock_read_lock(&sVnodeLock); 1185 1186 int32 tries = BUSY_VNODE_RETRIES; 1187 restart: 1188 struct vnode* vnode = lookup_vnode(mountID, vnodeID); 1189 AutoLocker<Vnode> nodeLocker(vnode); 1190 1191 if (vnode && vnode->IsBusy()) { 1192 nodeLocker.Unlock(); 1193 rw_lock_read_unlock(&sVnodeLock); 1194 if (!canWait) { 1195 dprintf("vnode %" B_PRIdDEV ":%" B_PRIdINO " is busy!\n", 1196 mountID, vnodeID); 1197 return B_BUSY; 1198 } 1199 if (!retry_busy_vnode(tries, mountID, vnodeID)) 1200 return B_BUSY; 1201 1202 rw_lock_read_lock(&sVnodeLock); 1203 goto restart; 1204 } 1205 1206 TRACE(("get_vnode: tried to lookup vnode, got %p\n", vnode)); 1207 1208 status_t status; 1209 1210 if (vnode) { 1211 if (vnode->ref_count == 0) { 1212 // this vnode has been unused before 1213 vnode_used(vnode); 1214 } 1215 inc_vnode_ref_count(vnode); 1216 1217 nodeLocker.Unlock(); 1218 rw_lock_read_unlock(&sVnodeLock); 1219 } else { 1220 // we need to create a new vnode and read it in 1221 rw_lock_read_unlock(&sVnodeLock); 1222 // unlock -- create_new_vnode_and_lock() write-locks on success 1223 bool nodeCreated; 1224 status = create_new_vnode_and_lock(mountID, vnodeID, vnode, 1225 nodeCreated); 1226 if (status != B_OK) 1227 return status; 1228 1229 if (!nodeCreated) { 1230 rw_lock_read_lock(&sVnodeLock); 1231 rw_lock_write_unlock(&sVnodeLock); 1232 goto restart; 1233 } 1234 1235 rw_lock_write_unlock(&sVnodeLock); 1236 1237 int type; 1238 uint32 flags; 1239 status = FS_MOUNT_CALL(vnode->mount, get_vnode, vnodeID, vnode, &type, 1240 &flags, reenter); 1241 if (status == B_OK && vnode->private_node == NULL) 1242 status = B_BAD_VALUE; 1243 1244 bool gotNode = status == B_OK; 1245 bool publishSpecialSubNode = false; 1246 if (gotNode) { 1247 vnode->SetType(type); 1248 publishSpecialSubNode = is_special_node_type(type) 1249 && (flags & B_VNODE_DONT_CREATE_SPECIAL_SUB_NODE) == 0; 1250 } 1251 1252 if (gotNode && publishSpecialSubNode) 1253 status = create_special_sub_node(vnode, flags); 1254 1255 if (status != B_OK) { 1256 if (gotNode) 1257 FS_CALL(vnode, put_vnode, reenter); 1258 1259 rw_lock_write_lock(&sVnodeLock); 1260 sVnodeTable->Remove(vnode); 1261 remove_vnode_from_mount_list(vnode, vnode->mount); 1262 rw_lock_write_unlock(&sVnodeLock); 1263 1264 object_cache_free(sVnodeCache, vnode, 0); 1265 return status; 1266 } 1267 1268 rw_lock_read_lock(&sVnodeLock); 1269 vnode->Lock(); 1270 1271 vnode->SetRemoved((flags & B_VNODE_PUBLISH_REMOVED) != 0); 1272 vnode->SetBusy(false); 1273 1274 vnode->Unlock(); 1275 rw_lock_read_unlock(&sVnodeLock); 1276 } 1277 1278 TRACE(("get_vnode: returning %p\n", vnode)); 1279 1280 *_vnode = vnode; 1281 return B_OK; 1282 } 1283 1284 1285 /*! \brief Decrements the reference counter of the given vnode and deletes it, 1286 if the counter dropped to 0. 1287 1288 The caller must, of course, own a reference to the vnode to call this 1289 function. 1290 The caller must not hold the sVnodeLock or the sMountLock. 1291 1292 \param vnode the vnode. 1293 */ 1294 static inline void 1295 put_vnode(struct vnode* vnode) 1296 { 1297 dec_vnode_ref_count(vnode, false, false); 1298 } 1299 1300 1301 static void 1302 free_unused_vnodes(int32 level) 1303 { 1304 unused_vnodes_check_started(); 1305 1306 if (level == B_NO_LOW_RESOURCE) { 1307 unused_vnodes_check_done(); 1308 return; 1309 } 1310 1311 flush_hot_vnodes(); 1312 1313 // determine how many nodes to free 1314 uint32 count = 1; 1315 { 1316 MutexLocker unusedVnodesLocker(sUnusedVnodesLock); 1317 1318 switch (level) { 1319 case B_LOW_RESOURCE_NOTE: 1320 count = sUnusedVnodes / 100; 1321 break; 1322 case B_LOW_RESOURCE_WARNING: 1323 count = sUnusedVnodes / 10; 1324 break; 1325 case B_LOW_RESOURCE_CRITICAL: 1326 count = sUnusedVnodes; 1327 break; 1328 } 1329 1330 if (count > sUnusedVnodes) 1331 count = sUnusedVnodes; 1332 } 1333 1334 // Write back the modified pages of some unused vnodes and free them. 1335 1336 for (uint32 i = 0; i < count; i++) { 1337 ReadLocker vnodesReadLocker(sVnodeLock); 1338 1339 // get the first node 1340 MutexLocker unusedVnodesLocker(sUnusedVnodesLock); 1341 struct vnode* vnode = (struct vnode*)list_get_first_item( 1342 &sUnusedVnodeList); 1343 unusedVnodesLocker.Unlock(); 1344 1345 if (vnode == NULL) 1346 break; 1347 1348 // lock the node 1349 AutoLocker<Vnode> nodeLocker(vnode); 1350 1351 // Check whether the node is still unused -- since we only append to the 1352 // tail of the unused queue, the vnode should still be at its head. 1353 // Alternatively we could check its ref count for 0 and its busy flag, 1354 // but if the node is no longer at the head of the queue, it means it 1355 // has been touched in the meantime, i.e. it is no longer the least 1356 // recently used unused vnode and we rather don't free it. 1357 unusedVnodesLocker.Lock(); 1358 if (vnode != list_get_first_item(&sUnusedVnodeList)) 1359 continue; 1360 unusedVnodesLocker.Unlock(); 1361 1362 ASSERT(!vnode->IsBusy()); 1363 1364 // grab a reference 1365 inc_vnode_ref_count(vnode); 1366 vnode_used(vnode); 1367 1368 // write back changes and free the node 1369 nodeLocker.Unlock(); 1370 vnodesReadLocker.Unlock(); 1371 1372 if (vnode->cache != NULL) 1373 vnode->cache->WriteModified(); 1374 1375 dec_vnode_ref_count(vnode, true, false); 1376 // this should free the vnode when it's still unused 1377 } 1378 1379 unused_vnodes_check_done(); 1380 } 1381 1382 1383 /*! Gets the vnode the given vnode is covering. 1384 1385 The caller must have \c sVnodeLock read-locked at least. 1386 1387 The function returns a reference to the retrieved vnode (if any), the caller 1388 is responsible to free. 1389 1390 \param vnode The vnode whose covered node shall be returned. 1391 \return The covered vnode, or \c NULL if the given vnode doesn't cover any 1392 vnode. 1393 */ 1394 static inline Vnode* 1395 get_covered_vnode_locked(Vnode* vnode) 1396 { 1397 if (Vnode* coveredNode = vnode->covers) { 1398 while (coveredNode->covers != NULL) 1399 coveredNode = coveredNode->covers; 1400 1401 inc_vnode_ref_count(coveredNode); 1402 return coveredNode; 1403 } 1404 1405 return NULL; 1406 } 1407 1408 1409 /*! Gets the vnode the given vnode is covering. 1410 1411 The caller must not hold \c sVnodeLock. Note that this implies a race 1412 condition, since the situation can change at any time. 1413 1414 The function returns a reference to the retrieved vnode (if any), the caller 1415 is responsible to free. 1416 1417 \param vnode The vnode whose covered node shall be returned. 1418 \return The covered vnode, or \c NULL if the given vnode doesn't cover any 1419 vnode. 1420 */ 1421 static inline Vnode* 1422 get_covered_vnode(Vnode* vnode) 1423 { 1424 if (!vnode->IsCovering()) 1425 return NULL; 1426 1427 ReadLocker vnodeReadLocker(sVnodeLock); 1428 return get_covered_vnode_locked(vnode); 1429 } 1430 1431 1432 /*! Gets the vnode the given vnode is covered by. 1433 1434 The caller must have \c sVnodeLock read-locked at least. 1435 1436 The function returns a reference to the retrieved vnode (if any), the caller 1437 is responsible to free. 1438 1439 \param vnode The vnode whose covering node shall be returned. 1440 \return The covering vnode, or \c NULL if the given vnode isn't covered by 1441 any vnode. 1442 */ 1443 static Vnode* 1444 get_covering_vnode_locked(Vnode* vnode) 1445 { 1446 if (Vnode* coveringNode = vnode->covered_by) { 1447 while (coveringNode->covered_by != NULL) 1448 coveringNode = coveringNode->covered_by; 1449 1450 inc_vnode_ref_count(coveringNode); 1451 return coveringNode; 1452 } 1453 1454 return NULL; 1455 } 1456 1457 1458 /*! Gets the vnode the given vnode is covered by. 1459 1460 The caller must not hold \c sVnodeLock. Note that this implies a race 1461 condition, since the situation can change at any time. 1462 1463 The function returns a reference to the retrieved vnode (if any), the caller 1464 is responsible to free. 1465 1466 \param vnode The vnode whose covering node shall be returned. 1467 \return The covering vnode, or \c NULL if the given vnode isn't covered by 1468 any vnode. 1469 */ 1470 static inline Vnode* 1471 get_covering_vnode(Vnode* vnode) 1472 { 1473 if (!vnode->IsCovered()) 1474 return NULL; 1475 1476 ReadLocker vnodeReadLocker(sVnodeLock); 1477 return get_covering_vnode_locked(vnode); 1478 } 1479 1480 1481 static void 1482 free_unused_vnodes() 1483 { 1484 free_unused_vnodes( 1485 low_resource_state(B_KERNEL_RESOURCE_PAGES | B_KERNEL_RESOURCE_MEMORY 1486 | B_KERNEL_RESOURCE_ADDRESS_SPACE)); 1487 } 1488 1489 1490 static void 1491 vnode_low_resource_handler(void* /*data*/, uint32 resources, int32 level) 1492 { 1493 TRACE(("vnode_low_resource_handler(level = %" B_PRId32 ")\n", level)); 1494 1495 free_unused_vnodes(level); 1496 } 1497 1498 1499 static inline void 1500 put_advisory_locking(struct advisory_locking* locking) 1501 { 1502 release_sem(locking->lock); 1503 } 1504 1505 1506 /*! Returns the advisory_locking object of the \a vnode in case it 1507 has one, and locks it. 1508 You have to call put_advisory_locking() when you're done with 1509 it. 1510 Note, you must not have the vnode mutex locked when calling 1511 this function. 1512 */ 1513 static struct advisory_locking* 1514 get_advisory_locking(struct vnode* vnode) 1515 { 1516 rw_lock_read_lock(&sVnodeLock); 1517 vnode->Lock(); 1518 1519 struct advisory_locking* locking = vnode->advisory_locking; 1520 sem_id lock = locking != NULL ? locking->lock : B_ERROR; 1521 1522 vnode->Unlock(); 1523 rw_lock_read_unlock(&sVnodeLock); 1524 1525 if (lock >= 0) 1526 lock = acquire_sem(lock); 1527 if (lock < 0) { 1528 // This means the locking has been deleted in the mean time 1529 // or had never existed in the first place - otherwise, we 1530 // would get the lock at some point. 1531 return NULL; 1532 } 1533 1534 return locking; 1535 } 1536 1537 1538 /*! Creates a locked advisory_locking object, and attaches it to the 1539 given \a vnode. 1540 Returns B_OK in case of success - also if the vnode got such an 1541 object from someone else in the mean time, you'll still get this 1542 one locked then. 1543 */ 1544 static status_t 1545 create_advisory_locking(struct vnode* vnode) 1546 { 1547 if (vnode == NULL) 1548 return B_FILE_ERROR; 1549 1550 ObjectDeleter<advisory_locking> lockingDeleter; 1551 struct advisory_locking* locking = NULL; 1552 1553 while (get_advisory_locking(vnode) == NULL) { 1554 // no locking object set on the vnode yet, create one 1555 if (locking == NULL) { 1556 locking = new(std::nothrow) advisory_locking; 1557 if (locking == NULL) 1558 return B_NO_MEMORY; 1559 lockingDeleter.SetTo(locking); 1560 1561 locking->wait_sem = create_sem(0, "advisory lock"); 1562 if (locking->wait_sem < 0) 1563 return locking->wait_sem; 1564 1565 locking->lock = create_sem(0, "advisory locking"); 1566 if (locking->lock < 0) 1567 return locking->lock; 1568 } 1569 1570 // set our newly created locking object 1571 ReadLocker _(sVnodeLock); 1572 AutoLocker<Vnode> nodeLocker(vnode); 1573 if (vnode->advisory_locking == NULL) { 1574 vnode->advisory_locking = locking; 1575 lockingDeleter.Detach(); 1576 return B_OK; 1577 } 1578 } 1579 1580 // The vnode already had a locking object. That's just as well. 1581 1582 return B_OK; 1583 } 1584 1585 1586 /*! Returns \c true when either \a flock is \c NULL or the \a flock intersects 1587 with the advisory_lock \a lock. 1588 */ 1589 static bool 1590 advisory_lock_intersects(struct advisory_lock* lock, struct flock* flock) 1591 { 1592 if (flock == NULL) 1593 return true; 1594 1595 return lock->start <= flock->l_start - 1 + flock->l_len 1596 && lock->end >= flock->l_start; 1597 } 1598 1599 1600 /*! Tests whether acquiring a lock would block. 1601 */ 1602 static status_t 1603 test_advisory_lock(struct vnode* vnode, struct flock* flock) 1604 { 1605 flock->l_type = F_UNLCK; 1606 1607 struct advisory_locking* locking = get_advisory_locking(vnode); 1608 if (locking == NULL) 1609 return B_OK; 1610 1611 team_id team = team_get_current_team_id(); 1612 1613 LockList::Iterator iterator = locking->locks.GetIterator(); 1614 while (iterator.HasNext()) { 1615 struct advisory_lock* lock = iterator.Next(); 1616 1617 if (lock->team != team && advisory_lock_intersects(lock, flock)) { 1618 // locks do overlap 1619 if (flock->l_type != F_RDLCK || !lock->shared) { 1620 // collision 1621 flock->l_type = lock->shared ? F_RDLCK : F_WRLCK; 1622 flock->l_whence = SEEK_SET; 1623 flock->l_start = lock->start; 1624 flock->l_len = lock->end - lock->start + 1; 1625 flock->l_pid = lock->team; 1626 break; 1627 } 1628 } 1629 } 1630 1631 put_advisory_locking(locking); 1632 return B_OK; 1633 } 1634 1635 1636 /*! Removes the specified lock, or all locks of the calling team 1637 if \a flock is NULL. 1638 */ 1639 static status_t 1640 release_advisory_lock(struct vnode* vnode, struct io_context* context, 1641 struct file_descriptor* descriptor, struct flock* flock) 1642 { 1643 FUNCTION(("release_advisory_lock(vnode = %p, flock = %p)\n", vnode, flock)); 1644 1645 struct advisory_locking* locking = get_advisory_locking(vnode); 1646 if (locking == NULL) 1647 return B_OK; 1648 1649 // find matching lock entries 1650 1651 LockList::Iterator iterator = locking->locks.GetIterator(); 1652 while (iterator.HasNext()) { 1653 struct advisory_lock* lock = iterator.Next(); 1654 bool removeLock = false; 1655 1656 if (descriptor != NULL && lock->bound_to == descriptor) { 1657 // Remove flock() locks 1658 removeLock = true; 1659 } else if (lock->bound_to == context 1660 && advisory_lock_intersects(lock, flock)) { 1661 // Remove POSIX locks 1662 bool endsBeyond = false; 1663 bool startsBefore = false; 1664 if (flock != NULL) { 1665 startsBefore = lock->start < flock->l_start; 1666 endsBeyond = lock->end > flock->l_start - 1 + flock->l_len; 1667 } 1668 1669 if (!startsBefore && !endsBeyond) { 1670 // lock is completely contained in flock 1671 removeLock = true; 1672 } else if (startsBefore && !endsBeyond) { 1673 // cut the end of the lock 1674 lock->end = flock->l_start - 1; 1675 } else if (!startsBefore && endsBeyond) { 1676 // cut the start of the lock 1677 lock->start = flock->l_start + flock->l_len; 1678 } else { 1679 // divide the lock into two locks 1680 struct advisory_lock* secondLock = new advisory_lock; 1681 if (secondLock == NULL) { 1682 // TODO: we should probably revert the locks we already 1683 // changed... (ie. allocate upfront) 1684 put_advisory_locking(locking); 1685 return B_NO_MEMORY; 1686 } 1687 1688 lock->end = flock->l_start - 1; 1689 1690 secondLock->bound_to = context; 1691 secondLock->team = lock->team; 1692 secondLock->session = lock->session; 1693 // values must already be normalized when getting here 1694 secondLock->start = flock->l_start + flock->l_len; 1695 secondLock->end = lock->end; 1696 secondLock->shared = lock->shared; 1697 1698 locking->locks.Add(secondLock); 1699 } 1700 } 1701 1702 if (removeLock) { 1703 // this lock is no longer used 1704 iterator.Remove(); 1705 free(lock); 1706 } 1707 } 1708 1709 bool removeLocking = locking->locks.IsEmpty(); 1710 release_sem_etc(locking->wait_sem, 1, B_RELEASE_ALL); 1711 1712 put_advisory_locking(locking); 1713 1714 if (removeLocking) { 1715 // We can remove the whole advisory locking structure; it's no 1716 // longer used 1717 locking = get_advisory_locking(vnode); 1718 if (locking != NULL) { 1719 ReadLocker locker(sVnodeLock); 1720 AutoLocker<Vnode> nodeLocker(vnode); 1721 1722 // the locking could have been changed in the mean time 1723 if (locking->locks.IsEmpty()) { 1724 vnode->advisory_locking = NULL; 1725 nodeLocker.Unlock(); 1726 locker.Unlock(); 1727 1728 // we've detached the locking from the vnode, so we can 1729 // safely delete it 1730 delete locking; 1731 } else { 1732 // the locking is in use again 1733 nodeLocker.Unlock(); 1734 locker.Unlock(); 1735 release_sem_etc(locking->lock, 1, B_DO_NOT_RESCHEDULE); 1736 } 1737 } 1738 } 1739 1740 return B_OK; 1741 } 1742 1743 1744 /*! Acquires an advisory lock for the \a vnode. If \a wait is \c true, it 1745 will wait for the lock to become available, if there are any collisions 1746 (it will return B_PERMISSION_DENIED in this case if \a wait is \c false). 1747 1748 If \a descriptor is NULL, POSIX semantics are used for this lock. Otherwise, 1749 BSD flock() semantics are used, that is, all children can unlock the file 1750 in question (we even allow parents to remove the lock, though, but that 1751 seems to be in line to what the BSD's are doing). 1752 */ 1753 static status_t 1754 acquire_advisory_lock(struct vnode* vnode, io_context* context, 1755 struct file_descriptor* descriptor, struct flock* flock, bool wait) 1756 { 1757 FUNCTION(("acquire_advisory_lock(vnode = %p, flock = %p, wait = %s)\n", 1758 vnode, flock, wait ? "yes" : "no")); 1759 1760 bool shared = flock->l_type == F_RDLCK; 1761 void* boundTo = descriptor != NULL ? (void*)descriptor : (void*)context; 1762 status_t status = B_OK; 1763 1764 // TODO: do deadlock detection! 1765 1766 struct advisory_locking* locking; 1767 1768 while (true) { 1769 // if this vnode has an advisory_locking structure attached, 1770 // lock that one and search for any colliding file lock 1771 status = create_advisory_locking(vnode); 1772 if (status != B_OK) 1773 return status; 1774 1775 locking = vnode->advisory_locking; 1776 team_id team = team_get_current_team_id(); 1777 sem_id waitForLock = -1; 1778 1779 // test for collisions 1780 LockList::Iterator iterator = locking->locks.GetIterator(); 1781 while (iterator.HasNext()) { 1782 struct advisory_lock* lock = iterator.Next(); 1783 1784 // TODO: locks from the same team might be joinable! 1785 if ((lock->team != team || lock->bound_to != boundTo) 1786 && advisory_lock_intersects(lock, flock)) { 1787 // locks do overlap 1788 if (!shared || !lock->shared) { 1789 // we need to wait 1790 waitForLock = locking->wait_sem; 1791 break; 1792 } 1793 } 1794 } 1795 1796 if (waitForLock < 0) 1797 break; 1798 1799 // We need to wait. Do that or fail now, if we've been asked not to. 1800 1801 if (!wait) { 1802 put_advisory_locking(locking); 1803 return descriptor != NULL ? B_WOULD_BLOCK : B_PERMISSION_DENIED; 1804 } 1805 1806 status = switch_sem_etc(locking->lock, waitForLock, 1, 1807 B_CAN_INTERRUPT, 0); 1808 if (status != B_OK && status != B_BAD_SEM_ID) 1809 return status; 1810 1811 // We have been notified, but we need to re-lock the locking object. So 1812 // go another round... 1813 } 1814 1815 // install new lock 1816 1817 struct advisory_lock* lock = (struct advisory_lock*)malloc( 1818 sizeof(struct advisory_lock)); 1819 if (lock == NULL) { 1820 put_advisory_locking(locking); 1821 return B_NO_MEMORY; 1822 } 1823 1824 lock->bound_to = boundTo; 1825 lock->team = team_get_current_team_id(); 1826 lock->session = thread_get_current_thread()->team->session_id; 1827 // values must already be normalized when getting here 1828 lock->start = flock->l_start; 1829 lock->end = flock->l_start - 1 + flock->l_len; 1830 lock->shared = shared; 1831 1832 locking->locks.Add(lock); 1833 put_advisory_locking(locking); 1834 1835 return status; 1836 } 1837 1838 1839 /*! Normalizes the \a flock structure to make it easier to compare the 1840 structure with others. The l_start and l_len fields are set to absolute 1841 values according to the l_whence field. 1842 */ 1843 static status_t 1844 normalize_flock(struct file_descriptor* descriptor, struct flock* flock) 1845 { 1846 switch (flock->l_whence) { 1847 case SEEK_SET: 1848 break; 1849 case SEEK_CUR: 1850 flock->l_start += descriptor->pos; 1851 break; 1852 case SEEK_END: 1853 { 1854 struct vnode* vnode = descriptor->u.vnode; 1855 struct stat stat; 1856 status_t status; 1857 1858 if (!HAS_FS_CALL(vnode, read_stat)) 1859 return B_UNSUPPORTED; 1860 1861 status = FS_CALL(vnode, read_stat, &stat); 1862 if (status != B_OK) 1863 return status; 1864 1865 flock->l_start += stat.st_size; 1866 break; 1867 } 1868 default: 1869 return B_BAD_VALUE; 1870 } 1871 1872 if (flock->l_start < 0) 1873 flock->l_start = 0; 1874 if (flock->l_len == 0) 1875 flock->l_len = OFF_MAX; 1876 1877 // don't let the offset and length overflow 1878 if (flock->l_start > 0 && OFF_MAX - flock->l_start < flock->l_len) 1879 flock->l_len = OFF_MAX - flock->l_start; 1880 1881 if (flock->l_len < 0) { 1882 // a negative length reverses the region 1883 flock->l_start += flock->l_len; 1884 flock->l_len = -flock->l_len; 1885 } 1886 1887 return B_OK; 1888 } 1889 1890 1891 static void 1892 replace_vnode_if_disconnected(struct fs_mount* mount, 1893 struct vnode* vnodeToDisconnect, struct vnode*& vnode, 1894 struct vnode* fallBack, bool lockRootLock) 1895 { 1896 struct vnode* givenVnode = vnode; 1897 bool vnodeReplaced = false; 1898 1899 ReadLocker vnodeReadLocker(sVnodeLock); 1900 1901 if (lockRootLock) 1902 mutex_lock(&sIOContextRootLock); 1903 1904 while (vnode != NULL && vnode->mount == mount 1905 && (vnodeToDisconnect == NULL || vnodeToDisconnect == vnode)) { 1906 if (vnode->covers != NULL) { 1907 // redirect the vnode to the covered vnode 1908 vnode = vnode->covers; 1909 } else 1910 vnode = fallBack; 1911 1912 vnodeReplaced = true; 1913 } 1914 1915 // If we've replaced the node, grab a reference for the new one. 1916 if (vnodeReplaced && vnode != NULL) 1917 inc_vnode_ref_count(vnode); 1918 1919 if (lockRootLock) 1920 mutex_unlock(&sIOContextRootLock); 1921 1922 vnodeReadLocker.Unlock(); 1923 1924 if (vnodeReplaced) 1925 put_vnode(givenVnode); 1926 } 1927 1928 1929 /*! Disconnects all file descriptors that are associated with the 1930 \a vnodeToDisconnect, or if this is NULL, all vnodes of the specified 1931 \a mount object. 1932 1933 Note, after you've called this function, there might still be ongoing 1934 accesses - they won't be interrupted if they already happened before. 1935 However, any subsequent access will fail. 1936 1937 This is not a cheap function and should be used with care and rarely. 1938 TODO: there is currently no means to stop a blocking read/write! 1939 */ 1940 static void 1941 disconnect_mount_or_vnode_fds(struct fs_mount* mount, 1942 struct vnode* vnodeToDisconnect) 1943 { 1944 // iterate over all teams and peek into their file descriptors 1945 TeamListIterator teamIterator; 1946 while (Team* team = teamIterator.Next()) { 1947 BReference<Team> teamReference(team, true); 1948 TeamLocker teamLocker(team); 1949 1950 // lock the I/O context 1951 io_context* context = team->io_context; 1952 if (context == NULL) 1953 continue; 1954 MutexLocker contextLocker(context->io_mutex); 1955 1956 teamLocker.Unlock(); 1957 1958 replace_vnode_if_disconnected(mount, vnodeToDisconnect, context->root, 1959 sRoot, true); 1960 replace_vnode_if_disconnected(mount, vnodeToDisconnect, context->cwd, 1961 sRoot, false); 1962 1963 for (uint32 i = 0; i < context->table_size; i++) { 1964 struct file_descriptor* descriptor = context->fds[i]; 1965 if (descriptor == NULL || (descriptor->open_mode & O_DISCONNECTED) != 0) 1966 continue; 1967 1968 inc_fd_ref_count(descriptor); 1969 1970 // if this descriptor points at this mount, we 1971 // need to disconnect it to be able to unmount 1972 struct vnode* vnode = fd_vnode(descriptor); 1973 if (vnodeToDisconnect != NULL) { 1974 if (vnode == vnodeToDisconnect) 1975 disconnect_fd(descriptor); 1976 } else if ((vnode != NULL && vnode->mount == mount) 1977 || (vnode == NULL && descriptor->u.mount == mount)) 1978 disconnect_fd(descriptor); 1979 1980 put_fd(descriptor); 1981 } 1982 } 1983 } 1984 1985 1986 /*! \brief Gets the root node of the current IO context. 1987 If \a kernel is \c true, the kernel IO context will be used. 1988 The caller obtains a reference to the returned node. 1989 */ 1990 struct vnode* 1991 get_root_vnode(bool kernel) 1992 { 1993 if (!kernel) { 1994 // Get current working directory from io context 1995 struct io_context* context = get_current_io_context(kernel); 1996 1997 mutex_lock(&sIOContextRootLock); 1998 1999 struct vnode* root = context->root; 2000 if (root != NULL) 2001 inc_vnode_ref_count(root); 2002 2003 mutex_unlock(&sIOContextRootLock); 2004 2005 if (root != NULL) 2006 return root; 2007 2008 // That should never happen. 2009 dprintf("get_root_vnode(): IO context for team %" B_PRId32 " doesn't " 2010 "have a root\n", team_get_current_team_id()); 2011 } 2012 2013 inc_vnode_ref_count(sRoot); 2014 return sRoot; 2015 } 2016 2017 2018 /*! \brief Gets the directory path and leaf name for a given path. 2019 2020 The supplied \a path is transformed to refer to the directory part of 2021 the entry identified by the original path, and into the buffer \a filename 2022 the leaf name of the original entry is written. 2023 Neither the returned path nor the leaf name can be expected to be 2024 canonical. 2025 2026 \param path The path to be analyzed. Must be able to store at least one 2027 additional character. 2028 \param filename The buffer into which the leaf name will be written. 2029 Must be of size B_FILE_NAME_LENGTH at least. 2030 \return \c B_OK, if everything went fine, \c B_NAME_TOO_LONG, if the leaf 2031 name is longer than \c B_FILE_NAME_LENGTH, or \c B_ENTRY_NOT_FOUND, 2032 if the given path name is empty. 2033 */ 2034 static status_t 2035 get_dir_path_and_leaf(char* path, char* filename) 2036 { 2037 if (*path == '\0') 2038 return B_ENTRY_NOT_FOUND; 2039 2040 char* last = strrchr(path, '/'); 2041 // '/' are not allowed in file names! 2042 2043 FUNCTION(("get_dir_path_and_leaf(path = %s)\n", path)); 2044 2045 if (last == NULL) { 2046 // this path is single segment with no '/' in it 2047 // ex. "foo" 2048 if (strlcpy(filename, path, B_FILE_NAME_LENGTH) >= B_FILE_NAME_LENGTH) 2049 return B_NAME_TOO_LONG; 2050 2051 strcpy(path, "."); 2052 } else { 2053 last++; 2054 if (last[0] == '\0') { 2055 // special case: the path ends in one or more '/' - remove them 2056 while (*--last == '/' && last != path); 2057 last[1] = '\0'; 2058 2059 if (last == path && last[0] == '/') { 2060 // This path points to the root of the file system 2061 strcpy(filename, "."); 2062 return B_OK; 2063 } 2064 for (; last != path && *(last - 1) != '/'; last--); 2065 // rewind to the start of the leaf before the '/' 2066 } 2067 2068 // normal leaf: replace the leaf portion of the path with a '.' 2069 if (strlcpy(filename, last, B_FILE_NAME_LENGTH) >= B_FILE_NAME_LENGTH) 2070 return B_NAME_TOO_LONG; 2071 2072 last[0] = '.'; 2073 last[1] = '\0'; 2074 } 2075 return B_OK; 2076 } 2077 2078 2079 static status_t 2080 entry_ref_to_vnode(dev_t mountID, ino_t directoryID, const char* name, 2081 bool traverse, bool kernel, struct vnode** _vnode) 2082 { 2083 char clonedName[B_FILE_NAME_LENGTH + 1]; 2084 if (strlcpy(clonedName, name, B_FILE_NAME_LENGTH) >= B_FILE_NAME_LENGTH) 2085 return B_NAME_TOO_LONG; 2086 2087 // get the directory vnode and let vnode_path_to_vnode() do the rest 2088 struct vnode* directory; 2089 2090 status_t status = get_vnode(mountID, directoryID, &directory, true, false); 2091 if (status < 0) 2092 return status; 2093 2094 return vnode_path_to_vnode(directory, clonedName, traverse, 0, kernel, 2095 _vnode, NULL); 2096 } 2097 2098 2099 /*! Looks up the entry with name \a name in the directory represented by \a dir 2100 and returns the respective vnode. 2101 On success a reference to the vnode is acquired for the caller. 2102 */ 2103 static status_t 2104 lookup_dir_entry(struct vnode* dir, const char* name, struct vnode** _vnode) 2105 { 2106 ino_t id; 2107 bool missing; 2108 2109 if (dir->mount->entry_cache.Lookup(dir->id, name, id, missing)) { 2110 return missing ? B_ENTRY_NOT_FOUND 2111 : get_vnode(dir->device, id, _vnode, true, false); 2112 } 2113 2114 status_t status = FS_CALL(dir, lookup, name, &id); 2115 if (status != B_OK) 2116 return status; 2117 2118 // The lookup() hook calls get_vnode() or publish_vnode(), so we do already 2119 // have a reference and just need to look the node up. 2120 rw_lock_read_lock(&sVnodeLock); 2121 *_vnode = lookup_vnode(dir->device, id); 2122 rw_lock_read_unlock(&sVnodeLock); 2123 2124 if (*_vnode == NULL) { 2125 panic("lookup_dir_entry(): could not lookup vnode (mountid 0x%" B_PRIx32 2126 " vnid 0x%" B_PRIx64 ")\n", dir->device, id); 2127 return B_ENTRY_NOT_FOUND; 2128 } 2129 2130 // ktrace_printf("lookup_dir_entry(): dir: %p (%ld, %lld), name: \"%s\" -> " 2131 // "%p (%ld, %lld)", dir, dir->mount->id, dir->id, name, *_vnode, 2132 // (*_vnode)->mount->id, (*_vnode)->id); 2133 2134 return B_OK; 2135 } 2136 2137 2138 /*! Returns the vnode for the relative path starting at the specified \a vnode. 2139 \a path must not be NULL. 2140 If it returns successfully, \a path contains the name of the last path 2141 component. This function clobbers the buffer pointed to by \a path only 2142 if it does contain more than one component. 2143 Note, this reduces the ref_count of the starting \a vnode, no matter if 2144 it is successful or not! 2145 */ 2146 static status_t 2147 vnode_path_to_vnode(struct vnode* vnode, char* path, bool traverseLeafLink, 2148 int count, struct io_context* ioContext, struct vnode** _vnode, 2149 ino_t* _parentID) 2150 { 2151 status_t status = B_OK; 2152 ino_t lastParentID = vnode->id; 2153 2154 FUNCTION(("vnode_path_to_vnode(vnode = %p, path = %s)\n", vnode, path)); 2155 2156 if (path == NULL) { 2157 put_vnode(vnode); 2158 return B_BAD_VALUE; 2159 } 2160 2161 if (*path == '\0') { 2162 put_vnode(vnode); 2163 return B_ENTRY_NOT_FOUND; 2164 } 2165 2166 while (true) { 2167 struct vnode* nextVnode; 2168 char* nextPath; 2169 2170 TRACE(("vnode_path_to_vnode: top of loop. p = %p, p = '%s'\n", path, 2171 path)); 2172 2173 // done? 2174 if (path[0] == '\0') 2175 break; 2176 2177 // walk to find the next path component ("path" will point to a single 2178 // path component), and filter out multiple slashes 2179 for (nextPath = path + 1; *nextPath != '\0' && *nextPath != '/'; 2180 nextPath++); 2181 2182 if (*nextPath == '/') { 2183 *nextPath = '\0'; 2184 do 2185 nextPath++; 2186 while (*nextPath == '/'); 2187 } 2188 2189 // See if the '..' is at a covering vnode move to the covered 2190 // vnode so we pass the '..' path to the underlying filesystem. 2191 // Also prevent breaking the root of the IO context. 2192 if (strcmp("..", path) == 0) { 2193 if (vnode == ioContext->root) { 2194 // Attempted prison break! Keep it contained. 2195 path = nextPath; 2196 continue; 2197 } 2198 2199 if (Vnode* coveredVnode = get_covered_vnode(vnode)) { 2200 nextVnode = coveredVnode; 2201 put_vnode(vnode); 2202 vnode = nextVnode; 2203 } 2204 } 2205 2206 // check if vnode is really a directory 2207 if (status == B_OK && !S_ISDIR(vnode->Type())) 2208 status = B_NOT_A_DIRECTORY; 2209 2210 // Check if we have the right to search the current directory vnode. 2211 // If a file system doesn't have the access() function, we assume that 2212 // searching a directory is always allowed 2213 if (status == B_OK && HAS_FS_CALL(vnode, access)) 2214 status = FS_CALL(vnode, access, X_OK); 2215 2216 // Tell the filesystem to get the vnode of this path component (if we 2217 // got the permission from the call above) 2218 if (status == B_OK) 2219 status = lookup_dir_entry(vnode, path, &nextVnode); 2220 2221 if (status != B_OK) { 2222 put_vnode(vnode); 2223 return status; 2224 } 2225 2226 // If the new node is a symbolic link, resolve it (if we've been told 2227 // to do it) 2228 if (S_ISLNK(nextVnode->Type()) 2229 && (traverseLeafLink || nextPath[0] != '\0')) { 2230 size_t bufferSize; 2231 char* buffer; 2232 2233 TRACE(("traverse link\n")); 2234 2235 // it's not exactly nice style using goto in this way, but hey, 2236 // it works :-/ 2237 if (count + 1 > B_MAX_SYMLINKS) { 2238 status = B_LINK_LIMIT; 2239 goto resolve_link_error; 2240 } 2241 2242 bufferSize = B_PATH_NAME_LENGTH; 2243 buffer = (char*)object_cache_alloc(sPathNameCache, 0); 2244 if (buffer == NULL) { 2245 status = B_NO_MEMORY; 2246 goto resolve_link_error; 2247 } 2248 2249 if (HAS_FS_CALL(nextVnode, read_symlink)) { 2250 bufferSize--; 2251 status = FS_CALL(nextVnode, read_symlink, buffer, &bufferSize); 2252 // null-terminate 2253 if (status >= 0 && bufferSize < B_PATH_NAME_LENGTH) 2254 buffer[bufferSize] = '\0'; 2255 } else 2256 status = B_BAD_VALUE; 2257 2258 if (status != B_OK) { 2259 free(buffer); 2260 2261 resolve_link_error: 2262 put_vnode(vnode); 2263 put_vnode(nextVnode); 2264 2265 return status; 2266 } 2267 put_vnode(nextVnode); 2268 2269 // Check if we start from the root directory or the current 2270 // directory ("vnode" still points to that one). 2271 // Cut off all leading slashes if it's the root directory 2272 path = buffer; 2273 bool absoluteSymlink = false; 2274 if (path[0] == '/') { 2275 // we don't need the old directory anymore 2276 put_vnode(vnode); 2277 2278 while (*++path == '/') 2279 ; 2280 2281 mutex_lock(&sIOContextRootLock); 2282 vnode = ioContext->root; 2283 inc_vnode_ref_count(vnode); 2284 mutex_unlock(&sIOContextRootLock); 2285 2286 absoluteSymlink = true; 2287 } 2288 2289 inc_vnode_ref_count(vnode); 2290 // balance the next recursion - we will decrement the 2291 // ref_count of the vnode, no matter if we succeeded or not 2292 2293 if (absoluteSymlink && *path == '\0') { 2294 // symlink was just "/" 2295 nextVnode = vnode; 2296 } else { 2297 status = vnode_path_to_vnode(vnode, path, true, count + 1, 2298 ioContext, &nextVnode, &lastParentID); 2299 } 2300 2301 object_cache_free(sPathNameCache, buffer, 0); 2302 2303 if (status != B_OK) { 2304 put_vnode(vnode); 2305 return status; 2306 } 2307 } else 2308 lastParentID = vnode->id; 2309 2310 // decrease the ref count on the old dir we just looked up into 2311 put_vnode(vnode); 2312 2313 path = nextPath; 2314 vnode = nextVnode; 2315 2316 // see if we hit a covered node 2317 if (Vnode* coveringNode = get_covering_vnode(vnode)) { 2318 put_vnode(vnode); 2319 vnode = coveringNode; 2320 } 2321 } 2322 2323 *_vnode = vnode; 2324 if (_parentID) 2325 *_parentID = lastParentID; 2326 2327 return B_OK; 2328 } 2329 2330 2331 static status_t 2332 vnode_path_to_vnode(struct vnode* vnode, char* path, bool traverseLeafLink, 2333 int count, bool kernel, struct vnode** _vnode, ino_t* _parentID) 2334 { 2335 return vnode_path_to_vnode(vnode, path, traverseLeafLink, count, 2336 get_current_io_context(kernel), _vnode, _parentID); 2337 } 2338 2339 2340 static status_t 2341 path_to_vnode(char* path, bool traverseLink, struct vnode** _vnode, 2342 ino_t* _parentID, bool kernel) 2343 { 2344 struct vnode* start = NULL; 2345 2346 FUNCTION(("path_to_vnode(path = \"%s\")\n", path)); 2347 2348 if (!path) 2349 return B_BAD_VALUE; 2350 2351 if (*path == '\0') 2352 return B_ENTRY_NOT_FOUND; 2353 2354 // figure out if we need to start at root or at cwd 2355 if (*path == '/') { 2356 if (sRoot == NULL) { 2357 // we're a bit early, aren't we? 2358 return B_ERROR; 2359 } 2360 2361 while (*++path == '/') 2362 ; 2363 start = get_root_vnode(kernel); 2364 2365 if (*path == '\0') { 2366 *_vnode = start; 2367 return B_OK; 2368 } 2369 2370 } else { 2371 struct io_context* context = get_current_io_context(kernel); 2372 2373 mutex_lock(&context->io_mutex); 2374 start = context->cwd; 2375 if (start != NULL) 2376 inc_vnode_ref_count(start); 2377 mutex_unlock(&context->io_mutex); 2378 2379 if (start == NULL) 2380 return B_ERROR; 2381 } 2382 2383 return vnode_path_to_vnode(start, path, traverseLink, 0, kernel, _vnode, 2384 _parentID); 2385 } 2386 2387 2388 /*! Returns the vnode in the next to last segment of the path, and returns 2389 the last portion in filename. 2390 The path buffer must be able to store at least one additional character. 2391 */ 2392 static status_t 2393 path_to_dir_vnode(char* path, struct vnode** _vnode, char* filename, 2394 bool kernel) 2395 { 2396 status_t status = get_dir_path_and_leaf(path, filename); 2397 if (status != B_OK) 2398 return status; 2399 2400 return path_to_vnode(path, true, _vnode, NULL, kernel); 2401 } 2402 2403 2404 /*! \brief Retrieves the directory vnode and the leaf name of an entry referred 2405 to by a FD + path pair. 2406 2407 \a path must be given in either case. \a fd might be omitted, in which 2408 case \a path is either an absolute path or one relative to the current 2409 directory. If both a supplied and \a path is relative it is reckoned off 2410 of the directory referred to by \a fd. If \a path is absolute \a fd is 2411 ignored. 2412 2413 The caller has the responsibility to call put_vnode() on the returned 2414 directory vnode. 2415 2416 \param fd The FD. May be < 0. 2417 \param path The absolute or relative path. Must not be \c NULL. The buffer 2418 is modified by this function. It must have at least room for a 2419 string one character longer than the path it contains. 2420 \param _vnode A pointer to a variable the directory vnode shall be written 2421 into. 2422 \param filename A buffer of size B_FILE_NAME_LENGTH or larger into which 2423 the leaf name of the specified entry will be written. 2424 \param kernel \c true, if invoked from inside the kernel, \c false if 2425 invoked from userland. 2426 \return \c B_OK, if everything went fine, another error code otherwise. 2427 */ 2428 static status_t 2429 fd_and_path_to_dir_vnode(int fd, char* path, struct vnode** _vnode, 2430 char* filename, bool kernel) 2431 { 2432 if (!path) 2433 return B_BAD_VALUE; 2434 if (*path == '\0') 2435 return B_ENTRY_NOT_FOUND; 2436 if (fd < 0) 2437 return path_to_dir_vnode(path, _vnode, filename, kernel); 2438 2439 status_t status = get_dir_path_and_leaf(path, filename); 2440 if (status != B_OK) 2441 return status; 2442 2443 return fd_and_path_to_vnode(fd, path, true, _vnode, NULL, kernel); 2444 } 2445 2446 2447 /*! \brief Retrieves the directory vnode and the leaf name of an entry referred 2448 to by a vnode + path pair. 2449 2450 \a path must be given in either case. \a vnode might be omitted, in which 2451 case \a path is either an absolute path or one relative to the current 2452 directory. If both a supplied and \a path is relative it is reckoned off 2453 of the directory referred to by \a vnode. If \a path is absolute \a vnode is 2454 ignored. 2455 2456 The caller has the responsibility to call put_vnode() on the returned 2457 directory vnode. 2458 2459 \param vnode The vnode. May be \c NULL. 2460 \param path The absolute or relative path. Must not be \c NULL. The buffer 2461 is modified by this function. It must have at least room for a 2462 string one character longer than the path it contains. 2463 \param _vnode A pointer to a variable the directory vnode shall be written 2464 into. 2465 \param filename A buffer of size B_FILE_NAME_LENGTH or larger into which 2466 the leaf name of the specified entry will be written. 2467 \param kernel \c true, if invoked from inside the kernel, \c false if 2468 invoked from userland. 2469 \return \c B_OK, if everything went fine, another error code otherwise. 2470 */ 2471 static status_t 2472 vnode_and_path_to_dir_vnode(struct vnode* vnode, char* path, 2473 struct vnode** _vnode, char* filename, bool kernel) 2474 { 2475 if (!path) 2476 return B_BAD_VALUE; 2477 if (*path == '\0') 2478 return B_ENTRY_NOT_FOUND; 2479 if (vnode == NULL || path[0] == '/') 2480 return path_to_dir_vnode(path, _vnode, filename, kernel); 2481 2482 status_t status = get_dir_path_and_leaf(path, filename); 2483 if (status != B_OK) 2484 return status; 2485 2486 inc_vnode_ref_count(vnode); 2487 // vnode_path_to_vnode() always decrements the ref count 2488 2489 return vnode_path_to_vnode(vnode, path, true, 0, kernel, _vnode, NULL); 2490 } 2491 2492 2493 /*! Returns a vnode's name in the d_name field of a supplied dirent buffer. 2494 */ 2495 static status_t 2496 get_vnode_name(struct vnode* vnode, struct vnode* parent, struct dirent* buffer, 2497 size_t bufferSize, struct io_context* ioContext) 2498 { 2499 if (bufferSize < sizeof(struct dirent)) 2500 return B_BAD_VALUE; 2501 2502 // See if the vnode is covering another vnode and move to the covered 2503 // vnode so we get the underlying file system 2504 VNodePutter vnodePutter; 2505 if (Vnode* coveredVnode = get_covered_vnode(vnode)) { 2506 vnode = coveredVnode; 2507 vnodePutter.SetTo(vnode); 2508 } 2509 2510 if (HAS_FS_CALL(vnode, get_vnode_name)) { 2511 // The FS supports getting the name of a vnode. 2512 if (FS_CALL(vnode, get_vnode_name, buffer->d_name, 2513 (char*)buffer + bufferSize - buffer->d_name) == B_OK) 2514 return B_OK; 2515 } 2516 2517 // The FS doesn't support getting the name of a vnode. So we search the 2518 // parent directory for the vnode, if the caller let us. 2519 2520 if (parent == NULL || !HAS_FS_CALL(parent, read_dir)) 2521 return B_UNSUPPORTED; 2522 2523 void* cookie; 2524 2525 status_t status = FS_CALL(parent, open_dir, &cookie); 2526 if (status >= B_OK) { 2527 while (true) { 2528 uint32 num = 1; 2529 // We use the FS hook directly instead of dir_read(), since we don't 2530 // want the entries to be fixed. We have already resolved vnode to 2531 // the covered node. 2532 status = FS_CALL(parent, read_dir, cookie, buffer, bufferSize, 2533 &num); 2534 if (status != B_OK) 2535 break; 2536 if (num == 0) { 2537 status = B_ENTRY_NOT_FOUND; 2538 break; 2539 } 2540 2541 if (vnode->id == buffer->d_ino) { 2542 // found correct entry! 2543 break; 2544 } 2545 } 2546 2547 FS_CALL(parent, close_dir, cookie); 2548 FS_CALL(parent, free_dir_cookie, cookie); 2549 } 2550 return status; 2551 } 2552 2553 2554 static status_t 2555 get_vnode_name(struct vnode* vnode, struct vnode* parent, char* name, 2556 size_t nameSize, bool kernel) 2557 { 2558 char buffer[offsetof(struct dirent, d_name) + B_FILE_NAME_LENGTH + 1]; 2559 struct dirent* dirent = (struct dirent*)buffer; 2560 2561 status_t status = get_vnode_name(vnode, parent, dirent, sizeof(buffer), 2562 get_current_io_context(kernel)); 2563 if (status != B_OK) 2564 return status; 2565 2566 if (strlcpy(name, dirent->d_name, nameSize) >= nameSize) 2567 return B_BUFFER_OVERFLOW; 2568 2569 return B_OK; 2570 } 2571 2572 2573 /*! Gets the full path to a given directory vnode. 2574 It uses the fs_get_vnode_name() call to get the name of a vnode; if a 2575 file system doesn't support this call, it will fall back to iterating 2576 through the parent directory to get the name of the child. 2577 2578 To protect against circular loops, it supports a maximum tree depth 2579 of 256 levels. 2580 2581 Note that the path may not be correct the time this function returns! 2582 It doesn't use any locking to prevent returning the correct path, as 2583 paths aren't safe anyway: the path to a file can change at any time. 2584 2585 It might be a good idea, though, to check if the returned path exists 2586 in the calling function (it's not done here because of efficiency) 2587 */ 2588 static status_t 2589 dir_vnode_to_path(struct vnode* vnode, char* buffer, size_t bufferSize, 2590 bool kernel) 2591 { 2592 FUNCTION(("dir_vnode_to_path(%p, %p, %lu)\n", vnode, buffer, bufferSize)); 2593 2594 if (vnode == NULL || buffer == NULL || bufferSize == 0) 2595 return B_BAD_VALUE; 2596 2597 if (!S_ISDIR(vnode->Type())) 2598 return B_NOT_A_DIRECTORY; 2599 2600 char* path = buffer; 2601 int32 insert = bufferSize; 2602 int32 maxLevel = 256; 2603 int32 length; 2604 status_t status = B_OK; 2605 struct io_context* ioContext = get_current_io_context(kernel); 2606 2607 // we don't use get_vnode() here because this call is more 2608 // efficient and does all we need from get_vnode() 2609 inc_vnode_ref_count(vnode); 2610 2611 path[--insert] = '\0'; 2612 // the path is filled right to left 2613 2614 while (true) { 2615 // If the node is the context's root, bail out. Otherwise resolve mount 2616 // points. 2617 if (vnode == ioContext->root) 2618 break; 2619 2620 if (Vnode* coveredVnode = get_covered_vnode(vnode)) { 2621 put_vnode(vnode); 2622 vnode = coveredVnode; 2623 } 2624 2625 // lookup the parent vnode 2626 struct vnode* parentVnode; 2627 status = lookup_dir_entry(vnode, "..", &parentVnode); 2628 if (status != B_OK) 2629 goto out; 2630 2631 if (parentVnode == vnode) { 2632 // The caller apparently got their hands on a node outside of their 2633 // context's root. Now we've hit the global root. 2634 put_vnode(parentVnode); 2635 break; 2636 } 2637 2638 // get the node's name 2639 char nameBuffer[offsetof(struct dirent, d_name) + B_FILE_NAME_LENGTH + 1]; 2640 // also used for fs_read_dir() 2641 char* name = &((struct dirent*)nameBuffer)->d_name[0]; 2642 status = get_vnode_name(vnode, parentVnode, (struct dirent*)nameBuffer, 2643 sizeof(nameBuffer), ioContext); 2644 2645 // release the current vnode, we only need its parent from now on 2646 put_vnode(vnode); 2647 vnode = parentVnode; 2648 2649 if (status != B_OK) 2650 goto out; 2651 2652 // TODO: add an explicit check for loops in about 10 levels to do 2653 // real loop detection 2654 2655 // don't go deeper as 'maxLevel' to prevent circular loops 2656 if (maxLevel-- < 0) { 2657 status = B_LINK_LIMIT; 2658 goto out; 2659 } 2660 2661 // add the name in front of the current path 2662 name[B_FILE_NAME_LENGTH - 1] = '\0'; 2663 length = strlen(name); 2664 insert -= length; 2665 if (insert <= 0) { 2666 status = B_RESULT_NOT_REPRESENTABLE; 2667 goto out; 2668 } 2669 memcpy(path + insert, name, length); 2670 path[--insert] = '/'; 2671 } 2672 2673 // the root dir will result in an empty path: fix it 2674 if (path[insert] == '\0') 2675 path[--insert] = '/'; 2676 2677 TRACE((" path is: %s\n", path + insert)); 2678 2679 // move the path to the start of the buffer 2680 length = bufferSize - insert; 2681 memmove(buffer, path + insert, length); 2682 2683 out: 2684 put_vnode(vnode); 2685 return status; 2686 } 2687 2688 2689 /*! Checks the length of every path component, and adds a '.' 2690 if the path ends in a slash. 2691 The given path buffer must be able to store at least one 2692 additional character. 2693 */ 2694 static status_t 2695 check_path(char* to) 2696 { 2697 int32 length = 0; 2698 2699 // check length of every path component 2700 2701 while (*to) { 2702 char* begin; 2703 if (*to == '/') 2704 to++, length++; 2705 2706 begin = to; 2707 while (*to != '/' && *to) 2708 to++, length++; 2709 2710 if (to - begin > B_FILE_NAME_LENGTH) 2711 return B_NAME_TOO_LONG; 2712 } 2713 2714 if (length == 0) 2715 return B_ENTRY_NOT_FOUND; 2716 2717 // complete path if there is a slash at the end 2718 2719 if (*(to - 1) == '/') { 2720 if (length > B_PATH_NAME_LENGTH - 2) 2721 return B_NAME_TOO_LONG; 2722 2723 to[0] = '.'; 2724 to[1] = '\0'; 2725 } 2726 2727 return B_OK; 2728 } 2729 2730 2731 static struct file_descriptor* 2732 get_fd_and_vnode(int fd, struct vnode** _vnode, bool kernel) 2733 { 2734 struct file_descriptor* descriptor 2735 = get_fd(get_current_io_context(kernel), fd); 2736 if (descriptor == NULL) 2737 return NULL; 2738 2739 struct vnode* vnode = fd_vnode(descriptor); 2740 if (vnode == NULL) { 2741 put_fd(descriptor); 2742 return NULL; 2743 } 2744 2745 // ToDo: when we can close a file descriptor at any point, investigate 2746 // if this is still valid to do (accessing the vnode without ref_count 2747 // or locking) 2748 *_vnode = vnode; 2749 return descriptor; 2750 } 2751 2752 2753 static struct vnode* 2754 get_vnode_from_fd(int fd, bool kernel) 2755 { 2756 struct file_descriptor* descriptor; 2757 struct vnode* vnode; 2758 2759 descriptor = get_fd(get_current_io_context(kernel), fd); 2760 if (descriptor == NULL) 2761 return NULL; 2762 2763 vnode = fd_vnode(descriptor); 2764 if (vnode != NULL) 2765 inc_vnode_ref_count(vnode); 2766 2767 put_fd(descriptor); 2768 return vnode; 2769 } 2770 2771 2772 /*! Gets the vnode from an FD + path combination. If \a fd is lower than zero, 2773 only the path will be considered. In this case, the \a path must not be 2774 NULL. 2775 If \a fd is a valid file descriptor, \a path may be NULL for directories, 2776 and should be NULL for files. 2777 */ 2778 static status_t 2779 fd_and_path_to_vnode(int fd, char* path, bool traverseLeafLink, 2780 struct vnode** _vnode, ino_t* _parentID, bool kernel) 2781 { 2782 if (fd < 0 && !path) 2783 return B_BAD_VALUE; 2784 2785 if (path != NULL && *path == '\0') 2786 return B_ENTRY_NOT_FOUND; 2787 2788 if (fd < 0 || (path != NULL && path[0] == '/')) { 2789 // no FD or absolute path 2790 return path_to_vnode(path, traverseLeafLink, _vnode, _parentID, kernel); 2791 } 2792 2793 // FD only, or FD + relative path 2794 struct vnode* vnode = get_vnode_from_fd(fd, kernel); 2795 if (vnode == NULL) 2796 return B_FILE_ERROR; 2797 2798 if (path != NULL) { 2799 return vnode_path_to_vnode(vnode, path, traverseLeafLink, 0, kernel, 2800 _vnode, _parentID); 2801 } 2802 2803 // there is no relative path to take into account 2804 2805 *_vnode = vnode; 2806 if (_parentID) 2807 *_parentID = -1; 2808 2809 return B_OK; 2810 } 2811 2812 2813 static int 2814 get_new_fd(int type, struct fs_mount* mount, struct vnode* vnode, 2815 void* cookie, int openMode, bool kernel) 2816 { 2817 struct file_descriptor* descriptor; 2818 int fd; 2819 2820 // If the vnode is locked, we don't allow creating a new file/directory 2821 // file_descriptor for it 2822 if (vnode && vnode->mandatory_locked_by != NULL 2823 && (type == FDTYPE_FILE || type == FDTYPE_DIR)) 2824 return B_BUSY; 2825 2826 descriptor = alloc_fd(); 2827 if (!descriptor) 2828 return B_NO_MEMORY; 2829 2830 if (vnode) 2831 descriptor->u.vnode = vnode; 2832 else 2833 descriptor->u.mount = mount; 2834 descriptor->cookie = cookie; 2835 2836 switch (type) { 2837 // vnode types 2838 case FDTYPE_FILE: 2839 descriptor->ops = &sFileOps; 2840 break; 2841 case FDTYPE_DIR: 2842 descriptor->ops = &sDirectoryOps; 2843 break; 2844 case FDTYPE_ATTR: 2845 descriptor->ops = &sAttributeOps; 2846 break; 2847 case FDTYPE_ATTR_DIR: 2848 descriptor->ops = &sAttributeDirectoryOps; 2849 break; 2850 2851 // mount types 2852 case FDTYPE_INDEX_DIR: 2853 descriptor->ops = &sIndexDirectoryOps; 2854 break; 2855 case FDTYPE_QUERY: 2856 descriptor->ops = &sQueryOps; 2857 break; 2858 2859 default: 2860 panic("get_new_fd() called with unknown type %d\n", type); 2861 break; 2862 } 2863 descriptor->type = type; 2864 descriptor->open_mode = openMode; 2865 2866 io_context* context = get_current_io_context(kernel); 2867 fd = new_fd(context, descriptor); 2868 if (fd < 0) { 2869 descriptor->ops = NULL; 2870 put_fd(descriptor); 2871 return B_NO_MORE_FDS; 2872 } 2873 2874 mutex_lock(&context->io_mutex); 2875 fd_set_close_on_exec(context, fd, (openMode & O_CLOEXEC) != 0); 2876 mutex_unlock(&context->io_mutex); 2877 2878 return fd; 2879 } 2880 2881 2882 /*! In-place normalizes \a path. It's otherwise semantically equivalent to 2883 vfs_normalize_path(). See there for more documentation. 2884 */ 2885 static status_t 2886 normalize_path(char* path, size_t pathSize, bool traverseLink, bool kernel) 2887 { 2888 VNodePutter dirPutter; 2889 struct vnode* dir = NULL; 2890 status_t error; 2891 2892 for (int i = 0; i < B_MAX_SYMLINKS; i++) { 2893 // get dir vnode + leaf name 2894 struct vnode* nextDir; 2895 char leaf[B_FILE_NAME_LENGTH]; 2896 error = vnode_and_path_to_dir_vnode(dir, path, &nextDir, leaf, kernel); 2897 if (error != B_OK) 2898 return error; 2899 2900 dir = nextDir; 2901 strcpy(path, leaf); 2902 dirPutter.SetTo(dir); 2903 2904 // get file vnode, if we shall resolve links 2905 bool fileExists = false; 2906 struct vnode* fileVnode; 2907 VNodePutter fileVnodePutter; 2908 if (traverseLink) { 2909 inc_vnode_ref_count(dir); 2910 if (vnode_path_to_vnode(dir, path, false, 0, kernel, &fileVnode, 2911 NULL) == B_OK) { 2912 fileVnodePutter.SetTo(fileVnode); 2913 fileExists = true; 2914 } 2915 } 2916 2917 if (!fileExists || !traverseLink || !S_ISLNK(fileVnode->Type())) { 2918 // we're done -- construct the path 2919 bool hasLeaf = true; 2920 if (strcmp(leaf, ".") == 0 || strcmp(leaf, "..") == 0) { 2921 // special cases "." and ".." -- get the dir, forget the leaf 2922 inc_vnode_ref_count(dir); 2923 error = vnode_path_to_vnode(dir, leaf, false, 0, kernel, 2924 &nextDir, NULL); 2925 if (error != B_OK) 2926 return error; 2927 dir = nextDir; 2928 dirPutter.SetTo(dir); 2929 hasLeaf = false; 2930 } 2931 2932 // get the directory path 2933 error = dir_vnode_to_path(dir, path, B_PATH_NAME_LENGTH, kernel); 2934 if (error != B_OK) 2935 return error; 2936 2937 // append the leaf name 2938 if (hasLeaf) { 2939 // insert a directory separator if this is not the file system 2940 // root 2941 if ((strcmp(path, "/") != 0 2942 && strlcat(path, "/", pathSize) >= pathSize) 2943 || strlcat(path, leaf, pathSize) >= pathSize) { 2944 return B_NAME_TOO_LONG; 2945 } 2946 } 2947 2948 return B_OK; 2949 } 2950 2951 // read link 2952 if (HAS_FS_CALL(fileVnode, read_symlink)) { 2953 size_t bufferSize = B_PATH_NAME_LENGTH - 1; 2954 error = FS_CALL(fileVnode, read_symlink, path, &bufferSize); 2955 if (error != B_OK) 2956 return error; 2957 if (bufferSize < B_PATH_NAME_LENGTH) 2958 path[bufferSize] = '\0'; 2959 } else 2960 return B_BAD_VALUE; 2961 } 2962 2963 return B_LINK_LIMIT; 2964 } 2965 2966 2967 static status_t 2968 resolve_covered_parent(struct vnode* parent, dev_t* _device, ino_t* _node, 2969 struct io_context* ioContext) 2970 { 2971 // Make sure the IO context root is not bypassed. 2972 if (parent == ioContext->root) { 2973 *_device = parent->device; 2974 *_node = parent->id; 2975 return B_OK; 2976 } 2977 2978 inc_vnode_ref_count(parent); 2979 // vnode_path_to_vnode() puts the node 2980 2981 // ".." is guaranteed not to be clobbered by this call 2982 struct vnode* vnode; 2983 status_t status = vnode_path_to_vnode(parent, (char*)"..", false, 0, 2984 ioContext, &vnode, NULL); 2985 if (status == B_OK) { 2986 *_device = vnode->device; 2987 *_node = vnode->id; 2988 put_vnode(vnode); 2989 } 2990 2991 return status; 2992 } 2993 2994 2995 #ifdef ADD_DEBUGGER_COMMANDS 2996 2997 2998 static void 2999 _dump_advisory_locking(advisory_locking* locking) 3000 { 3001 if (locking == NULL) 3002 return; 3003 3004 kprintf(" lock: %" B_PRId32, locking->lock); 3005 kprintf(" wait_sem: %" B_PRId32, locking->wait_sem); 3006 3007 int32 index = 0; 3008 LockList::Iterator iterator = locking->locks.GetIterator(); 3009 while (iterator.HasNext()) { 3010 struct advisory_lock* lock = iterator.Next(); 3011 3012 kprintf(" [%2" B_PRId32 "] team: %" B_PRId32 "\n", index++, lock->team); 3013 kprintf(" start: %" B_PRIdOFF "\n", lock->start); 3014 kprintf(" end: %" B_PRIdOFF "\n", lock->end); 3015 kprintf(" shared? %s\n", lock->shared ? "yes" : "no"); 3016 } 3017 } 3018 3019 3020 static void 3021 _dump_mount(struct fs_mount* mount) 3022 { 3023 kprintf("MOUNT: %p\n", mount); 3024 kprintf(" id: %" B_PRIdDEV "\n", mount->id); 3025 kprintf(" device_name: %s\n", mount->device_name); 3026 kprintf(" root_vnode: %p\n", mount->root_vnode); 3027 kprintf(" covers: %p\n", mount->root_vnode->covers); 3028 kprintf(" partition: %p\n", mount->partition); 3029 kprintf(" lock: %p\n", &mount->lock); 3030 kprintf(" flags: %s%s\n", mount->unmounting ? " unmounting" : "", 3031 mount->owns_file_device ? " owns_file_device" : ""); 3032 3033 fs_volume* volume = mount->volume; 3034 while (volume != NULL) { 3035 kprintf(" volume %p:\n", volume); 3036 kprintf(" layer: %" B_PRId32 "\n", volume->layer); 3037 kprintf(" private_volume: %p\n", volume->private_volume); 3038 kprintf(" ops: %p\n", volume->ops); 3039 kprintf(" file_system: %p\n", volume->file_system); 3040 kprintf(" file_system_name: %s\n", volume->file_system_name); 3041 volume = volume->super_volume; 3042 } 3043 3044 set_debug_variable("_volume", (addr_t)mount->volume->private_volume); 3045 set_debug_variable("_root", (addr_t)mount->root_vnode); 3046 set_debug_variable("_covers", (addr_t)mount->root_vnode->covers); 3047 set_debug_variable("_partition", (addr_t)mount->partition); 3048 } 3049 3050 3051 static bool 3052 debug_prepend_vnode_name_to_path(char* buffer, size_t& bufferSize, 3053 const char* name) 3054 { 3055 bool insertSlash = buffer[bufferSize] != '\0'; 3056 size_t nameLength = strlen(name); 3057 3058 if (bufferSize < nameLength + (insertSlash ? 1 : 0)) 3059 return false; 3060 3061 if (insertSlash) 3062 buffer[--bufferSize] = '/'; 3063 3064 bufferSize -= nameLength; 3065 memcpy(buffer + bufferSize, name, nameLength); 3066 3067 return true; 3068 } 3069 3070 3071 static bool 3072 debug_prepend_vnode_id_to_path(char* buffer, size_t& bufferSize, dev_t devID, 3073 ino_t nodeID) 3074 { 3075 if (bufferSize == 0) 3076 return false; 3077 3078 bool insertSlash = buffer[bufferSize] != '\0'; 3079 if (insertSlash) 3080 buffer[--bufferSize] = '/'; 3081 3082 size_t size = snprintf(buffer, bufferSize, 3083 "<%" B_PRIdDEV ",%" B_PRIdINO ">", devID, nodeID); 3084 if (size > bufferSize) { 3085 if (insertSlash) 3086 bufferSize++; 3087 return false; 3088 } 3089 3090 if (size < bufferSize) 3091 memmove(buffer + bufferSize - size, buffer, size); 3092 3093 bufferSize -= size; 3094 return true; 3095 } 3096 3097 3098 static char* 3099 debug_resolve_vnode_path(struct vnode* vnode, char* buffer, size_t bufferSize, 3100 bool& _truncated) 3101 { 3102 // null-terminate the path 3103 buffer[--bufferSize] = '\0'; 3104 3105 while (true) { 3106 while (vnode->covers != NULL) 3107 vnode = vnode->covers; 3108 3109 if (vnode == sRoot) { 3110 _truncated = bufferSize == 0; 3111 if (!_truncated) 3112 buffer[--bufferSize] = '/'; 3113 return buffer + bufferSize; 3114 } 3115 3116 // resolve the name 3117 ino_t dirID; 3118 const char* name = vnode->mount->entry_cache.DebugReverseLookup( 3119 vnode->id, dirID); 3120 if (name == NULL) { 3121 // Failed to resolve the name -- prepend "<dev,node>/". 3122 _truncated = !debug_prepend_vnode_id_to_path(buffer, bufferSize, 3123 vnode->mount->id, vnode->id); 3124 return buffer + bufferSize; 3125 } 3126 3127 // prepend the name 3128 if (!debug_prepend_vnode_name_to_path(buffer, bufferSize, name)) { 3129 _truncated = true; 3130 return buffer + bufferSize; 3131 } 3132 3133 // resolve the directory node 3134 struct vnode* nextVnode = lookup_vnode(vnode->mount->id, dirID); 3135 if (nextVnode == NULL) { 3136 _truncated = !debug_prepend_vnode_id_to_path(buffer, bufferSize, 3137 vnode->mount->id, dirID); 3138 return buffer + bufferSize; 3139 } 3140 3141 vnode = nextVnode; 3142 } 3143 } 3144 3145 3146 static void 3147 _dump_vnode(struct vnode* vnode, bool printPath) 3148 { 3149 kprintf("VNODE: %p\n", vnode); 3150 kprintf(" device: %" B_PRIdDEV "\n", vnode->device); 3151 kprintf(" id: %" B_PRIdINO "\n", vnode->id); 3152 kprintf(" ref_count: %" B_PRId32 "\n", vnode->ref_count); 3153 kprintf(" private_node: %p\n", vnode->private_node); 3154 kprintf(" mount: %p\n", vnode->mount); 3155 kprintf(" covered_by: %p\n", vnode->covered_by); 3156 kprintf(" covers: %p\n", vnode->covers); 3157 kprintf(" cache: %p\n", vnode->cache); 3158 kprintf(" type: %#" B_PRIx32 "\n", vnode->Type()); 3159 kprintf(" flags: %s%s%s\n", vnode->IsRemoved() ? "r" : "-", 3160 vnode->IsBusy() ? "b" : "-", vnode->IsUnpublished() ? "u" : "-"); 3161 kprintf(" advisory_lock: %p\n", vnode->advisory_locking); 3162 3163 _dump_advisory_locking(vnode->advisory_locking); 3164 3165 if (printPath) { 3166 void* buffer = debug_malloc(B_PATH_NAME_LENGTH); 3167 if (buffer != NULL) { 3168 bool truncated; 3169 char* path = debug_resolve_vnode_path(vnode, (char*)buffer, 3170 B_PATH_NAME_LENGTH, truncated); 3171 if (path != NULL) { 3172 kprintf(" path: "); 3173 if (truncated) 3174 kputs("<truncated>/"); 3175 kputs(path); 3176 kputs("\n"); 3177 } else 3178 kprintf("Failed to resolve vnode path.\n"); 3179 3180 debug_free(buffer); 3181 } else 3182 kprintf("Failed to allocate memory for constructing the path.\n"); 3183 } 3184 3185 set_debug_variable("_node", (addr_t)vnode->private_node); 3186 set_debug_variable("_mount", (addr_t)vnode->mount); 3187 set_debug_variable("_covered_by", (addr_t)vnode->covered_by); 3188 set_debug_variable("_covers", (addr_t)vnode->covers); 3189 set_debug_variable("_adv_lock", (addr_t)vnode->advisory_locking); 3190 } 3191 3192 3193 static int 3194 dump_mount(int argc, char** argv) 3195 { 3196 if (argc != 2 || !strcmp(argv[1], "--help")) { 3197 kprintf("usage: %s [id|address]\n", argv[0]); 3198 return 0; 3199 } 3200 3201 ulong val = parse_expression(argv[1]); 3202 uint32 id = val; 3203 3204 struct fs_mount* mount = sMountsTable->Lookup(id); 3205 if (mount == NULL) { 3206 if (IS_USER_ADDRESS(id)) { 3207 kprintf("fs_mount not found\n"); 3208 return 0; 3209 } 3210 mount = (fs_mount*)val; 3211 } 3212 3213 _dump_mount(mount); 3214 return 0; 3215 } 3216 3217 3218 static int 3219 dump_mounts(int argc, char** argv) 3220 { 3221 if (argc != 1) { 3222 kprintf("usage: %s\n", argv[0]); 3223 return 0; 3224 } 3225 3226 kprintf("%-*s id %-*s %-*s %-*s fs_name\n", 3227 B_PRINTF_POINTER_WIDTH, "address", B_PRINTF_POINTER_WIDTH, "root", 3228 B_PRINTF_POINTER_WIDTH, "covers", B_PRINTF_POINTER_WIDTH, "cookie"); 3229 3230 struct fs_mount* mount; 3231 3232 MountTable::Iterator iterator(sMountsTable); 3233 while (iterator.HasNext()) { 3234 mount = iterator.Next(); 3235 kprintf("%p%4" B_PRIdDEV " %p %p %p %s\n", mount, mount->id, mount->root_vnode, 3236 mount->root_vnode->covers, mount->volume->private_volume, 3237 mount->volume->file_system_name); 3238 3239 fs_volume* volume = mount->volume; 3240 while (volume->super_volume != NULL) { 3241 volume = volume->super_volume; 3242 kprintf(" %p %s\n", 3243 volume->private_volume, volume->file_system_name); 3244 } 3245 } 3246 3247 return 0; 3248 } 3249 3250 3251 static int 3252 dump_vnode(int argc, char** argv) 3253 { 3254 bool printPath = false; 3255 int argi = 1; 3256 if (argc >= 2 && strcmp(argv[argi], "-p") == 0) { 3257 printPath = true; 3258 argi++; 3259 } 3260 3261 if (argi >= argc || argi + 2 < argc) { 3262 print_debugger_command_usage(argv[0]); 3263 return 0; 3264 } 3265 3266 struct vnode* vnode = NULL; 3267 3268 if (argi + 1 == argc) { 3269 vnode = (struct vnode*)parse_expression(argv[argi]); 3270 if (IS_USER_ADDRESS(vnode)) { 3271 kprintf("invalid vnode address\n"); 3272 return 0; 3273 } 3274 _dump_vnode(vnode, printPath); 3275 return 0; 3276 } 3277 3278 dev_t device = parse_expression(argv[argi]); 3279 ino_t id = parse_expression(argv[argi + 1]); 3280 3281 VnodeTable::Iterator iterator(sVnodeTable); 3282 while (iterator.HasNext()) { 3283 vnode = iterator.Next(); 3284 if (vnode->id != id || vnode->device != device) 3285 continue; 3286 3287 _dump_vnode(vnode, printPath); 3288 } 3289 3290 return 0; 3291 } 3292 3293 3294 static int 3295 dump_vnodes(int argc, char** argv) 3296 { 3297 if (argc != 2 || !strcmp(argv[1], "--help")) { 3298 kprintf("usage: %s [device]\n", argv[0]); 3299 return 0; 3300 } 3301 3302 // restrict dumped nodes to a certain device if requested 3303 dev_t device = parse_expression(argv[1]); 3304 3305 struct vnode* vnode; 3306 3307 kprintf("%-*s dev inode ref %-*s %-*s %-*s flags\n", 3308 B_PRINTF_POINTER_WIDTH, "address", B_PRINTF_POINTER_WIDTH, "cache", 3309 B_PRINTF_POINTER_WIDTH, "fs-node", B_PRINTF_POINTER_WIDTH, "locking"); 3310 3311 VnodeTable::Iterator iterator(sVnodeTable); 3312 while (iterator.HasNext()) { 3313 vnode = iterator.Next(); 3314 if (vnode->device != device) 3315 continue; 3316 3317 kprintf("%p%4" B_PRIdDEV "%10" B_PRIdINO "%5" B_PRId32 " %p %p %p %s%s%s\n", 3318 vnode, vnode->device, vnode->id, vnode->ref_count, vnode->cache, 3319 vnode->private_node, vnode->advisory_locking, 3320 vnode->IsRemoved() ? "r" : "-", vnode->IsBusy() ? "b" : "-", 3321 vnode->IsUnpublished() ? "u" : "-"); 3322 } 3323 3324 return 0; 3325 } 3326 3327 3328 static int 3329 dump_vnode_caches(int argc, char** argv) 3330 { 3331 struct vnode* vnode; 3332 3333 if (argc > 2 || !strcmp(argv[1], "--help")) { 3334 kprintf("usage: %s [device]\n", argv[0]); 3335 return 0; 3336 } 3337 3338 // restrict dumped nodes to a certain device if requested 3339 dev_t device = -1; 3340 if (argc > 1) 3341 device = parse_expression(argv[1]); 3342 3343 kprintf("%-*s dev inode %-*s size pages\n", 3344 B_PRINTF_POINTER_WIDTH, "address", B_PRINTF_POINTER_WIDTH, "cache"); 3345 3346 VnodeTable::Iterator iterator(sVnodeTable); 3347 while (iterator.HasNext()) { 3348 vnode = iterator.Next(); 3349 if (vnode->cache == NULL) 3350 continue; 3351 if (device != -1 && vnode->device != device) 3352 continue; 3353 3354 kprintf("%p%4" B_PRIdDEV "%10" B_PRIdINO " %p %8" B_PRIdOFF "%8" B_PRId32 "\n", 3355 vnode, vnode->device, vnode->id, vnode->cache, 3356 (vnode->cache->virtual_end + B_PAGE_SIZE - 1) / B_PAGE_SIZE, 3357 vnode->cache->page_count); 3358 } 3359 3360 return 0; 3361 } 3362 3363 3364 int 3365 dump_io_context(int argc, char** argv) 3366 { 3367 if (argc > 2 || !strcmp(argv[1], "--help")) { 3368 kprintf("usage: %s [team-id|address]\n", argv[0]); 3369 return 0; 3370 } 3371 3372 struct io_context* context = NULL; 3373 3374 if (argc > 1) { 3375 ulong num = parse_expression(argv[1]); 3376 if (IS_KERNEL_ADDRESS(num)) 3377 context = (struct io_context*)num; 3378 else { 3379 Team* team = team_get_team_struct_locked(num); 3380 if (team == NULL) { 3381 kprintf("could not find team with ID %lu\n", num); 3382 return 0; 3383 } 3384 context = (struct io_context*)team->io_context; 3385 } 3386 } else 3387 context = get_current_io_context(true); 3388 3389 kprintf("I/O CONTEXT: %p\n", context); 3390 kprintf(" root vnode:\t%p\n", context->root); 3391 kprintf(" cwd vnode:\t%p\n", context->cwd); 3392 kprintf(" used fds:\t%" B_PRIu32 "\n", context->num_used_fds); 3393 kprintf(" max fds:\t%" B_PRIu32 "\n", context->table_size); 3394 3395 if (context->num_used_fds) { 3396 kprintf(" no. type %*s ref open mode pos %*s\n", 3397 B_PRINTF_POINTER_WIDTH, "ops", B_PRINTF_POINTER_WIDTH, "cookie"); 3398 } 3399 3400 for (uint32 i = 0; i < context->table_size; i++) { 3401 struct file_descriptor* fd = context->fds[i]; 3402 if (fd == NULL) 3403 continue; 3404 3405 kprintf(" %3" B_PRIu32 ": %4" B_PRId32 " %p %3" B_PRId32 " %4" 3406 B_PRIu32 " %4" B_PRIx32 " %10" B_PRIdOFF " %p %s %p\n", i, 3407 fd->type, fd->ops, fd->ref_count, fd->open_count, fd->open_mode, 3408 fd->pos, fd->cookie, 3409 fd->type >= FDTYPE_INDEX && fd->type <= FDTYPE_QUERY 3410 ? "mount" : "vnode", 3411 fd->u.vnode); 3412 } 3413 3414 kprintf(" used monitors:\t%" B_PRIu32 "\n", context->num_monitors); 3415 kprintf(" max monitors:\t%" B_PRIu32 "\n", context->max_monitors); 3416 3417 set_debug_variable("_cwd", (addr_t)context->cwd); 3418 3419 return 0; 3420 } 3421 3422 3423 int 3424 dump_vnode_usage(int argc, char** argv) 3425 { 3426 if (argc != 1) { 3427 kprintf("usage: %s\n", argv[0]); 3428 return 0; 3429 } 3430 3431 kprintf("Unused vnodes: %" B_PRIu32 " (max unused %" B_PRIu32 ")\n", 3432 sUnusedVnodes, kMaxUnusedVnodes); 3433 3434 uint32 count = sVnodeTable->CountElements(); 3435 3436 kprintf("%" B_PRIu32 " vnodes total (%" B_PRIu32 " in use).\n", count, 3437 count - sUnusedVnodes); 3438 return 0; 3439 } 3440 3441 #endif // ADD_DEBUGGER_COMMANDS 3442 3443 3444 /*! Clears memory specified by an iovec array. 3445 */ 3446 static void 3447 zero_iovecs(const iovec* vecs, size_t vecCount, size_t bytes) 3448 { 3449 for (size_t i = 0; i < vecCount && bytes > 0; i++) { 3450 size_t length = std::min(vecs[i].iov_len, bytes); 3451 memset(vecs[i].iov_base, 0, length); 3452 bytes -= length; 3453 } 3454 } 3455 3456 3457 /*! Does the dirty work of combining the file_io_vecs with the iovecs 3458 and calls the file system hooks to read/write the request to disk. 3459 */ 3460 static status_t 3461 common_file_io_vec_pages(struct vnode* vnode, void* cookie, 3462 const file_io_vec* fileVecs, size_t fileVecCount, const iovec* vecs, 3463 size_t vecCount, uint32* _vecIndex, size_t* _vecOffset, size_t* _numBytes, 3464 bool doWrite) 3465 { 3466 if (fileVecCount == 0) { 3467 // There are no file vecs at this offset, so we're obviously trying 3468 // to access the file outside of its bounds 3469 return B_BAD_VALUE; 3470 } 3471 3472 size_t numBytes = *_numBytes; 3473 uint32 fileVecIndex; 3474 size_t vecOffset = *_vecOffset; 3475 uint32 vecIndex = *_vecIndex; 3476 status_t status; 3477 size_t size; 3478 3479 if (!doWrite && vecOffset == 0) { 3480 // now directly read the data from the device 3481 // the first file_io_vec can be read directly 3482 3483 if (fileVecs[0].length < (off_t)numBytes) 3484 size = fileVecs[0].length; 3485 else 3486 size = numBytes; 3487 3488 if (fileVecs[0].offset >= 0) { 3489 status = FS_CALL(vnode, read_pages, cookie, fileVecs[0].offset, 3490 &vecs[vecIndex], vecCount - vecIndex, &size); 3491 } else { 3492 // sparse read 3493 zero_iovecs(&vecs[vecIndex], vecCount - vecIndex, size); 3494 status = B_OK; 3495 } 3496 if (status != B_OK) 3497 return status; 3498 3499 // TODO: this is a work-around for buggy device drivers! 3500 // When our own drivers honour the length, we can: 3501 // a) also use this direct I/O for writes (otherwise, it would 3502 // overwrite precious data) 3503 // b) panic if the term below is true (at least for writes) 3504 if ((off_t)size > fileVecs[0].length) { 3505 //dprintf("warning: device driver %p doesn't respect total length " 3506 // "in read_pages() call!\n", ref->device); 3507 size = fileVecs[0].length; 3508 } 3509 3510 ASSERT((off_t)size <= fileVecs[0].length); 3511 3512 // If the file portion was contiguous, we're already done now 3513 if (size == numBytes) 3514 return B_OK; 3515 3516 // if we reached the end of the file, we can return as well 3517 if ((off_t)size != fileVecs[0].length) { 3518 *_numBytes = size; 3519 return B_OK; 3520 } 3521 3522 fileVecIndex = 1; 3523 3524 // first, find out where we have to continue in our iovecs 3525 for (; vecIndex < vecCount; vecIndex++) { 3526 if (size < vecs[vecIndex].iov_len) 3527 break; 3528 3529 size -= vecs[vecIndex].iov_len; 3530 } 3531 3532 vecOffset = size; 3533 } else { 3534 fileVecIndex = 0; 3535 size = 0; 3536 } 3537 3538 // Too bad, let's process the rest of the file_io_vecs 3539 3540 size_t totalSize = size; 3541 size_t bytesLeft = numBytes - size; 3542 3543 for (; fileVecIndex < fileVecCount; fileVecIndex++) { 3544 const file_io_vec &fileVec = fileVecs[fileVecIndex]; 3545 off_t fileOffset = fileVec.offset; 3546 off_t fileLeft = min_c(fileVec.length, (off_t)bytesLeft); 3547 3548 TRACE(("FILE VEC [%" B_PRIu32 "] length %" B_PRIdOFF "\n", fileVecIndex, 3549 fileLeft)); 3550 3551 // process the complete fileVec 3552 while (fileLeft > 0) { 3553 iovec tempVecs[MAX_TEMP_IO_VECS]; 3554 uint32 tempCount = 0; 3555 3556 // size tracks how much of what is left of the current fileVec 3557 // (fileLeft) has been assigned to tempVecs 3558 size = 0; 3559 3560 // assign what is left of the current fileVec to the tempVecs 3561 for (size = 0; (off_t)size < fileLeft && vecIndex < vecCount 3562 && tempCount < MAX_TEMP_IO_VECS;) { 3563 // try to satisfy one iovec per iteration (or as much as 3564 // possible) 3565 3566 // bytes left of the current iovec 3567 size_t vecLeft = vecs[vecIndex].iov_len - vecOffset; 3568 if (vecLeft == 0) { 3569 vecOffset = 0; 3570 vecIndex++; 3571 continue; 3572 } 3573 3574 TRACE(("fill vec %" B_PRIu32 ", offset = %lu, size = %lu\n", 3575 vecIndex, vecOffset, size)); 3576 3577 // actually available bytes 3578 size_t tempVecSize = min_c(vecLeft, fileLeft - size); 3579 3580 tempVecs[tempCount].iov_base 3581 = (void*)((addr_t)vecs[vecIndex].iov_base + vecOffset); 3582 tempVecs[tempCount].iov_len = tempVecSize; 3583 tempCount++; 3584 3585 size += tempVecSize; 3586 vecOffset += tempVecSize; 3587 } 3588 3589 size_t bytes = size; 3590 3591 if (fileOffset == -1) { 3592 if (doWrite) { 3593 panic("sparse write attempt: vnode %p", vnode); 3594 status = B_IO_ERROR; 3595 } else { 3596 // sparse read 3597 zero_iovecs(tempVecs, tempCount, bytes); 3598 status = B_OK; 3599 } 3600 } else if (doWrite) { 3601 status = FS_CALL(vnode, write_pages, cookie, fileOffset, 3602 tempVecs, tempCount, &bytes); 3603 } else { 3604 status = FS_CALL(vnode, read_pages, cookie, fileOffset, 3605 tempVecs, tempCount, &bytes); 3606 } 3607 if (status != B_OK) 3608 return status; 3609 3610 totalSize += bytes; 3611 bytesLeft -= size; 3612 if (fileOffset >= 0) 3613 fileOffset += size; 3614 fileLeft -= size; 3615 //dprintf("-> file left = %Lu\n", fileLeft); 3616 3617 if (size != bytes || vecIndex >= vecCount) { 3618 // there are no more bytes or iovecs, let's bail out 3619 *_numBytes = totalSize; 3620 return B_OK; 3621 } 3622 } 3623 } 3624 3625 *_vecIndex = vecIndex; 3626 *_vecOffset = vecOffset; 3627 *_numBytes = totalSize; 3628 return B_OK; 3629 } 3630 3631 3632 static bool 3633 is_user_in_group(gid_t gid) 3634 { 3635 if (gid == getegid()) 3636 return true; 3637 3638 gid_t groups[NGROUPS_MAX]; 3639 int groupCount = getgroups(NGROUPS_MAX, groups); 3640 for (int i = 0; i < groupCount; i++) { 3641 if (gid == groups[i]) 3642 return true; 3643 } 3644 3645 return false; 3646 } 3647 3648 3649 static status_t 3650 free_io_context(io_context* context) 3651 { 3652 uint32 i; 3653 3654 TIOC(FreeIOContext(context)); 3655 3656 if (context->root) 3657 put_vnode(context->root); 3658 3659 if (context->cwd) 3660 put_vnode(context->cwd); 3661 3662 mutex_lock(&context->io_mutex); 3663 3664 for (i = 0; i < context->table_size; i++) { 3665 if (struct file_descriptor* descriptor = context->fds[i]) { 3666 close_fd(context, descriptor); 3667 put_fd(descriptor); 3668 } 3669 } 3670 3671 mutex_destroy(&context->io_mutex); 3672 3673 remove_node_monitors(context); 3674 free(context->fds); 3675 free(context); 3676 3677 return B_OK; 3678 } 3679 3680 3681 static status_t 3682 resize_monitor_table(struct io_context* context, const int newSize) 3683 { 3684 int status = B_OK; 3685 3686 if (newSize <= 0 || newSize > MAX_NODE_MONITORS) 3687 return B_BAD_VALUE; 3688 3689 mutex_lock(&context->io_mutex); 3690 3691 if ((size_t)newSize < context->num_monitors) { 3692 status = B_BUSY; 3693 goto out; 3694 } 3695 context->max_monitors = newSize; 3696 3697 out: 3698 mutex_unlock(&context->io_mutex); 3699 return status; 3700 } 3701 3702 3703 // #pragma mark - public API for file systems 3704 3705 3706 extern "C" status_t 3707 new_vnode(fs_volume* volume, ino_t vnodeID, void* privateNode, 3708 fs_vnode_ops* ops) 3709 { 3710 FUNCTION(("new_vnode(volume = %p (%" B_PRId32 "), vnodeID = %" B_PRId64 3711 ", node = %p)\n", volume, volume->id, vnodeID, privateNode)); 3712 3713 if (privateNode == NULL) 3714 return B_BAD_VALUE; 3715 3716 int32 tries = BUSY_VNODE_RETRIES; 3717 restart: 3718 // create the node 3719 bool nodeCreated; 3720 struct vnode* vnode; 3721 status_t status = create_new_vnode_and_lock(volume->id, vnodeID, vnode, 3722 nodeCreated); 3723 if (status != B_OK) 3724 return status; 3725 3726 WriteLocker nodeLocker(sVnodeLock, true); 3727 // create_new_vnode_and_lock() has locked for us 3728 3729 if (!nodeCreated && vnode->IsBusy()) { 3730 nodeLocker.Unlock(); 3731 if (!retry_busy_vnode(tries, volume->id, vnodeID)) 3732 return B_BUSY; 3733 goto restart; 3734 } 3735 3736 // file system integrity check: 3737 // test if the vnode already exists and bail out if this is the case! 3738 if (!nodeCreated) { 3739 panic("vnode %" B_PRIdDEV ":%" B_PRIdINO " already exists (node = %p, " 3740 "vnode->node = %p)!", volume->id, vnodeID, privateNode, 3741 vnode->private_node); 3742 return B_ERROR; 3743 } 3744 3745 vnode->private_node = privateNode; 3746 vnode->ops = ops; 3747 vnode->SetUnpublished(true); 3748 3749 TRACE(("returns: %s\n", strerror(status))); 3750 3751 return status; 3752 } 3753 3754 3755 extern "C" status_t 3756 publish_vnode(fs_volume* volume, ino_t vnodeID, void* privateNode, 3757 fs_vnode_ops* ops, int type, uint32 flags) 3758 { 3759 FUNCTION(("publish_vnode()\n")); 3760 3761 int32 tries = BUSY_VNODE_RETRIES; 3762 restart: 3763 WriteLocker locker(sVnodeLock); 3764 3765 struct vnode* vnode = lookup_vnode(volume->id, vnodeID); 3766 3767 bool nodeCreated = false; 3768 if (vnode == NULL) { 3769 if (privateNode == NULL) 3770 return B_BAD_VALUE; 3771 3772 // create the node 3773 locker.Unlock(); 3774 // create_new_vnode_and_lock() will re-lock for us on success 3775 status_t status = create_new_vnode_and_lock(volume->id, vnodeID, vnode, 3776 nodeCreated); 3777 if (status != B_OK) 3778 return status; 3779 3780 locker.SetTo(sVnodeLock, true); 3781 } 3782 3783 if (nodeCreated) { 3784 vnode->private_node = privateNode; 3785 vnode->ops = ops; 3786 vnode->SetUnpublished(true); 3787 } else if (vnode->IsBusy() && vnode->IsUnpublished() 3788 && vnode->private_node == privateNode && vnode->ops == ops) { 3789 // already known, but not published 3790 } else if (vnode->IsBusy()) { 3791 locker.Unlock(); 3792 if (!retry_busy_vnode(tries, volume->id, vnodeID)) 3793 return B_BUSY; 3794 goto restart; 3795 } else 3796 return B_BAD_VALUE; 3797 3798 bool publishSpecialSubNode = false; 3799 3800 vnode->SetType(type); 3801 vnode->SetRemoved((flags & B_VNODE_PUBLISH_REMOVED) != 0); 3802 publishSpecialSubNode = is_special_node_type(type) 3803 && (flags & B_VNODE_DONT_CREATE_SPECIAL_SUB_NODE) == 0; 3804 3805 status_t status = B_OK; 3806 3807 // create sub vnodes, if necessary 3808 if (volume->sub_volume != NULL || publishSpecialSubNode) { 3809 locker.Unlock(); 3810 3811 fs_volume* subVolume = volume; 3812 if (volume->sub_volume != NULL) { 3813 while (status == B_OK && subVolume->sub_volume != NULL) { 3814 subVolume = subVolume->sub_volume; 3815 status = subVolume->ops->create_sub_vnode(subVolume, vnodeID, 3816 vnode); 3817 } 3818 } 3819 3820 if (status == B_OK && publishSpecialSubNode) 3821 status = create_special_sub_node(vnode, flags); 3822 3823 if (status != B_OK) { 3824 // error -- clean up the created sub vnodes 3825 while (subVolume->super_volume != volume) { 3826 subVolume = subVolume->super_volume; 3827 subVolume->ops->delete_sub_vnode(subVolume, vnode); 3828 } 3829 } 3830 3831 if (status == B_OK) { 3832 ReadLocker vnodesReadLocker(sVnodeLock); 3833 AutoLocker<Vnode> nodeLocker(vnode); 3834 vnode->SetBusy(false); 3835 vnode->SetUnpublished(false); 3836 } else { 3837 locker.Lock(); 3838 sVnodeTable->Remove(vnode); 3839 remove_vnode_from_mount_list(vnode, vnode->mount); 3840 object_cache_free(sVnodeCache, vnode, 0); 3841 } 3842 } else { 3843 // we still hold the write lock -- mark the node unbusy and published 3844 vnode->SetBusy(false); 3845 vnode->SetUnpublished(false); 3846 } 3847 3848 TRACE(("returns: %s\n", strerror(status))); 3849 3850 return status; 3851 } 3852 3853 3854 extern "C" status_t 3855 get_vnode(fs_volume* volume, ino_t vnodeID, void** _privateNode) 3856 { 3857 struct vnode* vnode; 3858 3859 if (volume == NULL) 3860 return B_BAD_VALUE; 3861 3862 status_t status = get_vnode(volume->id, vnodeID, &vnode, true, true); 3863 if (status != B_OK) 3864 return status; 3865 3866 // If this is a layered FS, we need to get the node cookie for the requested 3867 // layer. 3868 if (HAS_FS_CALL(vnode, get_super_vnode)) { 3869 fs_vnode resolvedNode; 3870 status_t status = FS_CALL(vnode, get_super_vnode, volume, 3871 &resolvedNode); 3872 if (status != B_OK) { 3873 panic("get_vnode(): Failed to get super node for vnode %p, " 3874 "volume: %p", vnode, volume); 3875 put_vnode(vnode); 3876 return status; 3877 } 3878 3879 if (_privateNode != NULL) 3880 *_privateNode = resolvedNode.private_node; 3881 } else if (_privateNode != NULL) 3882 *_privateNode = vnode->private_node; 3883 3884 return B_OK; 3885 } 3886 3887 3888 extern "C" status_t 3889 acquire_vnode(fs_volume* volume, ino_t vnodeID) 3890 { 3891 struct vnode* vnode; 3892 3893 rw_lock_read_lock(&sVnodeLock); 3894 vnode = lookup_vnode(volume->id, vnodeID); 3895 rw_lock_read_unlock(&sVnodeLock); 3896 3897 if (vnode == NULL) 3898 return B_BAD_VALUE; 3899 3900 inc_vnode_ref_count(vnode); 3901 return B_OK; 3902 } 3903 3904 3905 extern "C" status_t 3906 put_vnode(fs_volume* volume, ino_t vnodeID) 3907 { 3908 struct vnode* vnode; 3909 3910 rw_lock_read_lock(&sVnodeLock); 3911 vnode = lookup_vnode(volume->id, vnodeID); 3912 rw_lock_read_unlock(&sVnodeLock); 3913 3914 if (vnode == NULL) 3915 return B_BAD_VALUE; 3916 3917 dec_vnode_ref_count(vnode, false, true); 3918 return B_OK; 3919 } 3920 3921 3922 extern "C" status_t 3923 remove_vnode(fs_volume* volume, ino_t vnodeID) 3924 { 3925 ReadLocker locker(sVnodeLock); 3926 3927 struct vnode* vnode = lookup_vnode(volume->id, vnodeID); 3928 if (vnode == NULL) 3929 return B_ENTRY_NOT_FOUND; 3930 3931 if (vnode->covered_by != NULL || vnode->covers != NULL) { 3932 // this vnode is in use 3933 return B_BUSY; 3934 } 3935 3936 vnode->Lock(); 3937 3938 vnode->SetRemoved(true); 3939 bool removeUnpublished = false; 3940 3941 if (vnode->IsUnpublished()) { 3942 // prepare the vnode for deletion 3943 removeUnpublished = true; 3944 vnode->SetBusy(true); 3945 } 3946 3947 vnode->Unlock(); 3948 locker.Unlock(); 3949 3950 if (removeUnpublished) { 3951 // If the vnode hasn't been published yet, we delete it here 3952 atomic_add(&vnode->ref_count, -1); 3953 free_vnode(vnode, true); 3954 } 3955 3956 return B_OK; 3957 } 3958 3959 3960 extern "C" status_t 3961 unremove_vnode(fs_volume* volume, ino_t vnodeID) 3962 { 3963 struct vnode* vnode; 3964 3965 rw_lock_read_lock(&sVnodeLock); 3966 3967 vnode = lookup_vnode(volume->id, vnodeID); 3968 if (vnode) { 3969 AutoLocker<Vnode> nodeLocker(vnode); 3970 vnode->SetRemoved(false); 3971 } 3972 3973 rw_lock_read_unlock(&sVnodeLock); 3974 return B_OK; 3975 } 3976 3977 3978 extern "C" status_t 3979 get_vnode_removed(fs_volume* volume, ino_t vnodeID, bool* _removed) 3980 { 3981 ReadLocker _(sVnodeLock); 3982 3983 if (struct vnode* vnode = lookup_vnode(volume->id, vnodeID)) { 3984 if (_removed != NULL) 3985 *_removed = vnode->IsRemoved(); 3986 return B_OK; 3987 } 3988 3989 return B_BAD_VALUE; 3990 } 3991 3992 3993 extern "C" fs_volume* 3994 volume_for_vnode(fs_vnode* _vnode) 3995 { 3996 if (_vnode == NULL) 3997 return NULL; 3998 3999 struct vnode* vnode = static_cast<struct vnode*>(_vnode); 4000 return vnode->mount->volume; 4001 } 4002 4003 4004 extern "C" status_t 4005 check_access_permissions(int accessMode, mode_t mode, gid_t nodeGroupID, 4006 uid_t nodeUserID) 4007 { 4008 // get node permissions 4009 int userPermissions = (mode & S_IRWXU) >> 6; 4010 int groupPermissions = (mode & S_IRWXG) >> 3; 4011 int otherPermissions = mode & S_IRWXO; 4012 4013 // get the node permissions for this uid/gid 4014 int permissions = 0; 4015 uid_t uid = geteuid(); 4016 4017 if (uid == 0) { 4018 // user is root 4019 // root has always read/write permission, but at least one of the 4020 // X bits must be set for execute permission 4021 permissions = userPermissions | groupPermissions | otherPermissions 4022 | S_IROTH | S_IWOTH; 4023 if (S_ISDIR(mode)) 4024 permissions |= S_IXOTH; 4025 } else if (uid == nodeUserID) { 4026 // user is node owner 4027 permissions = userPermissions; 4028 } else if (is_user_in_group(nodeGroupID)) { 4029 // user is in owning group 4030 permissions = groupPermissions; 4031 } else { 4032 // user is one of the others 4033 permissions = otherPermissions; 4034 } 4035 4036 return (accessMode & ~permissions) == 0 ? B_OK : B_PERMISSION_DENIED; 4037 } 4038 4039 4040 #if 0 4041 extern "C" status_t 4042 read_pages(int fd, off_t pos, const iovec* vecs, size_t count, 4043 size_t* _numBytes) 4044 { 4045 struct file_descriptor* descriptor; 4046 struct vnode* vnode; 4047 4048 descriptor = get_fd_and_vnode(fd, &vnode, true); 4049 if (descriptor == NULL) 4050 return B_FILE_ERROR; 4051 4052 status_t status = vfs_read_pages(vnode, descriptor->cookie, pos, vecs, 4053 count, 0, _numBytes); 4054 4055 put_fd(descriptor); 4056 return status; 4057 } 4058 4059 4060 extern "C" status_t 4061 write_pages(int fd, off_t pos, const iovec* vecs, size_t count, 4062 size_t* _numBytes) 4063 { 4064 struct file_descriptor* descriptor; 4065 struct vnode* vnode; 4066 4067 descriptor = get_fd_and_vnode(fd, &vnode, true); 4068 if (descriptor == NULL) 4069 return B_FILE_ERROR; 4070 4071 status_t status = vfs_write_pages(vnode, descriptor->cookie, pos, vecs, 4072 count, 0, _numBytes); 4073 4074 put_fd(descriptor); 4075 return status; 4076 } 4077 #endif 4078 4079 4080 extern "C" status_t 4081 read_file_io_vec_pages(int fd, const file_io_vec* fileVecs, size_t fileVecCount, 4082 const iovec* vecs, size_t vecCount, uint32* _vecIndex, size_t* _vecOffset, 4083 size_t* _bytes) 4084 { 4085 struct file_descriptor* descriptor; 4086 struct vnode* vnode; 4087 4088 descriptor = get_fd_and_vnode(fd, &vnode, true); 4089 if (descriptor == NULL) 4090 return B_FILE_ERROR; 4091 4092 status_t status = common_file_io_vec_pages(vnode, descriptor->cookie, 4093 fileVecs, fileVecCount, vecs, vecCount, _vecIndex, _vecOffset, _bytes, 4094 false); 4095 4096 put_fd(descriptor); 4097 return status; 4098 } 4099 4100 4101 extern "C" status_t 4102 write_file_io_vec_pages(int fd, const file_io_vec* fileVecs, size_t fileVecCount, 4103 const iovec* vecs, size_t vecCount, uint32* _vecIndex, size_t* _vecOffset, 4104 size_t* _bytes) 4105 { 4106 struct file_descriptor* descriptor; 4107 struct vnode* vnode; 4108 4109 descriptor = get_fd_and_vnode(fd, &vnode, true); 4110 if (descriptor == NULL) 4111 return B_FILE_ERROR; 4112 4113 status_t status = common_file_io_vec_pages(vnode, descriptor->cookie, 4114 fileVecs, fileVecCount, vecs, vecCount, _vecIndex, _vecOffset, _bytes, 4115 true); 4116 4117 put_fd(descriptor); 4118 return status; 4119 } 4120 4121 4122 extern "C" status_t 4123 entry_cache_add(dev_t mountID, ino_t dirID, const char* name, ino_t nodeID) 4124 { 4125 // lookup mount -- the caller is required to make sure that the mount 4126 // won't go away 4127 ReadLocker locker(sMountLock); 4128 struct fs_mount* mount = find_mount(mountID); 4129 if (mount == NULL) 4130 return B_BAD_VALUE; 4131 locker.Unlock(); 4132 4133 return mount->entry_cache.Add(dirID, name, nodeID, false); 4134 } 4135 4136 4137 extern "C" status_t 4138 entry_cache_add_missing(dev_t mountID, ino_t dirID, const char* name) 4139 { 4140 // lookup mount -- the caller is required to make sure that the mount 4141 // won't go away 4142 ReadLocker locker(sMountLock); 4143 struct fs_mount* mount = find_mount(mountID); 4144 if (mount == NULL) 4145 return B_BAD_VALUE; 4146 locker.Unlock(); 4147 4148 return mount->entry_cache.Add(dirID, name, -1, true); 4149 } 4150 4151 4152 extern "C" status_t 4153 entry_cache_remove(dev_t mountID, ino_t dirID, const char* name) 4154 { 4155 // lookup mount -- the caller is required to make sure that the mount 4156 // won't go away 4157 ReadLocker locker(sMountLock); 4158 struct fs_mount* mount = find_mount(mountID); 4159 if (mount == NULL) 4160 return B_BAD_VALUE; 4161 locker.Unlock(); 4162 4163 return mount->entry_cache.Remove(dirID, name); 4164 } 4165 4166 4167 // #pragma mark - private VFS API 4168 // Functions the VFS exports for other parts of the kernel 4169 4170 4171 /*! Acquires another reference to the vnode that has to be released 4172 by calling vfs_put_vnode(). 4173 */ 4174 void 4175 vfs_acquire_vnode(struct vnode* vnode) 4176 { 4177 inc_vnode_ref_count(vnode); 4178 } 4179 4180 4181 /*! This is currently called from file_cache_create() only. 4182 It's probably a temporary solution as long as devfs requires that 4183 fs_read_pages()/fs_write_pages() are called with the standard 4184 open cookie and not with a device cookie. 4185 If that's done differently, remove this call; it has no other 4186 purpose. 4187 */ 4188 extern "C" status_t 4189 vfs_get_cookie_from_fd(int fd, void** _cookie) 4190 { 4191 struct file_descriptor* descriptor; 4192 4193 descriptor = get_fd(get_current_io_context(true), fd); 4194 if (descriptor == NULL) 4195 return B_FILE_ERROR; 4196 4197 *_cookie = descriptor->cookie; 4198 return B_OK; 4199 } 4200 4201 4202 extern "C" status_t 4203 vfs_get_vnode_from_fd(int fd, bool kernel, struct vnode** vnode) 4204 { 4205 *vnode = get_vnode_from_fd(fd, kernel); 4206 4207 if (*vnode == NULL) 4208 return B_FILE_ERROR; 4209 4210 return B_NO_ERROR; 4211 } 4212 4213 4214 extern "C" status_t 4215 vfs_get_vnode_from_path(const char* path, bool kernel, struct vnode** _vnode) 4216 { 4217 TRACE(("vfs_get_vnode_from_path: entry. path = '%s', kernel %d\n", 4218 path, kernel)); 4219 4220 KPath pathBuffer; 4221 if (pathBuffer.InitCheck() != B_OK) 4222 return B_NO_MEMORY; 4223 4224 char* buffer = pathBuffer.LockBuffer(); 4225 strlcpy(buffer, path, pathBuffer.BufferSize()); 4226 4227 struct vnode* vnode; 4228 status_t status = path_to_vnode(buffer, true, &vnode, NULL, kernel); 4229 if (status != B_OK) 4230 return status; 4231 4232 *_vnode = vnode; 4233 return B_OK; 4234 } 4235 4236 4237 extern "C" status_t 4238 vfs_get_vnode(dev_t mountID, ino_t vnodeID, bool canWait, struct vnode** _vnode) 4239 { 4240 struct vnode* vnode = NULL; 4241 4242 status_t status = get_vnode(mountID, vnodeID, &vnode, canWait, false); 4243 if (status != B_OK) 4244 return status; 4245 4246 *_vnode = vnode; 4247 return B_OK; 4248 } 4249 4250 4251 extern "C" status_t 4252 vfs_entry_ref_to_vnode(dev_t mountID, ino_t directoryID, 4253 const char* name, struct vnode** _vnode) 4254 { 4255 return entry_ref_to_vnode(mountID, directoryID, name, false, true, _vnode); 4256 } 4257 4258 4259 extern "C" void 4260 vfs_vnode_to_node_ref(struct vnode* vnode, dev_t* _mountID, ino_t* _vnodeID) 4261 { 4262 *_mountID = vnode->device; 4263 *_vnodeID = vnode->id; 4264 } 4265 4266 4267 /*! 4268 Helper function abstracting the process of "converting" a given 4269 vnode-pointer to a fs_vnode-pointer. 4270 Currently only used in bindfs. 4271 */ 4272 extern "C" fs_vnode* 4273 vfs_fsnode_for_vnode(struct vnode* vnode) 4274 { 4275 return vnode; 4276 } 4277 4278 4279 /*! 4280 Calls fs_open() on the given vnode and returns a new 4281 file descriptor for it 4282 */ 4283 int 4284 vfs_open_vnode(struct vnode* vnode, int openMode, bool kernel) 4285 { 4286 return open_vnode(vnode, openMode, kernel); 4287 } 4288 4289 4290 /*! Looks up a vnode with the given mount and vnode ID. 4291 Must only be used with "in-use" vnodes as it doesn't grab a reference 4292 to the node. 4293 It's currently only be used by file_cache_create(). 4294 */ 4295 extern "C" status_t 4296 vfs_lookup_vnode(dev_t mountID, ino_t vnodeID, struct vnode** _vnode) 4297 { 4298 rw_lock_read_lock(&sVnodeLock); 4299 struct vnode* vnode = lookup_vnode(mountID, vnodeID); 4300 rw_lock_read_unlock(&sVnodeLock); 4301 4302 if (vnode == NULL) 4303 return B_ERROR; 4304 4305 *_vnode = vnode; 4306 return B_OK; 4307 } 4308 4309 4310 extern "C" status_t 4311 vfs_get_fs_node_from_path(fs_volume* volume, const char* path, 4312 bool traverseLeafLink, bool kernel, void** _node) 4313 { 4314 TRACE(("vfs_get_fs_node_from_path(volume = %p, path = \"%s\", kernel %d)\n", 4315 volume, path, kernel)); 4316 4317 KPath pathBuffer; 4318 if (pathBuffer.InitCheck() != B_OK) 4319 return B_NO_MEMORY; 4320 4321 fs_mount* mount; 4322 status_t status = get_mount(volume->id, &mount); 4323 if (status != B_OK) 4324 return status; 4325 4326 char* buffer = pathBuffer.LockBuffer(); 4327 strlcpy(buffer, path, pathBuffer.BufferSize()); 4328 4329 struct vnode* vnode = mount->root_vnode; 4330 4331 if (buffer[0] == '/') 4332 status = path_to_vnode(buffer, traverseLeafLink, &vnode, NULL, kernel); 4333 else { 4334 inc_vnode_ref_count(vnode); 4335 // vnode_path_to_vnode() releases a reference to the starting vnode 4336 status = vnode_path_to_vnode(vnode, buffer, traverseLeafLink, 0, 4337 kernel, &vnode, NULL); 4338 } 4339 4340 put_mount(mount); 4341 4342 if (status != B_OK) 4343 return status; 4344 4345 if (vnode->device != volume->id) { 4346 // wrong mount ID - must not gain access on foreign file system nodes 4347 put_vnode(vnode); 4348 return B_BAD_VALUE; 4349 } 4350 4351 // Use get_vnode() to resolve the cookie for the right layer. 4352 status = get_vnode(volume, vnode->id, _node); 4353 put_vnode(vnode); 4354 4355 return status; 4356 } 4357 4358 4359 status_t 4360 vfs_read_stat(int fd, const char* path, bool traverseLeafLink, 4361 struct stat* stat, bool kernel) 4362 { 4363 status_t status; 4364 4365 if (path != NULL) { 4366 // path given: get the stat of the node referred to by (fd, path) 4367 KPath pathBuffer(path); 4368 if (pathBuffer.InitCheck() != B_OK) 4369 return B_NO_MEMORY; 4370 4371 status = common_path_read_stat(fd, pathBuffer.LockBuffer(), 4372 traverseLeafLink, stat, kernel); 4373 } else { 4374 // no path given: get the FD and use the FD operation 4375 struct file_descriptor* descriptor 4376 = get_fd(get_current_io_context(kernel), fd); 4377 if (descriptor == NULL) 4378 return B_FILE_ERROR; 4379 4380 if (descriptor->ops->fd_read_stat) 4381 status = descriptor->ops->fd_read_stat(descriptor, stat); 4382 else 4383 status = B_UNSUPPORTED; 4384 4385 put_fd(descriptor); 4386 } 4387 4388 return status; 4389 } 4390 4391 4392 /*! Finds the full path to the file that contains the module \a moduleName, 4393 puts it into \a pathBuffer, and returns B_OK for success. 4394 If \a pathBuffer was too small, it returns \c B_BUFFER_OVERFLOW, 4395 \c B_ENTRY_NOT_FOUNT if no file could be found. 4396 \a pathBuffer is clobbered in any case and must not be relied on if this 4397 functions returns unsuccessfully. 4398 \a basePath and \a pathBuffer must not point to the same space. 4399 */ 4400 status_t 4401 vfs_get_module_path(const char* basePath, const char* moduleName, 4402 char* pathBuffer, size_t bufferSize) 4403 { 4404 struct vnode* dir; 4405 struct vnode* file; 4406 status_t status; 4407 size_t length; 4408 char* path; 4409 4410 if (bufferSize == 0 4411 || strlcpy(pathBuffer, basePath, bufferSize) >= bufferSize) 4412 return B_BUFFER_OVERFLOW; 4413 4414 status = path_to_vnode(pathBuffer, true, &dir, NULL, true); 4415 if (status != B_OK) 4416 return status; 4417 4418 // the path buffer had been clobbered by the above call 4419 length = strlcpy(pathBuffer, basePath, bufferSize); 4420 if (pathBuffer[length - 1] != '/') 4421 pathBuffer[length++] = '/'; 4422 4423 path = pathBuffer + length; 4424 bufferSize -= length; 4425 4426 while (moduleName) { 4427 char* nextPath = strchr(moduleName, '/'); 4428 if (nextPath == NULL) 4429 length = strlen(moduleName); 4430 else { 4431 length = nextPath - moduleName; 4432 nextPath++; 4433 } 4434 4435 if (length + 1 >= bufferSize) { 4436 status = B_BUFFER_OVERFLOW; 4437 goto err; 4438 } 4439 4440 memcpy(path, moduleName, length); 4441 path[length] = '\0'; 4442 moduleName = nextPath; 4443 4444 status = vnode_path_to_vnode(dir, path, true, 0, true, &file, NULL); 4445 if (status != B_OK) { 4446 // vnode_path_to_vnode() has already released the reference to dir 4447 return status; 4448 } 4449 4450 if (S_ISDIR(file->Type())) { 4451 // goto the next directory 4452 path[length] = '/'; 4453 path[length + 1] = '\0'; 4454 path += length + 1; 4455 bufferSize -= length + 1; 4456 4457 dir = file; 4458 } else if (S_ISREG(file->Type())) { 4459 // it's a file so it should be what we've searched for 4460 put_vnode(file); 4461 4462 return B_OK; 4463 } else { 4464 TRACE(("vfs_get_module_path(): something is strange here: " 4465 "0x%08" B_PRIx32 "...\n", file->Type())); 4466 status = B_ERROR; 4467 dir = file; 4468 goto err; 4469 } 4470 } 4471 4472 // if we got here, the moduleName just pointed to a directory, not to 4473 // a real module - what should we do in this case? 4474 status = B_ENTRY_NOT_FOUND; 4475 4476 err: 4477 put_vnode(dir); 4478 return status; 4479 } 4480 4481 4482 /*! \brief Normalizes a given path. 4483 4484 The path must refer to an existing or non-existing entry in an existing 4485 directory, that is chopping off the leaf component the remaining path must 4486 refer to an existing directory. 4487 4488 The returned will be canonical in that it will be absolute, will not 4489 contain any "." or ".." components or duplicate occurrences of '/'s, 4490 and none of the directory components will by symbolic links. 4491 4492 Any two paths referring to the same entry, will result in the same 4493 normalized path (well, that is pretty much the definition of `normalized', 4494 isn't it :-). 4495 4496 \param path The path to be normalized. 4497 \param buffer The buffer into which the normalized path will be written. 4498 May be the same one as \a path. 4499 \param bufferSize The size of \a buffer. 4500 \param traverseLink If \c true, the function also resolves leaf symlinks. 4501 \param kernel \c true, if the IO context of the kernel shall be used, 4502 otherwise that of the team this thread belongs to. Only relevant, 4503 if the path is relative (to get the CWD). 4504 \return \c B_OK if everything went fine, another error code otherwise. 4505 */ 4506 status_t 4507 vfs_normalize_path(const char* path, char* buffer, size_t bufferSize, 4508 bool traverseLink, bool kernel) 4509 { 4510 if (!path || !buffer || bufferSize < 1) 4511 return B_BAD_VALUE; 4512 4513 if (path != buffer) { 4514 if (strlcpy(buffer, path, bufferSize) >= bufferSize) 4515 return B_BUFFER_OVERFLOW; 4516 } 4517 4518 return normalize_path(buffer, bufferSize, traverseLink, kernel); 4519 } 4520 4521 4522 /*! \brief Gets the parent of the passed in node. 4523 4524 Gets the parent of the passed in node, and correctly resolves covered 4525 nodes. 4526 */ 4527 extern "C" status_t 4528 vfs_resolve_parent(struct vnode* parent, dev_t* device, ino_t* node) 4529 { 4530 return resolve_covered_parent(parent, device, node, 4531 get_current_io_context(true)); 4532 } 4533 4534 4535 /*! \brief Creates a special node in the file system. 4536 4537 The caller gets a reference to the newly created node (which is passed 4538 back through \a _createdVnode) and is responsible for releasing it. 4539 4540 \param path The path where to create the entry for the node. Can be \c NULL, 4541 in which case the node is created without an entry in the root FS -- it 4542 will automatically be deleted when the last reference has been released. 4543 \param subVnode The definition of the subnode. Can be \c NULL, in which case 4544 the target file system will just create the node with its standard 4545 operations. Depending on the type of the node a subnode might be created 4546 automatically, though. 4547 \param mode The type and permissions for the node to be created. 4548 \param flags Flags to be passed to the creating FS. 4549 \param kernel \c true, if called in the kernel context (relevant only if 4550 \a path is not \c NULL and not absolute). 4551 \param _superVnode Pointer to a pre-allocated structure to be filled by the 4552 file system creating the node, with the private data pointer and 4553 operations for the super node. Can be \c NULL. 4554 \param _createVnode Pointer to pre-allocated storage where to store the 4555 pointer to the newly created node. 4556 \return \c B_OK, if everything went fine, another error code otherwise. 4557 */ 4558 status_t 4559 vfs_create_special_node(const char* path, fs_vnode* subVnode, mode_t mode, 4560 uint32 flags, bool kernel, fs_vnode* _superVnode, 4561 struct vnode** _createdVnode) 4562 { 4563 struct vnode* dirNode; 4564 char _leaf[B_FILE_NAME_LENGTH]; 4565 char* leaf = NULL; 4566 4567 if (path) { 4568 // We've got a path. Get the dir vnode and the leaf name. 4569 KPath tmpPathBuffer; 4570 if (tmpPathBuffer.InitCheck() != B_OK) 4571 return B_NO_MEMORY; 4572 4573 char* tmpPath = tmpPathBuffer.LockBuffer(); 4574 if (strlcpy(tmpPath, path, B_PATH_NAME_LENGTH) >= B_PATH_NAME_LENGTH) 4575 return B_NAME_TOO_LONG; 4576 4577 // get the dir vnode and the leaf name 4578 leaf = _leaf; 4579 status_t error = path_to_dir_vnode(tmpPath, &dirNode, leaf, kernel); 4580 if (error != B_OK) 4581 return error; 4582 } else { 4583 // No path. Create the node in the root FS. 4584 dirNode = sRoot; 4585 inc_vnode_ref_count(dirNode); 4586 } 4587 4588 VNodePutter _(dirNode); 4589 4590 // check support for creating special nodes 4591 if (!HAS_FS_CALL(dirNode, create_special_node)) 4592 return B_UNSUPPORTED; 4593 4594 // create the node 4595 fs_vnode superVnode; 4596 ino_t nodeID; 4597 status_t status = FS_CALL(dirNode, create_special_node, leaf, subVnode, 4598 mode, flags, _superVnode != NULL ? _superVnode : &superVnode, &nodeID); 4599 if (status != B_OK) 4600 return status; 4601 4602 // lookup the node 4603 rw_lock_read_lock(&sVnodeLock); 4604 *_createdVnode = lookup_vnode(dirNode->mount->id, nodeID); 4605 rw_lock_read_unlock(&sVnodeLock); 4606 4607 if (*_createdVnode == NULL) { 4608 panic("vfs_create_special_node(): lookup of node failed"); 4609 return B_ERROR; 4610 } 4611 4612 return B_OK; 4613 } 4614 4615 4616 extern "C" void 4617 vfs_put_vnode(struct vnode* vnode) 4618 { 4619 put_vnode(vnode); 4620 } 4621 4622 4623 extern "C" status_t 4624 vfs_get_cwd(dev_t* _mountID, ino_t* _vnodeID) 4625 { 4626 // Get current working directory from io context 4627 struct io_context* context = get_current_io_context(false); 4628 status_t status = B_OK; 4629 4630 mutex_lock(&context->io_mutex); 4631 4632 if (context->cwd != NULL) { 4633 *_mountID = context->cwd->device; 4634 *_vnodeID = context->cwd->id; 4635 } else 4636 status = B_ERROR; 4637 4638 mutex_unlock(&context->io_mutex); 4639 return status; 4640 } 4641 4642 4643 status_t 4644 vfs_unmount(dev_t mountID, uint32 flags) 4645 { 4646 return fs_unmount(NULL, mountID, flags, true); 4647 } 4648 4649 4650 extern "C" status_t 4651 vfs_disconnect_vnode(dev_t mountID, ino_t vnodeID) 4652 { 4653 struct vnode* vnode; 4654 4655 status_t status = get_vnode(mountID, vnodeID, &vnode, true, true); 4656 if (status != B_OK) 4657 return status; 4658 4659 disconnect_mount_or_vnode_fds(vnode->mount, vnode); 4660 put_vnode(vnode); 4661 return B_OK; 4662 } 4663 4664 4665 extern "C" void 4666 vfs_free_unused_vnodes(int32 level) 4667 { 4668 vnode_low_resource_handler(NULL, 4669 B_KERNEL_RESOURCE_PAGES | B_KERNEL_RESOURCE_MEMORY 4670 | B_KERNEL_RESOURCE_ADDRESS_SPACE, 4671 level); 4672 } 4673 4674 4675 extern "C" bool 4676 vfs_can_page(struct vnode* vnode, void* cookie) 4677 { 4678 FUNCTION(("vfs_canpage: vnode %p\n", vnode)); 4679 4680 if (HAS_FS_CALL(vnode, can_page)) 4681 return FS_CALL(vnode, can_page, cookie); 4682 return false; 4683 } 4684 4685 4686 extern "C" status_t 4687 vfs_read_pages(struct vnode* vnode, void* cookie, off_t pos, 4688 const generic_io_vec* vecs, size_t count, uint32 flags, 4689 generic_size_t* _numBytes) 4690 { 4691 FUNCTION(("vfs_read_pages: vnode %p, vecs %p, pos %" B_PRIdOFF "\n", vnode, 4692 vecs, pos)); 4693 4694 #if VFS_PAGES_IO_TRACING 4695 generic_size_t bytesRequested = *_numBytes; 4696 #endif 4697 4698 IORequest request; 4699 status_t status = request.Init(pos, vecs, count, *_numBytes, false, flags); 4700 if (status == B_OK) { 4701 status = vfs_vnode_io(vnode, cookie, &request); 4702 if (status == B_OK) 4703 status = request.Wait(); 4704 *_numBytes = request.TransferredBytes(); 4705 } 4706 4707 TPIO(ReadPages(vnode, cookie, pos, vecs, count, flags, bytesRequested, 4708 status, *_numBytes)); 4709 4710 return status; 4711 } 4712 4713 4714 extern "C" status_t 4715 vfs_write_pages(struct vnode* vnode, void* cookie, off_t pos, 4716 const generic_io_vec* vecs, size_t count, uint32 flags, 4717 generic_size_t* _numBytes) 4718 { 4719 FUNCTION(("vfs_write_pages: vnode %p, vecs %p, pos %" B_PRIdOFF "\n", vnode, 4720 vecs, pos)); 4721 4722 #if VFS_PAGES_IO_TRACING 4723 generic_size_t bytesRequested = *_numBytes; 4724 #endif 4725 4726 IORequest request; 4727 status_t status = request.Init(pos, vecs, count, *_numBytes, true, flags); 4728 if (status == B_OK) { 4729 status = vfs_vnode_io(vnode, cookie, &request); 4730 if (status == B_OK) 4731 status = request.Wait(); 4732 *_numBytes = request.TransferredBytes(); 4733 } 4734 4735 TPIO(WritePages(vnode, cookie, pos, vecs, count, flags, bytesRequested, 4736 status, *_numBytes)); 4737 4738 return status; 4739 } 4740 4741 4742 /*! Gets the vnode's VMCache object. If it didn't have one, it will be 4743 created if \a allocate is \c true. 4744 In case it's successful, it will also grab a reference to the cache 4745 it returns. 4746 */ 4747 extern "C" status_t 4748 vfs_get_vnode_cache(struct vnode* vnode, VMCache** _cache, bool allocate) 4749 { 4750 if (vnode->cache != NULL) { 4751 vnode->cache->AcquireRef(); 4752 *_cache = vnode->cache; 4753 return B_OK; 4754 } 4755 4756 rw_lock_read_lock(&sVnodeLock); 4757 vnode->Lock(); 4758 4759 status_t status = B_OK; 4760 4761 // The cache could have been created in the meantime 4762 if (vnode->cache == NULL) { 4763 if (allocate) { 4764 // TODO: actually the vnode needs to be busy already here, or 4765 // else this won't work... 4766 bool wasBusy = vnode->IsBusy(); 4767 vnode->SetBusy(true); 4768 4769 vnode->Unlock(); 4770 rw_lock_read_unlock(&sVnodeLock); 4771 4772 status = vm_create_vnode_cache(vnode, &vnode->cache); 4773 4774 rw_lock_read_lock(&sVnodeLock); 4775 vnode->Lock(); 4776 vnode->SetBusy(wasBusy); 4777 } else 4778 status = B_BAD_VALUE; 4779 } 4780 4781 vnode->Unlock(); 4782 rw_lock_read_unlock(&sVnodeLock); 4783 4784 if (status == B_OK) { 4785 vnode->cache->AcquireRef(); 4786 *_cache = vnode->cache; 4787 } 4788 4789 return status; 4790 } 4791 4792 4793 /*! Sets the vnode's VMCache object, for subsystems that want to manage 4794 their own. 4795 In case it's successful, it will also grab a reference to the cache 4796 it returns. 4797 */ 4798 extern "C" status_t 4799 vfs_set_vnode_cache(struct vnode* vnode, VMCache* _cache) 4800 { 4801 rw_lock_read_lock(&sVnodeLock); 4802 vnode->Lock(); 4803 4804 status_t status = B_OK; 4805 if (vnode->cache != NULL) { 4806 status = B_NOT_ALLOWED; 4807 } else { 4808 vnode->cache = _cache; 4809 _cache->AcquireRef(); 4810 } 4811 4812 vnode->Unlock(); 4813 rw_lock_read_unlock(&sVnodeLock); 4814 return status; 4815 } 4816 4817 4818 status_t 4819 vfs_get_file_map(struct vnode* vnode, off_t offset, size_t size, 4820 file_io_vec* vecs, size_t* _count) 4821 { 4822 FUNCTION(("vfs_get_file_map: vnode %p, vecs %p, offset %" B_PRIdOFF 4823 ", size = %" B_PRIuSIZE "\n", vnode, vecs, offset, size)); 4824 4825 return FS_CALL(vnode, get_file_map, offset, size, vecs, _count); 4826 } 4827 4828 4829 status_t 4830 vfs_stat_vnode(struct vnode* vnode, struct stat* stat) 4831 { 4832 status_t status = FS_CALL(vnode, read_stat, stat); 4833 4834 // fill in the st_dev and st_ino fields 4835 if (status == B_OK) { 4836 stat->st_dev = vnode->device; 4837 stat->st_ino = vnode->id; 4838 // the rdev field must stay unset for non-special files 4839 if (!S_ISBLK(stat->st_mode) && !S_ISCHR(stat->st_mode)) 4840 stat->st_rdev = -1; 4841 } 4842 4843 return status; 4844 } 4845 4846 4847 status_t 4848 vfs_stat_node_ref(dev_t device, ino_t inode, struct stat* stat) 4849 { 4850 struct vnode* vnode; 4851 status_t status = get_vnode(device, inode, &vnode, true, false); 4852 if (status != B_OK) 4853 return status; 4854 4855 status = vfs_stat_vnode(vnode, stat); 4856 4857 put_vnode(vnode); 4858 return status; 4859 } 4860 4861 4862 status_t 4863 vfs_get_vnode_name(struct vnode* vnode, char* name, size_t nameSize) 4864 { 4865 return get_vnode_name(vnode, NULL, name, nameSize, true); 4866 } 4867 4868 4869 status_t 4870 vfs_entry_ref_to_path(dev_t device, ino_t inode, const char* leaf, 4871 bool kernel, char* path, size_t pathLength) 4872 { 4873 struct vnode* vnode; 4874 status_t status; 4875 4876 // filter invalid leaf names 4877 if (leaf != NULL && (leaf[0] == '\0' || strchr(leaf, '/'))) 4878 return B_BAD_VALUE; 4879 4880 // get the vnode matching the dir's node_ref 4881 if (leaf && (strcmp(leaf, ".") == 0 || strcmp(leaf, "..") == 0)) { 4882 // special cases "." and "..": we can directly get the vnode of the 4883 // referenced directory 4884 status = entry_ref_to_vnode(device, inode, leaf, false, kernel, &vnode); 4885 leaf = NULL; 4886 } else 4887 status = get_vnode(device, inode, &vnode, true, false); 4888 if (status != B_OK) 4889 return status; 4890 4891 // get the directory path 4892 status = dir_vnode_to_path(vnode, path, pathLength, kernel); 4893 put_vnode(vnode); 4894 // we don't need the vnode anymore 4895 if (status != B_OK) 4896 return status; 4897 4898 // append the leaf name 4899 if (leaf) { 4900 // insert a directory separator if this is not the file system root 4901 if ((strcmp(path, "/") && strlcat(path, "/", pathLength) 4902 >= pathLength) 4903 || strlcat(path, leaf, pathLength) >= pathLength) { 4904 return B_NAME_TOO_LONG; 4905 } 4906 } 4907 4908 return B_OK; 4909 } 4910 4911 4912 /*! If the given descriptor locked its vnode, that lock will be released. */ 4913 void 4914 vfs_unlock_vnode_if_locked(struct file_descriptor* descriptor) 4915 { 4916 struct vnode* vnode = fd_vnode(descriptor); 4917 4918 if (vnode != NULL && vnode->mandatory_locked_by == descriptor) 4919 vnode->mandatory_locked_by = NULL; 4920 } 4921 4922 4923 /*! Releases any POSIX locks on the file descriptor. */ 4924 status_t 4925 vfs_release_posix_lock(io_context* context, struct file_descriptor* descriptor) 4926 { 4927 struct vnode* vnode = descriptor->u.vnode; 4928 if (vnode == NULL) 4929 return B_OK; 4930 4931 if (HAS_FS_CALL(vnode, release_lock)) 4932 return FS_CALL(vnode, release_lock, descriptor->cookie, NULL); 4933 4934 return release_advisory_lock(vnode, context, NULL, NULL); 4935 } 4936 4937 4938 /*! Closes all file descriptors of the specified I/O context that 4939 have the O_CLOEXEC flag set. 4940 */ 4941 void 4942 vfs_exec_io_context(io_context* context) 4943 { 4944 uint32 i; 4945 4946 for (i = 0; i < context->table_size; i++) { 4947 mutex_lock(&context->io_mutex); 4948 4949 struct file_descriptor* descriptor = context->fds[i]; 4950 bool remove = false; 4951 4952 if (descriptor != NULL && fd_close_on_exec(context, i)) { 4953 context->fds[i] = NULL; 4954 context->num_used_fds--; 4955 4956 remove = true; 4957 } 4958 4959 mutex_unlock(&context->io_mutex); 4960 4961 if (remove) { 4962 close_fd(context, descriptor); 4963 put_fd(descriptor); 4964 } 4965 } 4966 } 4967 4968 4969 /*! Sets up a new io_control structure, and inherits the properties 4970 of the parent io_control if it is given. 4971 */ 4972 io_context* 4973 vfs_new_io_context(io_context* parentContext, bool purgeCloseOnExec) 4974 { 4975 io_context* context = (io_context*)malloc(sizeof(io_context)); 4976 if (context == NULL) 4977 return NULL; 4978 4979 TIOC(NewIOContext(context, parentContext)); 4980 4981 memset(context, 0, sizeof(io_context)); 4982 context->ref_count = 1; 4983 4984 MutexLocker parentLocker; 4985 4986 size_t tableSize; 4987 if (parentContext != NULL) { 4988 parentLocker.SetTo(parentContext->io_mutex, false); 4989 tableSize = parentContext->table_size; 4990 } else 4991 tableSize = DEFAULT_FD_TABLE_SIZE; 4992 4993 // allocate space for FDs and their close-on-exec flag 4994 context->fds = (file_descriptor**)malloc( 4995 sizeof(struct file_descriptor*) * tableSize 4996 + sizeof(struct select_info**) * tableSize 4997 + (tableSize + 7) / 8); 4998 if (context->fds == NULL) { 4999 free(context); 5000 return NULL; 5001 } 5002 5003 context->select_infos = (select_info**)(context->fds + tableSize); 5004 context->fds_close_on_exec = (uint8*)(context->select_infos + tableSize); 5005 5006 memset(context->fds, 0, sizeof(struct file_descriptor*) * tableSize 5007 + sizeof(struct select_info**) * tableSize 5008 + (tableSize + 7) / 8); 5009 5010 mutex_init(&context->io_mutex, "I/O context"); 5011 5012 // Copy all parent file descriptors 5013 5014 if (parentContext != NULL) { 5015 size_t i; 5016 5017 mutex_lock(&sIOContextRootLock); 5018 context->root = parentContext->root; 5019 if (context->root) 5020 inc_vnode_ref_count(context->root); 5021 mutex_unlock(&sIOContextRootLock); 5022 5023 context->cwd = parentContext->cwd; 5024 if (context->cwd) 5025 inc_vnode_ref_count(context->cwd); 5026 5027 if (parentContext->inherit_fds) { 5028 for (i = 0; i < tableSize; i++) { 5029 struct file_descriptor* descriptor = parentContext->fds[i]; 5030 5031 if (descriptor != NULL 5032 && (descriptor->open_mode & O_DISCONNECTED) == 0) { 5033 bool closeOnExec = fd_close_on_exec(parentContext, i); 5034 if (closeOnExec && purgeCloseOnExec) 5035 continue; 5036 5037 TFD(InheritFD(context, i, descriptor, parentContext)); 5038 5039 context->fds[i] = descriptor; 5040 context->num_used_fds++; 5041 atomic_add(&descriptor->ref_count, 1); 5042 atomic_add(&descriptor->open_count, 1); 5043 5044 if (closeOnExec) 5045 fd_set_close_on_exec(context, i, true); 5046 } 5047 } 5048 } 5049 5050 parentLocker.Unlock(); 5051 } else { 5052 context->root = sRoot; 5053 context->cwd = sRoot; 5054 5055 if (context->root) 5056 inc_vnode_ref_count(context->root); 5057 5058 if (context->cwd) 5059 inc_vnode_ref_count(context->cwd); 5060 } 5061 5062 context->table_size = tableSize; 5063 context->inherit_fds = parentContext != NULL; 5064 5065 list_init(&context->node_monitors); 5066 context->max_monitors = DEFAULT_NODE_MONITORS; 5067 5068 return context; 5069 } 5070 5071 5072 void 5073 vfs_get_io_context(io_context* context) 5074 { 5075 atomic_add(&context->ref_count, 1); 5076 } 5077 5078 5079 void 5080 vfs_put_io_context(io_context* context) 5081 { 5082 if (atomic_add(&context->ref_count, -1) == 1) 5083 free_io_context(context); 5084 } 5085 5086 5087 status_t 5088 vfs_resize_fd_table(struct io_context* context, uint32 newSize) 5089 { 5090 if (newSize == 0 || newSize > MAX_FD_TABLE_SIZE) 5091 return B_BAD_VALUE; 5092 5093 TIOC(ResizeIOContext(context, newSize)); 5094 5095 MutexLocker _(context->io_mutex); 5096 5097 uint32 oldSize = context->table_size; 5098 int oldCloseOnExitBitmapSize = (oldSize + 7) / 8; 5099 int newCloseOnExitBitmapSize = (newSize + 7) / 8; 5100 5101 // If the tables shrink, make sure none of the fds being dropped are in use. 5102 if (newSize < oldSize) { 5103 for (uint32 i = oldSize; i-- > newSize;) { 5104 if (context->fds[i]) 5105 return B_BUSY; 5106 } 5107 } 5108 5109 // store pointers to the old tables 5110 file_descriptor** oldFDs = context->fds; 5111 select_info** oldSelectInfos = context->select_infos; 5112 uint8* oldCloseOnExecTable = context->fds_close_on_exec; 5113 5114 // allocate new tables 5115 file_descriptor** newFDs = (file_descriptor**)malloc( 5116 sizeof(struct file_descriptor*) * newSize 5117 + sizeof(struct select_infos**) * newSize 5118 + newCloseOnExitBitmapSize); 5119 if (newFDs == NULL) 5120 return B_NO_MEMORY; 5121 5122 context->fds = newFDs; 5123 context->select_infos = (select_info**)(context->fds + newSize); 5124 context->fds_close_on_exec = (uint8*)(context->select_infos + newSize); 5125 context->table_size = newSize; 5126 5127 // copy entries from old tables 5128 uint32 toCopy = min_c(oldSize, newSize); 5129 5130 memcpy(context->fds, oldFDs, sizeof(void*) * toCopy); 5131 memcpy(context->select_infos, oldSelectInfos, sizeof(void*) * toCopy); 5132 memcpy(context->fds_close_on_exec, oldCloseOnExecTable, 5133 min_c(oldCloseOnExitBitmapSize, newCloseOnExitBitmapSize)); 5134 5135 // clear additional entries, if the tables grow 5136 if (newSize > oldSize) { 5137 memset(context->fds + oldSize, 0, sizeof(void*) * (newSize - oldSize)); 5138 memset(context->select_infos + oldSize, 0, 5139 sizeof(void*) * (newSize - oldSize)); 5140 memset(context->fds_close_on_exec + oldCloseOnExitBitmapSize, 0, 5141 newCloseOnExitBitmapSize - oldCloseOnExitBitmapSize); 5142 } 5143 5144 free(oldFDs); 5145 5146 return B_OK; 5147 } 5148 5149 5150 /*! \brief Resolves a vnode to the vnode it is covered by, if any. 5151 5152 Given an arbitrary vnode (identified by mount and node ID), the function 5153 checks, whether the vnode is covered by another vnode. If it is, the 5154 function returns the mount and node ID of the covering vnode. Otherwise 5155 it simply returns the supplied mount and node ID. 5156 5157 In case of error (e.g. the supplied node could not be found) the variables 5158 for storing the resolved mount and node ID remain untouched and an error 5159 code is returned. 5160 5161 \param mountID The mount ID of the vnode in question. 5162 \param nodeID The node ID of the vnode in question. 5163 \param resolvedMountID Pointer to storage for the resolved mount ID. 5164 \param resolvedNodeID Pointer to storage for the resolved node ID. 5165 \return 5166 - \c B_OK, if everything went fine, 5167 - another error code, if something went wrong. 5168 */ 5169 status_t 5170 vfs_resolve_vnode_to_covering_vnode(dev_t mountID, ino_t nodeID, 5171 dev_t* resolvedMountID, ino_t* resolvedNodeID) 5172 { 5173 // get the node 5174 struct vnode* node; 5175 status_t error = get_vnode(mountID, nodeID, &node, true, false); 5176 if (error != B_OK) 5177 return error; 5178 5179 // resolve the node 5180 if (Vnode* coveringNode = get_covering_vnode(node)) { 5181 put_vnode(node); 5182 node = coveringNode; 5183 } 5184 5185 // set the return values 5186 *resolvedMountID = node->device; 5187 *resolvedNodeID = node->id; 5188 5189 put_vnode(node); 5190 5191 return B_OK; 5192 } 5193 5194 5195 status_t 5196 vfs_get_mount_point(dev_t mountID, dev_t* _mountPointMountID, 5197 ino_t* _mountPointNodeID) 5198 { 5199 ReadLocker nodeLocker(sVnodeLock); 5200 ReadLocker mountLocker(sMountLock); 5201 5202 struct fs_mount* mount = find_mount(mountID); 5203 if (mount == NULL) 5204 return B_BAD_VALUE; 5205 5206 Vnode* mountPoint = mount->covers_vnode; 5207 5208 *_mountPointMountID = mountPoint->device; 5209 *_mountPointNodeID = mountPoint->id; 5210 5211 return B_OK; 5212 } 5213 5214 5215 status_t 5216 vfs_bind_mount_directory(dev_t mountID, ino_t nodeID, dev_t coveredMountID, 5217 ino_t coveredNodeID) 5218 { 5219 // get the vnodes 5220 Vnode* vnode; 5221 status_t error = get_vnode(mountID, nodeID, &vnode, true, false); 5222 if (error != B_OK) 5223 return B_BAD_VALUE; 5224 VNodePutter vnodePutter(vnode); 5225 5226 Vnode* coveredVnode; 5227 error = get_vnode(coveredMountID, coveredNodeID, &coveredVnode, true, 5228 false); 5229 if (error != B_OK) 5230 return B_BAD_VALUE; 5231 VNodePutter coveredVnodePutter(coveredVnode); 5232 5233 // establish the covered/covering links 5234 WriteLocker locker(sVnodeLock); 5235 5236 if (vnode->covers != NULL || coveredVnode->covered_by != NULL 5237 || vnode->mount->unmounting || coveredVnode->mount->unmounting) { 5238 return B_BUSY; 5239 } 5240 5241 vnode->covers = coveredVnode; 5242 vnode->SetCovering(true); 5243 5244 coveredVnode->covered_by = vnode; 5245 coveredVnode->SetCovered(true); 5246 5247 // the vnodes do now reference each other 5248 inc_vnode_ref_count(vnode); 5249 inc_vnode_ref_count(coveredVnode); 5250 5251 return B_OK; 5252 } 5253 5254 5255 int 5256 vfs_getrlimit(int resource, struct rlimit* rlp) 5257 { 5258 if (!rlp) 5259 return B_BAD_ADDRESS; 5260 5261 switch (resource) { 5262 case RLIMIT_NOFILE: 5263 { 5264 struct io_context* context = get_current_io_context(false); 5265 MutexLocker _(context->io_mutex); 5266 5267 rlp->rlim_cur = context->table_size; 5268 rlp->rlim_max = MAX_FD_TABLE_SIZE; 5269 return 0; 5270 } 5271 5272 case RLIMIT_NOVMON: 5273 { 5274 struct io_context* context = get_current_io_context(false); 5275 MutexLocker _(context->io_mutex); 5276 5277 rlp->rlim_cur = context->max_monitors; 5278 rlp->rlim_max = MAX_NODE_MONITORS; 5279 return 0; 5280 } 5281 5282 default: 5283 return B_BAD_VALUE; 5284 } 5285 } 5286 5287 5288 int 5289 vfs_setrlimit(int resource, const struct rlimit* rlp) 5290 { 5291 if (!rlp) 5292 return B_BAD_ADDRESS; 5293 5294 switch (resource) { 5295 case RLIMIT_NOFILE: 5296 /* TODO: check getuid() */ 5297 if (rlp->rlim_max != RLIM_SAVED_MAX 5298 && rlp->rlim_max != MAX_FD_TABLE_SIZE) 5299 return B_NOT_ALLOWED; 5300 5301 return vfs_resize_fd_table(get_current_io_context(false), 5302 rlp->rlim_cur); 5303 5304 case RLIMIT_NOVMON: 5305 /* TODO: check getuid() */ 5306 if (rlp->rlim_max != RLIM_SAVED_MAX 5307 && rlp->rlim_max != MAX_NODE_MONITORS) 5308 return B_NOT_ALLOWED; 5309 5310 return resize_monitor_table(get_current_io_context(false), 5311 rlp->rlim_cur); 5312 5313 default: 5314 return B_BAD_VALUE; 5315 } 5316 } 5317 5318 5319 status_t 5320 vfs_init(kernel_args* args) 5321 { 5322 vnode::StaticInit(); 5323 5324 sVnodeTable = new(std::nothrow) VnodeTable(); 5325 if (sVnodeTable == NULL || sVnodeTable->Init(VNODE_HASH_TABLE_SIZE) != B_OK) 5326 panic("vfs_init: error creating vnode hash table\n"); 5327 5328 struct vnode dummy_vnode; 5329 list_init_etc(&sUnusedVnodeList, offset_of_member(dummy_vnode, unused_link)); 5330 5331 struct fs_mount dummyMount; 5332 sMountsTable = new(std::nothrow) MountTable(); 5333 if (sMountsTable == NULL 5334 || sMountsTable->Init(MOUNTS_HASH_TABLE_SIZE) != B_OK) 5335 panic("vfs_init: error creating mounts hash table\n"); 5336 5337 sPathNameCache = create_object_cache("vfs path names", 5338 B_PATH_NAME_LENGTH + 1, 8, NULL, NULL, NULL); 5339 if (sPathNameCache == NULL) 5340 panic("vfs_init: error creating path name object_cache\n"); 5341 5342 sVnodeCache = create_object_cache("vfs vnodes", 5343 sizeof(struct vnode), 8, NULL, NULL, NULL); 5344 if (sVnodeCache == NULL) 5345 panic("vfs_init: error creating vnode object_cache\n"); 5346 5347 sFileDescriptorCache = create_object_cache("vfs fds", 5348 sizeof(file_descriptor), 8, NULL, NULL, NULL); 5349 if (sFileDescriptorCache == NULL) 5350 panic("vfs_init: error creating file descriptor object_cache\n"); 5351 5352 node_monitor_init(); 5353 5354 sRoot = NULL; 5355 5356 recursive_lock_init(&sMountOpLock, "vfs_mount_op_lock"); 5357 5358 if (block_cache_init() != B_OK) 5359 return B_ERROR; 5360 5361 #ifdef ADD_DEBUGGER_COMMANDS 5362 // add some debugger commands 5363 add_debugger_command_etc("vnode", &dump_vnode, 5364 "Print info about the specified vnode", 5365 "[ \"-p\" ] ( <vnode> | <devID> <nodeID> )\n" 5366 "Prints information about the vnode specified by address <vnode> or\n" 5367 "<devID>, <vnodeID> pair. If \"-p\" is given, a path of the vnode is\n" 5368 "constructed and printed. It might not be possible to construct a\n" 5369 "complete path, though.\n", 5370 0); 5371 add_debugger_command("vnodes", &dump_vnodes, 5372 "list all vnodes (from the specified device)"); 5373 add_debugger_command("vnode_caches", &dump_vnode_caches, 5374 "list all vnode caches"); 5375 add_debugger_command("mount", &dump_mount, 5376 "info about the specified fs_mount"); 5377 add_debugger_command("mounts", &dump_mounts, "list all fs_mounts"); 5378 add_debugger_command("io_context", &dump_io_context, 5379 "info about the I/O context"); 5380 add_debugger_command("vnode_usage", &dump_vnode_usage, 5381 "info about vnode usage"); 5382 #endif 5383 5384 register_low_resource_handler(&vnode_low_resource_handler, NULL, 5385 B_KERNEL_RESOURCE_PAGES | B_KERNEL_RESOURCE_MEMORY 5386 | B_KERNEL_RESOURCE_ADDRESS_SPACE, 5387 0); 5388 5389 fifo_init(); 5390 file_map_init(); 5391 5392 return file_cache_init(); 5393 } 5394 5395 5396 // #pragma mark - fd_ops implementations 5397 5398 5399 /*! 5400 Calls fs_open() on the given vnode and returns a new 5401 file descriptor for it 5402 */ 5403 static int 5404 open_vnode(struct vnode* vnode, int openMode, bool kernel) 5405 { 5406 void* cookie; 5407 status_t status = FS_CALL(vnode, open, openMode, &cookie); 5408 if (status != B_OK) 5409 return status; 5410 5411 int fd = get_new_fd(FDTYPE_FILE, NULL, vnode, cookie, openMode, kernel); 5412 if (fd < 0) { 5413 FS_CALL(vnode, close, cookie); 5414 FS_CALL(vnode, free_cookie, cookie); 5415 } 5416 return fd; 5417 } 5418 5419 5420 /*! 5421 Calls fs_open() on the given vnode and returns a new 5422 file descriptor for it 5423 */ 5424 static int 5425 create_vnode(struct vnode* directory, const char* name, int openMode, 5426 int perms, bool kernel) 5427 { 5428 bool traverse = ((openMode & (O_NOTRAVERSE | O_NOFOLLOW)) == 0); 5429 status_t status = B_ERROR; 5430 struct vnode* vnode; 5431 void* cookie; 5432 ino_t newID; 5433 5434 // This is somewhat tricky: If the entry already exists, the FS responsible 5435 // for the directory might not necessarily also be the one responsible for 5436 // the node the entry refers to (e.g. in case of mount points or FIFOs). So 5437 // we can actually never call the create() hook without O_EXCL. Instead we 5438 // try to look the entry up first. If it already exists, we just open the 5439 // node (unless O_EXCL), otherwise we call create() with O_EXCL. This 5440 // introduces a race condition, since someone else might have created the 5441 // entry in the meantime. We hope the respective FS returns the correct 5442 // error code and retry (up to 3 times) again. 5443 5444 for (int i = 0; i < 3 && status != B_OK; i++) { 5445 // look the node up 5446 status = lookup_dir_entry(directory, name, &vnode); 5447 if (status == B_OK) { 5448 VNodePutter putter(vnode); 5449 5450 if ((openMode & O_EXCL) != 0) 5451 return B_FILE_EXISTS; 5452 5453 // If the node is a symlink, we have to follow it, unless 5454 // O_NOTRAVERSE is set. 5455 if (S_ISLNK(vnode->Type()) && traverse) { 5456 putter.Put(); 5457 char clonedName[B_FILE_NAME_LENGTH + 1]; 5458 if (strlcpy(clonedName, name, B_FILE_NAME_LENGTH) 5459 >= B_FILE_NAME_LENGTH) { 5460 return B_NAME_TOO_LONG; 5461 } 5462 5463 inc_vnode_ref_count(directory); 5464 status = vnode_path_to_vnode(directory, clonedName, true, 0, 5465 kernel, &vnode, NULL); 5466 if (status != B_OK) 5467 return status; 5468 5469 putter.SetTo(vnode); 5470 } 5471 5472 if ((openMode & O_NOFOLLOW) != 0 && S_ISLNK(vnode->Type())) 5473 return B_LINK_LIMIT; 5474 5475 int fd = open_vnode(vnode, openMode & ~O_CREAT, kernel); 5476 // on success keep the vnode reference for the FD 5477 if (fd >= 0) 5478 putter.Detach(); 5479 5480 return fd; 5481 } 5482 5483 // it doesn't exist yet -- try to create it 5484 5485 if (!HAS_FS_CALL(directory, create)) 5486 return B_READ_ONLY_DEVICE; 5487 5488 status = FS_CALL(directory, create, name, openMode | O_EXCL, perms, 5489 &cookie, &newID); 5490 if (status != B_OK 5491 && ((openMode & O_EXCL) != 0 || status != B_FILE_EXISTS)) { 5492 return status; 5493 } 5494 } 5495 5496 if (status != B_OK) 5497 return status; 5498 5499 // the node has been created successfully 5500 5501 rw_lock_read_lock(&sVnodeLock); 5502 vnode = lookup_vnode(directory->device, newID); 5503 rw_lock_read_unlock(&sVnodeLock); 5504 5505 if (vnode == NULL) { 5506 panic("vfs: fs_create() returned success but there is no vnode, " 5507 "mount ID %" B_PRIdDEV "!\n", directory->device); 5508 return B_BAD_VALUE; 5509 } 5510 5511 int fd = get_new_fd(FDTYPE_FILE, NULL, vnode, cookie, openMode, kernel); 5512 if (fd >= 0) 5513 return fd; 5514 5515 status = fd; 5516 5517 // something went wrong, clean up 5518 5519 FS_CALL(vnode, close, cookie); 5520 FS_CALL(vnode, free_cookie, cookie); 5521 put_vnode(vnode); 5522 5523 FS_CALL(directory, unlink, name); 5524 5525 return status; 5526 } 5527 5528 5529 /*! Calls fs open_dir() on the given vnode and returns a new 5530 file descriptor for it 5531 */ 5532 static int 5533 open_dir_vnode(struct vnode* vnode, bool kernel) 5534 { 5535 void* cookie; 5536 status_t status = FS_CALL(vnode, open_dir, &cookie); 5537 if (status != B_OK) 5538 return status; 5539 5540 // directory is opened, create a fd 5541 status = get_new_fd(FDTYPE_DIR, NULL, vnode, cookie, O_CLOEXEC, kernel); 5542 if (status >= 0) 5543 return status; 5544 5545 FS_CALL(vnode, close_dir, cookie); 5546 FS_CALL(vnode, free_dir_cookie, cookie); 5547 5548 return status; 5549 } 5550 5551 5552 /*! Calls fs open_attr_dir() on the given vnode and returns a new 5553 file descriptor for it. 5554 Used by attr_dir_open(), and attr_dir_open_fd(). 5555 */ 5556 static int 5557 open_attr_dir_vnode(struct vnode* vnode, bool kernel) 5558 { 5559 if (!HAS_FS_CALL(vnode, open_attr_dir)) 5560 return B_UNSUPPORTED; 5561 5562 void* cookie; 5563 status_t status = FS_CALL(vnode, open_attr_dir, &cookie); 5564 if (status != B_OK) 5565 return status; 5566 5567 // directory is opened, create a fd 5568 status = get_new_fd(FDTYPE_ATTR_DIR, NULL, vnode, cookie, O_CLOEXEC, 5569 kernel); 5570 if (status >= 0) 5571 return status; 5572 5573 FS_CALL(vnode, close_attr_dir, cookie); 5574 FS_CALL(vnode, free_attr_dir_cookie, cookie); 5575 5576 return status; 5577 } 5578 5579 5580 static int 5581 file_create_entry_ref(dev_t mountID, ino_t directoryID, const char* name, 5582 int openMode, int perms, bool kernel) 5583 { 5584 FUNCTION(("file_create_entry_ref: name = '%s', omode %x, perms %d, " 5585 "kernel %d\n", name, openMode, perms, kernel)); 5586 5587 // get directory to put the new file in 5588 struct vnode* directory; 5589 status_t status = get_vnode(mountID, directoryID, &directory, true, false); 5590 if (status != B_OK) 5591 return status; 5592 5593 status = create_vnode(directory, name, openMode, perms, kernel); 5594 put_vnode(directory); 5595 5596 return status; 5597 } 5598 5599 5600 static int 5601 file_create(int fd, char* path, int openMode, int perms, bool kernel) 5602 { 5603 FUNCTION(("file_create: path '%s', omode %x, perms %d, kernel %d\n", path, 5604 openMode, perms, kernel)); 5605 5606 // get directory to put the new file in 5607 char name[B_FILE_NAME_LENGTH]; 5608 struct vnode* directory; 5609 status_t status = fd_and_path_to_dir_vnode(fd, path, &directory, name, 5610 kernel); 5611 if (status < 0) 5612 return status; 5613 5614 status = create_vnode(directory, name, openMode, perms, kernel); 5615 5616 put_vnode(directory); 5617 return status; 5618 } 5619 5620 5621 static int 5622 file_open_entry_ref(dev_t mountID, ino_t directoryID, const char* name, 5623 int openMode, bool kernel) 5624 { 5625 if (name == NULL || *name == '\0') 5626 return B_BAD_VALUE; 5627 5628 FUNCTION(("file_open_entry_ref(ref = (%" B_PRId32 ", %" B_PRId64 ", %s), " 5629 "openMode = %d)\n", mountID, directoryID, name, openMode)); 5630 5631 bool traverse = (openMode & (O_NOTRAVERSE | O_NOFOLLOW)) == 0; 5632 5633 // get the vnode matching the entry_ref 5634 struct vnode* vnode; 5635 status_t status = entry_ref_to_vnode(mountID, directoryID, name, traverse, 5636 kernel, &vnode); 5637 if (status != B_OK) 5638 return status; 5639 5640 if ((openMode & O_NOFOLLOW) != 0 && S_ISLNK(vnode->Type())) { 5641 put_vnode(vnode); 5642 return B_LINK_LIMIT; 5643 } 5644 5645 int newFD = open_vnode(vnode, openMode, kernel); 5646 if (newFD >= 0) { 5647 // The vnode reference has been transferred to the FD 5648 cache_node_opened(vnode, FDTYPE_FILE, vnode->cache, mountID, 5649 directoryID, vnode->id, name); 5650 } else 5651 put_vnode(vnode); 5652 5653 return newFD; 5654 } 5655 5656 5657 static int 5658 file_open(int fd, char* path, int openMode, bool kernel) 5659 { 5660 bool traverse = (openMode & (O_NOTRAVERSE | O_NOFOLLOW)) == 0; 5661 5662 FUNCTION(("file_open: fd: %d, entry path = '%s', omode %d, kernel %d\n", 5663 fd, path, openMode, kernel)); 5664 5665 // get the vnode matching the vnode + path combination 5666 struct vnode* vnode; 5667 ino_t parentID; 5668 status_t status = fd_and_path_to_vnode(fd, path, traverse, &vnode, 5669 &parentID, kernel); 5670 if (status != B_OK) 5671 return status; 5672 5673 if ((openMode & O_NOFOLLOW) != 0 && S_ISLNK(vnode->Type())) { 5674 put_vnode(vnode); 5675 return B_LINK_LIMIT; 5676 } 5677 5678 // open the vnode 5679 int newFD = open_vnode(vnode, openMode, kernel); 5680 if (newFD >= 0) { 5681 // The vnode reference has been transferred to the FD 5682 cache_node_opened(vnode, FDTYPE_FILE, vnode->cache, 5683 vnode->device, parentID, vnode->id, NULL); 5684 } else 5685 put_vnode(vnode); 5686 5687 return newFD; 5688 } 5689 5690 5691 static status_t 5692 file_close(struct file_descriptor* descriptor) 5693 { 5694 struct vnode* vnode = descriptor->u.vnode; 5695 status_t status = B_OK; 5696 5697 FUNCTION(("file_close(descriptor = %p)\n", descriptor)); 5698 5699 cache_node_closed(vnode, FDTYPE_FILE, vnode->cache, vnode->device, 5700 vnode->id); 5701 if (HAS_FS_CALL(vnode, close)) { 5702 status = FS_CALL(vnode, close, descriptor->cookie); 5703 } 5704 5705 if (status == B_OK) { 5706 // remove all outstanding locks for this team 5707 if (HAS_FS_CALL(vnode, release_lock)) 5708 status = FS_CALL(vnode, release_lock, descriptor->cookie, NULL); 5709 else 5710 status = release_advisory_lock(vnode, NULL, descriptor, NULL); 5711 } 5712 return status; 5713 } 5714 5715 5716 static void 5717 file_free_fd(struct file_descriptor* descriptor) 5718 { 5719 struct vnode* vnode = descriptor->u.vnode; 5720 5721 if (vnode != NULL) { 5722 FS_CALL(vnode, free_cookie, descriptor->cookie); 5723 put_vnode(vnode); 5724 } 5725 } 5726 5727 5728 static status_t 5729 file_read(struct file_descriptor* descriptor, off_t pos, void* buffer, 5730 size_t* length) 5731 { 5732 struct vnode* vnode = descriptor->u.vnode; 5733 FUNCTION(("file_read: buf %p, pos %" B_PRIdOFF ", len %p = %ld\n", buffer, 5734 pos, length, *length)); 5735 5736 if (S_ISDIR(vnode->Type())) 5737 return B_IS_A_DIRECTORY; 5738 5739 return FS_CALL(vnode, read, descriptor->cookie, pos, buffer, length); 5740 } 5741 5742 5743 static status_t 5744 file_write(struct file_descriptor* descriptor, off_t pos, const void* buffer, 5745 size_t* length) 5746 { 5747 struct vnode* vnode = descriptor->u.vnode; 5748 FUNCTION(("file_write: buf %p, pos %" B_PRIdOFF ", len %p\n", buffer, pos, 5749 length)); 5750 5751 if (S_ISDIR(vnode->Type())) 5752 return B_IS_A_DIRECTORY; 5753 if (!HAS_FS_CALL(vnode, write)) 5754 return B_READ_ONLY_DEVICE; 5755 5756 return FS_CALL(vnode, write, descriptor->cookie, pos, buffer, length); 5757 } 5758 5759 5760 static off_t 5761 file_seek(struct file_descriptor* descriptor, off_t pos, int seekType) 5762 { 5763 struct vnode* vnode = descriptor->u.vnode; 5764 off_t offset; 5765 bool isDevice = false; 5766 5767 FUNCTION(("file_seek(pos = %" B_PRIdOFF ", seekType = %d)\n", pos, 5768 seekType)); 5769 5770 // some kinds of files are not seekable 5771 switch (vnode->Type() & S_IFMT) { 5772 case S_IFIFO: 5773 case S_IFSOCK: 5774 return ESPIPE; 5775 5776 // drivers publish block devices as chr, so pick both 5777 case S_IFBLK: 5778 case S_IFCHR: 5779 isDevice = true; 5780 break; 5781 // The Open Group Base Specs don't mention any file types besides pipes, 5782 // fifos, and sockets specially, so we allow seeking them. 5783 case S_IFREG: 5784 case S_IFDIR: 5785 case S_IFLNK: 5786 break; 5787 } 5788 5789 switch (seekType) { 5790 case SEEK_SET: 5791 offset = 0; 5792 break; 5793 case SEEK_CUR: 5794 offset = descriptor->pos; 5795 break; 5796 case SEEK_END: 5797 { 5798 // stat() the node 5799 if (!HAS_FS_CALL(vnode, read_stat)) 5800 return B_UNSUPPORTED; 5801 5802 struct stat stat; 5803 status_t status = FS_CALL(vnode, read_stat, &stat); 5804 if (status != B_OK) 5805 return status; 5806 5807 offset = stat.st_size; 5808 5809 if (offset == 0 && isDevice) { 5810 // stat() on regular drivers doesn't report size 5811 device_geometry geometry; 5812 5813 if (HAS_FS_CALL(vnode, ioctl)) { 5814 status = FS_CALL(vnode, ioctl, descriptor->cookie, 5815 B_GET_GEOMETRY, &geometry, sizeof(geometry)); 5816 if (status == B_OK) 5817 offset = (off_t)geometry.bytes_per_sector 5818 * geometry.sectors_per_track 5819 * geometry.cylinder_count 5820 * geometry.head_count; 5821 } 5822 } 5823 5824 break; 5825 } 5826 case SEEK_DATA: 5827 case SEEK_HOLE: 5828 { 5829 status_t status = B_BAD_VALUE; 5830 if (HAS_FS_CALL(vnode, ioctl)) { 5831 offset = pos; 5832 status = FS_CALL(vnode, ioctl, descriptor->cookie, 5833 seekType == SEEK_DATA ? FIOSEEKDATA : FIOSEEKHOLE, 5834 &offset, sizeof(offset)); 5835 if (status == B_OK) { 5836 if (offset > pos) 5837 offset -= pos; 5838 break; 5839 } 5840 } 5841 if (status != B_BAD_VALUE && status != B_DEV_INVALID_IOCTL) 5842 return status; 5843 5844 // basic implementation with stat() the node 5845 if (!HAS_FS_CALL(vnode, read_stat) || isDevice) 5846 return B_BAD_VALUE; 5847 5848 struct stat stat; 5849 status = FS_CALL(vnode, read_stat, &stat); 5850 if (status != B_OK) 5851 return status; 5852 5853 off_t end = stat.st_size; 5854 if (pos >= end) 5855 return ENXIO; 5856 offset = seekType == SEEK_HOLE ? end - pos : 0; 5857 break; 5858 } 5859 default: 5860 return B_BAD_VALUE; 5861 } 5862 5863 // assumes off_t is 64 bits wide 5864 if (offset > 0 && LONGLONG_MAX - offset < pos) 5865 return B_BUFFER_OVERFLOW; 5866 5867 pos += offset; 5868 if (pos < 0) 5869 return B_BAD_VALUE; 5870 5871 return descriptor->pos = pos; 5872 } 5873 5874 5875 static status_t 5876 file_select(struct file_descriptor* descriptor, uint8 event, 5877 struct selectsync* sync) 5878 { 5879 FUNCTION(("file_select(%p, %u, %p)\n", descriptor, event, sync)); 5880 5881 struct vnode* vnode = descriptor->u.vnode; 5882 5883 // If the FS has no select() hook, notify select() now. 5884 if (!HAS_FS_CALL(vnode, select)) { 5885 if (!SELECT_TYPE_IS_OUTPUT_ONLY(event)) 5886 return notify_select_event(sync, event); 5887 else 5888 return B_OK; 5889 } 5890 5891 return FS_CALL(vnode, select, descriptor->cookie, event, sync); 5892 } 5893 5894 5895 static status_t 5896 file_deselect(struct file_descriptor* descriptor, uint8 event, 5897 struct selectsync* sync) 5898 { 5899 struct vnode* vnode = descriptor->u.vnode; 5900 5901 if (!HAS_FS_CALL(vnode, deselect)) 5902 return B_OK; 5903 5904 return FS_CALL(vnode, deselect, descriptor->cookie, event, sync); 5905 } 5906 5907 5908 static status_t 5909 dir_create_entry_ref(dev_t mountID, ino_t parentID, const char* name, int perms, 5910 bool kernel) 5911 { 5912 struct vnode* vnode; 5913 status_t status; 5914 5915 if (name == NULL || *name == '\0') 5916 return B_BAD_VALUE; 5917 5918 FUNCTION(("dir_create_entry_ref(dev = %" B_PRId32 ", ino = %" B_PRId64 ", " 5919 "name = '%s', perms = %d)\n", mountID, parentID, name, perms)); 5920 5921 status = get_vnode(mountID, parentID, &vnode, true, false); 5922 if (status != B_OK) 5923 return status; 5924 5925 if (HAS_FS_CALL(vnode, create_dir)) 5926 status = FS_CALL(vnode, create_dir, name, perms); 5927 else 5928 status = B_READ_ONLY_DEVICE; 5929 5930 put_vnode(vnode); 5931 return status; 5932 } 5933 5934 5935 static status_t 5936 dir_create(int fd, char* path, int perms, bool kernel) 5937 { 5938 char filename[B_FILE_NAME_LENGTH]; 5939 struct vnode* vnode; 5940 status_t status; 5941 5942 FUNCTION(("dir_create: path '%s', perms %d, kernel %d\n", path, perms, 5943 kernel)); 5944 5945 status = fd_and_path_to_dir_vnode(fd, path, &vnode, filename, kernel); 5946 if (status < 0) 5947 return status; 5948 5949 if (HAS_FS_CALL(vnode, create_dir)) { 5950 status = FS_CALL(vnode, create_dir, filename, perms); 5951 } else 5952 status = B_READ_ONLY_DEVICE; 5953 5954 put_vnode(vnode); 5955 return status; 5956 } 5957 5958 5959 static int 5960 dir_open_entry_ref(dev_t mountID, ino_t parentID, const char* name, bool kernel) 5961 { 5962 FUNCTION(("dir_open_entry_ref()\n")); 5963 5964 if (name && name[0] == '\0') 5965 return B_BAD_VALUE; 5966 5967 // get the vnode matching the entry_ref/node_ref 5968 struct vnode* vnode; 5969 status_t status; 5970 if (name) { 5971 status = entry_ref_to_vnode(mountID, parentID, name, true, kernel, 5972 &vnode); 5973 } else 5974 status = get_vnode(mountID, parentID, &vnode, true, false); 5975 if (status != B_OK) 5976 return status; 5977 5978 int newFD = open_dir_vnode(vnode, kernel); 5979 if (newFD >= 0) { 5980 // The vnode reference has been transferred to the FD 5981 cache_node_opened(vnode, FDTYPE_DIR, vnode->cache, mountID, parentID, 5982 vnode->id, name); 5983 } else 5984 put_vnode(vnode); 5985 5986 return newFD; 5987 } 5988 5989 5990 static int 5991 dir_open(int fd, char* path, bool kernel) 5992 { 5993 FUNCTION(("dir_open: fd: %d, entry path = '%s', kernel %d\n", fd, path, 5994 kernel)); 5995 5996 // get the vnode matching the vnode + path combination 5997 struct vnode* vnode = NULL; 5998 ino_t parentID; 5999 status_t status = fd_and_path_to_vnode(fd, path, true, &vnode, &parentID, 6000 kernel); 6001 if (status != B_OK) 6002 return status; 6003 6004 // open the dir 6005 int newFD = open_dir_vnode(vnode, kernel); 6006 if (newFD >= 0) { 6007 // The vnode reference has been transferred to the FD 6008 cache_node_opened(vnode, FDTYPE_DIR, vnode->cache, vnode->device, 6009 parentID, vnode->id, NULL); 6010 } else 6011 put_vnode(vnode); 6012 6013 return newFD; 6014 } 6015 6016 6017 static status_t 6018 dir_close(struct file_descriptor* descriptor) 6019 { 6020 struct vnode* vnode = descriptor->u.vnode; 6021 6022 FUNCTION(("dir_close(descriptor = %p)\n", descriptor)); 6023 6024 cache_node_closed(vnode, FDTYPE_DIR, vnode->cache, vnode->device, 6025 vnode->id); 6026 if (HAS_FS_CALL(vnode, close_dir)) 6027 return FS_CALL(vnode, close_dir, descriptor->cookie); 6028 6029 return B_OK; 6030 } 6031 6032 6033 static void 6034 dir_free_fd(struct file_descriptor* descriptor) 6035 { 6036 struct vnode* vnode = descriptor->u.vnode; 6037 6038 if (vnode != NULL) { 6039 FS_CALL(vnode, free_dir_cookie, descriptor->cookie); 6040 put_vnode(vnode); 6041 } 6042 } 6043 6044 6045 static status_t 6046 dir_read(struct io_context* ioContext, struct file_descriptor* descriptor, 6047 struct dirent* buffer, size_t bufferSize, uint32* _count) 6048 { 6049 return dir_read(ioContext, descriptor->u.vnode, descriptor->cookie, buffer, 6050 bufferSize, _count); 6051 } 6052 6053 6054 static status_t 6055 fix_dirent(struct vnode* parent, struct dirent* entry, 6056 struct io_context* ioContext) 6057 { 6058 // set d_pdev and d_pino 6059 entry->d_pdev = parent->device; 6060 entry->d_pino = parent->id; 6061 6062 // If this is the ".." entry and the directory covering another vnode, 6063 // we need to replace d_dev and d_ino with the actual values. 6064 if (strcmp(entry->d_name, "..") == 0 && parent->IsCovering()) { 6065 return resolve_covered_parent(parent, &entry->d_dev, &entry->d_ino, 6066 ioContext); 6067 } 6068 6069 // resolve covered vnodes 6070 ReadLocker _(&sVnodeLock); 6071 6072 struct vnode* vnode = lookup_vnode(entry->d_dev, entry->d_ino); 6073 if (vnode != NULL && vnode->covered_by != NULL) { 6074 do { 6075 vnode = vnode->covered_by; 6076 } while (vnode->covered_by != NULL); 6077 6078 entry->d_dev = vnode->device; 6079 entry->d_ino = vnode->id; 6080 } 6081 6082 return B_OK; 6083 } 6084 6085 6086 static status_t 6087 dir_read(struct io_context* ioContext, struct vnode* vnode, void* cookie, 6088 struct dirent* buffer, size_t bufferSize, uint32* _count) 6089 { 6090 if (!HAS_FS_CALL(vnode, read_dir)) 6091 return B_UNSUPPORTED; 6092 6093 status_t error = FS_CALL(vnode, read_dir, cookie, buffer, bufferSize, 6094 _count); 6095 if (error != B_OK) 6096 return error; 6097 6098 // we need to adjust the read dirents 6099 uint32 count = *_count; 6100 for (uint32 i = 0; i < count; i++) { 6101 error = fix_dirent(vnode, buffer, ioContext); 6102 if (error != B_OK) 6103 return error; 6104 6105 buffer = (struct dirent*)((uint8*)buffer + buffer->d_reclen); 6106 } 6107 6108 return error; 6109 } 6110 6111 6112 static status_t 6113 dir_rewind(struct file_descriptor* descriptor) 6114 { 6115 struct vnode* vnode = descriptor->u.vnode; 6116 6117 if (HAS_FS_CALL(vnode, rewind_dir)) { 6118 return FS_CALL(vnode, rewind_dir, descriptor->cookie); 6119 } 6120 6121 return B_UNSUPPORTED; 6122 } 6123 6124 6125 static status_t 6126 dir_remove(int fd, char* path, bool kernel) 6127 { 6128 char name[B_FILE_NAME_LENGTH]; 6129 struct vnode* directory; 6130 status_t status; 6131 6132 if (path != NULL) { 6133 // we need to make sure our path name doesn't stop with "/", ".", 6134 // or ".." 6135 char* lastSlash; 6136 while ((lastSlash = strrchr(path, '/')) != NULL) { 6137 char* leaf = lastSlash + 1; 6138 if (!strcmp(leaf, "..")) 6139 return B_NOT_ALLOWED; 6140 6141 // omit multiple slashes 6142 while (lastSlash > path && lastSlash[-1] == '/') 6143 lastSlash--; 6144 6145 if (leaf[0] 6146 && strcmp(leaf, ".")) { 6147 break; 6148 } 6149 // "name/" -> "name", or "name/." -> "name" 6150 lastSlash[0] = '\0'; 6151 } 6152 6153 if (!strcmp(path, ".") || !strcmp(path, "..")) 6154 return B_NOT_ALLOWED; 6155 } 6156 6157 status = fd_and_path_to_dir_vnode(fd, path, &directory, name, kernel); 6158 if (status != B_OK) 6159 return status; 6160 6161 if (HAS_FS_CALL(directory, remove_dir)) 6162 status = FS_CALL(directory, remove_dir, name); 6163 else 6164 status = B_READ_ONLY_DEVICE; 6165 6166 put_vnode(directory); 6167 return status; 6168 } 6169 6170 6171 static status_t 6172 common_ioctl(struct file_descriptor* descriptor, ulong op, void* buffer, 6173 size_t length) 6174 { 6175 struct vnode* vnode = descriptor->u.vnode; 6176 6177 if (HAS_FS_CALL(vnode, ioctl)) 6178 return FS_CALL(vnode, ioctl, descriptor->cookie, op, buffer, length); 6179 6180 return B_DEV_INVALID_IOCTL; 6181 } 6182 6183 6184 static status_t 6185 common_fcntl(int fd, int op, size_t argument, bool kernel) 6186 { 6187 struct flock flock; 6188 6189 FUNCTION(("common_fcntl(fd = %d, op = %d, argument = %lx, %s)\n", 6190 fd, op, argument, kernel ? "kernel" : "user")); 6191 6192 struct io_context* context = get_current_io_context(kernel); 6193 6194 struct file_descriptor* descriptor = get_fd(context, fd); 6195 if (descriptor == NULL) 6196 return B_FILE_ERROR; 6197 6198 struct vnode* vnode = fd_vnode(descriptor); 6199 6200 status_t status = B_OK; 6201 6202 if (op == F_SETLK || op == F_SETLKW || op == F_GETLK) { 6203 if (descriptor->type != FDTYPE_FILE) 6204 status = B_BAD_VALUE; 6205 else if (kernel) 6206 memcpy(&flock, (struct flock*)argument, sizeof(struct flock)); 6207 else if (user_memcpy(&flock, (struct flock*)argument, 6208 sizeof(struct flock)) != B_OK) 6209 status = B_BAD_ADDRESS; 6210 if (status != B_OK) { 6211 put_fd(descriptor); 6212 return status; 6213 } 6214 } 6215 6216 switch (op) { 6217 case F_SETFD: 6218 { 6219 // Set file descriptor flags 6220 6221 // O_CLOEXEC is the only flag available at this time 6222 mutex_lock(&context->io_mutex); 6223 fd_set_close_on_exec(context, fd, (argument & FD_CLOEXEC) != 0); 6224 mutex_unlock(&context->io_mutex); 6225 6226 status = B_OK; 6227 break; 6228 } 6229 6230 case F_GETFD: 6231 { 6232 // Get file descriptor flags 6233 mutex_lock(&context->io_mutex); 6234 status = fd_close_on_exec(context, fd) ? FD_CLOEXEC : 0; 6235 mutex_unlock(&context->io_mutex); 6236 break; 6237 } 6238 6239 case F_SETFL: 6240 // Set file descriptor open mode 6241 6242 // we only accept changes to O_APPEND and O_NONBLOCK 6243 argument &= O_APPEND | O_NONBLOCK; 6244 if (descriptor->ops->fd_set_flags != NULL) { 6245 status = descriptor->ops->fd_set_flags(descriptor, argument); 6246 } else if (vnode != NULL && HAS_FS_CALL(vnode, set_flags)) { 6247 status = FS_CALL(vnode, set_flags, descriptor->cookie, 6248 (int)argument); 6249 } else 6250 status = B_UNSUPPORTED; 6251 6252 if (status == B_OK) { 6253 // update this descriptor's open_mode field 6254 descriptor->open_mode = (descriptor->open_mode 6255 & ~(O_APPEND | O_NONBLOCK)) | argument; 6256 } 6257 6258 break; 6259 6260 case F_GETFL: 6261 // Get file descriptor open mode 6262 status = descriptor->open_mode; 6263 break; 6264 6265 case F_DUPFD: 6266 case F_DUPFD_CLOEXEC: 6267 { 6268 status = new_fd_etc(context, descriptor, (int)argument); 6269 if (status >= 0) { 6270 mutex_lock(&context->io_mutex); 6271 fd_set_close_on_exec(context, status, op == F_DUPFD_CLOEXEC); 6272 mutex_unlock(&context->io_mutex); 6273 6274 atomic_add(&descriptor->ref_count, 1); 6275 } 6276 break; 6277 } 6278 6279 case F_GETLK: 6280 if (vnode != NULL) { 6281 struct flock normalizedLock; 6282 6283 memcpy(&normalizedLock, &flock, sizeof(struct flock)); 6284 status = normalize_flock(descriptor, &normalizedLock); 6285 if (status != B_OK) 6286 break; 6287 6288 if (HAS_FS_CALL(vnode, test_lock)) { 6289 status = FS_CALL(vnode, test_lock, descriptor->cookie, 6290 &normalizedLock); 6291 } else 6292 status = test_advisory_lock(vnode, &normalizedLock); 6293 if (status == B_OK) { 6294 if (normalizedLock.l_type == F_UNLCK) { 6295 // no conflicting lock found, copy back the same struct 6296 // we were given except change type to F_UNLCK 6297 flock.l_type = F_UNLCK; 6298 if (kernel) { 6299 memcpy((struct flock*)argument, &flock, 6300 sizeof(struct flock)); 6301 } else { 6302 status = user_memcpy((struct flock*)argument, 6303 &flock, sizeof(struct flock)); 6304 } 6305 } else { 6306 // a conflicting lock was found, copy back its range and 6307 // type 6308 if (normalizedLock.l_len == OFF_MAX) 6309 normalizedLock.l_len = 0; 6310 6311 if (kernel) { 6312 memcpy((struct flock*)argument, 6313 &normalizedLock, sizeof(struct flock)); 6314 } else { 6315 status = user_memcpy((struct flock*)argument, 6316 &normalizedLock, sizeof(struct flock)); 6317 } 6318 } 6319 } 6320 } else 6321 status = B_BAD_VALUE; 6322 break; 6323 6324 case F_SETLK: 6325 case F_SETLKW: 6326 status = normalize_flock(descriptor, &flock); 6327 if (status != B_OK) 6328 break; 6329 6330 if (vnode == NULL) { 6331 status = B_BAD_VALUE; 6332 } else if (flock.l_type == F_UNLCK) { 6333 if (HAS_FS_CALL(vnode, release_lock)) { 6334 status = FS_CALL(vnode, release_lock, descriptor->cookie, 6335 &flock); 6336 } else { 6337 status = release_advisory_lock(vnode, context, NULL, 6338 &flock); 6339 } 6340 } else { 6341 // the open mode must match the lock type 6342 if (((descriptor->open_mode & O_RWMASK) == O_RDONLY 6343 && flock.l_type == F_WRLCK) 6344 || ((descriptor->open_mode & O_RWMASK) == O_WRONLY 6345 && flock.l_type == F_RDLCK)) 6346 status = B_FILE_ERROR; 6347 else { 6348 if (HAS_FS_CALL(vnode, acquire_lock)) { 6349 status = FS_CALL(vnode, acquire_lock, 6350 descriptor->cookie, &flock, op == F_SETLKW); 6351 } else { 6352 status = acquire_advisory_lock(vnode, context, NULL, 6353 &flock, op == F_SETLKW); 6354 } 6355 } 6356 } 6357 break; 6358 6359 // ToDo: add support for more ops? 6360 6361 default: 6362 status = B_BAD_VALUE; 6363 } 6364 6365 put_fd(descriptor); 6366 return status; 6367 } 6368 6369 6370 static status_t 6371 common_sync(int fd, bool kernel) 6372 { 6373 struct file_descriptor* descriptor; 6374 struct vnode* vnode; 6375 status_t status; 6376 6377 FUNCTION(("common_fsync: entry. fd %d kernel %d\n", fd, kernel)); 6378 6379 descriptor = get_fd_and_vnode(fd, &vnode, kernel); 6380 if (descriptor == NULL) 6381 return B_FILE_ERROR; 6382 6383 if (HAS_FS_CALL(vnode, fsync)) 6384 status = FS_CALL_NO_PARAMS(vnode, fsync); 6385 else 6386 status = B_UNSUPPORTED; 6387 6388 put_fd(descriptor); 6389 return status; 6390 } 6391 6392 6393 static status_t 6394 common_lock_node(int fd, bool kernel) 6395 { 6396 struct file_descriptor* descriptor; 6397 struct vnode* vnode; 6398 6399 descriptor = get_fd_and_vnode(fd, &vnode, kernel); 6400 if (descriptor == NULL) 6401 return B_FILE_ERROR; 6402 6403 status_t status = B_OK; 6404 6405 // We need to set the locking atomically - someone 6406 // else might set one at the same time 6407 if (atomic_pointer_test_and_set(&vnode->mandatory_locked_by, descriptor, 6408 (file_descriptor*)NULL) != NULL) 6409 status = B_BUSY; 6410 6411 put_fd(descriptor); 6412 return status; 6413 } 6414 6415 6416 static status_t 6417 common_unlock_node(int fd, bool kernel) 6418 { 6419 struct file_descriptor* descriptor; 6420 struct vnode* vnode; 6421 6422 descriptor = get_fd_and_vnode(fd, &vnode, kernel); 6423 if (descriptor == NULL) 6424 return B_FILE_ERROR; 6425 6426 status_t status = B_OK; 6427 6428 // We need to set the locking atomically - someone 6429 // else might set one at the same time 6430 if (atomic_pointer_test_and_set(&vnode->mandatory_locked_by, 6431 (file_descriptor*)NULL, descriptor) != descriptor) 6432 status = B_BAD_VALUE; 6433 6434 put_fd(descriptor); 6435 return status; 6436 } 6437 6438 6439 static status_t 6440 common_preallocate(int fd, off_t offset, off_t length, bool kernel) 6441 { 6442 struct file_descriptor* descriptor; 6443 struct vnode* vnode; 6444 6445 if (offset < 0 || length == 0) 6446 return B_BAD_VALUE; 6447 if (offset > OFF_MAX - length) 6448 return B_FILE_TOO_LARGE; 6449 6450 descriptor = get_fd_and_vnode(fd, &vnode, kernel); 6451 if (descriptor == NULL || (descriptor->open_mode & O_RWMASK) == O_RDONLY) 6452 return B_FILE_ERROR; 6453 6454 switch (vnode->Type() & S_IFMT) { 6455 case S_IFIFO: 6456 case S_IFSOCK: 6457 return ESPIPE; 6458 6459 case S_IFBLK: 6460 case S_IFCHR: 6461 case S_IFDIR: 6462 case S_IFLNK: 6463 return B_DEVICE_NOT_FOUND; 6464 6465 case S_IFREG: 6466 break; 6467 } 6468 6469 status_t status = B_OK; 6470 if (HAS_FS_CALL(vnode, preallocate)) { 6471 status = FS_CALL(vnode, preallocate, offset, length); 6472 } else { 6473 status = HAS_FS_CALL(vnode, write) 6474 ? B_UNSUPPORTED : B_READ_ONLY_DEVICE; 6475 } 6476 6477 return status; 6478 } 6479 6480 6481 static status_t 6482 common_read_link(int fd, char* path, char* buffer, size_t* _bufferSize, 6483 bool kernel) 6484 { 6485 struct vnode* vnode; 6486 status_t status; 6487 6488 status = fd_and_path_to_vnode(fd, path, false, &vnode, NULL, kernel); 6489 if (status != B_OK) 6490 return status; 6491 6492 if (HAS_FS_CALL(vnode, read_symlink)) { 6493 status = FS_CALL(vnode, read_symlink, buffer, _bufferSize); 6494 } else 6495 status = B_BAD_VALUE; 6496 6497 put_vnode(vnode); 6498 return status; 6499 } 6500 6501 6502 static status_t 6503 common_create_symlink(int fd, char* path, const char* toPath, int mode, 6504 bool kernel) 6505 { 6506 // path validity checks have to be in the calling function! 6507 char name[B_FILE_NAME_LENGTH]; 6508 struct vnode* vnode; 6509 status_t status; 6510 6511 FUNCTION(("common_create_symlink(fd = %d, path = %s, toPath = %s, " 6512 "mode = %d, kernel = %d)\n", fd, path, toPath, mode, kernel)); 6513 6514 status = fd_and_path_to_dir_vnode(fd, path, &vnode, name, kernel); 6515 if (status != B_OK) 6516 return status; 6517 6518 if (HAS_FS_CALL(vnode, create_symlink)) 6519 status = FS_CALL(vnode, create_symlink, name, toPath, mode); 6520 else { 6521 status = HAS_FS_CALL(vnode, write) 6522 ? B_UNSUPPORTED : B_READ_ONLY_DEVICE; 6523 } 6524 6525 put_vnode(vnode); 6526 6527 return status; 6528 } 6529 6530 6531 static status_t 6532 common_create_link(int pathFD, char* path, int toFD, char* toPath, 6533 bool traverseLeafLink, bool kernel) 6534 { 6535 // path validity checks have to be in the calling function! 6536 6537 FUNCTION(("common_create_link(path = %s, toPath = %s, kernel = %d)\n", path, 6538 toPath, kernel)); 6539 6540 char name[B_FILE_NAME_LENGTH]; 6541 struct vnode* directory; 6542 status_t status = fd_and_path_to_dir_vnode(pathFD, path, &directory, name, 6543 kernel); 6544 if (status != B_OK) 6545 return status; 6546 6547 struct vnode* vnode; 6548 status = fd_and_path_to_vnode(toFD, toPath, traverseLeafLink, &vnode, NULL, 6549 kernel); 6550 if (status != B_OK) 6551 goto err; 6552 6553 if (directory->mount != vnode->mount) { 6554 status = B_CROSS_DEVICE_LINK; 6555 goto err1; 6556 } 6557 6558 if (HAS_FS_CALL(directory, link)) 6559 status = FS_CALL(directory, link, name, vnode); 6560 else 6561 status = B_READ_ONLY_DEVICE; 6562 6563 err1: 6564 put_vnode(vnode); 6565 err: 6566 put_vnode(directory); 6567 6568 return status; 6569 } 6570 6571 6572 static status_t 6573 common_unlink(int fd, char* path, bool kernel) 6574 { 6575 char filename[B_FILE_NAME_LENGTH]; 6576 struct vnode* vnode; 6577 status_t status; 6578 6579 FUNCTION(("common_unlink: fd: %d, path '%s', kernel %d\n", fd, path, 6580 kernel)); 6581 6582 status = fd_and_path_to_dir_vnode(fd, path, &vnode, filename, kernel); 6583 if (status < 0) 6584 return status; 6585 6586 if (HAS_FS_CALL(vnode, unlink)) 6587 status = FS_CALL(vnode, unlink, filename); 6588 else 6589 status = B_READ_ONLY_DEVICE; 6590 6591 put_vnode(vnode); 6592 6593 return status; 6594 } 6595 6596 6597 static status_t 6598 common_access(int fd, char* path, int mode, bool effectiveUserGroup, bool kernel) 6599 { 6600 struct vnode* vnode; 6601 status_t status; 6602 6603 // TODO: honor effectiveUserGroup argument 6604 6605 status = fd_and_path_to_vnode(fd, path, true, &vnode, NULL, kernel); 6606 if (status != B_OK) 6607 return status; 6608 6609 if (HAS_FS_CALL(vnode, access)) 6610 status = FS_CALL(vnode, access, mode); 6611 else 6612 status = B_OK; 6613 6614 put_vnode(vnode); 6615 6616 return status; 6617 } 6618 6619 6620 static status_t 6621 common_rename(int fd, char* path, int newFD, char* newPath, bool kernel) 6622 { 6623 struct vnode* fromVnode; 6624 struct vnode* toVnode; 6625 char fromName[B_FILE_NAME_LENGTH]; 6626 char toName[B_FILE_NAME_LENGTH]; 6627 status_t status; 6628 6629 FUNCTION(("common_rename(fd = %d, path = %s, newFD = %d, newPath = %s, " 6630 "kernel = %d)\n", fd, path, newFD, newPath, kernel)); 6631 6632 status = fd_and_path_to_dir_vnode(fd, path, &fromVnode, fromName, kernel); 6633 if (status != B_OK) 6634 return status; 6635 6636 status = fd_and_path_to_dir_vnode(newFD, newPath, &toVnode, toName, kernel); 6637 if (status != B_OK) 6638 goto err1; 6639 6640 if (fromVnode->device != toVnode->device) { 6641 status = B_CROSS_DEVICE_LINK; 6642 goto err2; 6643 } 6644 6645 if (fromName[0] == '\0' || toName[0] == '\0' 6646 || !strcmp(fromName, ".") || !strcmp(fromName, "..") 6647 || !strcmp(toName, ".") || !strcmp(toName, "..") 6648 || (fromVnode == toVnode && !strcmp(fromName, toName))) { 6649 status = B_BAD_VALUE; 6650 goto err2; 6651 } 6652 6653 if (HAS_FS_CALL(fromVnode, rename)) 6654 status = FS_CALL(fromVnode, rename, fromName, toVnode, toName); 6655 else 6656 status = B_READ_ONLY_DEVICE; 6657 6658 err2: 6659 put_vnode(toVnode); 6660 err1: 6661 put_vnode(fromVnode); 6662 6663 return status; 6664 } 6665 6666 6667 static status_t 6668 common_read_stat(struct file_descriptor* descriptor, struct stat* stat) 6669 { 6670 struct vnode* vnode = descriptor->u.vnode; 6671 6672 FUNCTION(("common_read_stat: stat %p\n", stat)); 6673 6674 // TODO: remove this once all file systems properly set them! 6675 stat->st_crtim.tv_nsec = 0; 6676 stat->st_ctim.tv_nsec = 0; 6677 stat->st_mtim.tv_nsec = 0; 6678 stat->st_atim.tv_nsec = 0; 6679 6680 return vfs_stat_vnode(vnode, stat); 6681 } 6682 6683 6684 static status_t 6685 common_write_stat(struct file_descriptor* descriptor, const struct stat* stat, 6686 int statMask) 6687 { 6688 struct vnode* vnode = descriptor->u.vnode; 6689 6690 FUNCTION(("common_write_stat(vnode = %p, stat = %p, statMask = %d)\n", 6691 vnode, stat, statMask)); 6692 6693 if ((descriptor->open_mode & O_RWMASK) == O_RDONLY 6694 && (statMask & B_STAT_SIZE) != 0) { 6695 return B_BAD_VALUE; 6696 } 6697 6698 if (!HAS_FS_CALL(vnode, write_stat)) 6699 return B_READ_ONLY_DEVICE; 6700 6701 return FS_CALL(vnode, write_stat, stat, statMask); 6702 } 6703 6704 6705 static status_t 6706 common_path_read_stat(int fd, char* path, bool traverseLeafLink, 6707 struct stat* stat, bool kernel) 6708 { 6709 FUNCTION(("common_path_read_stat: fd: %d, path '%s', stat %p,\n", fd, path, 6710 stat)); 6711 6712 struct vnode* vnode; 6713 status_t status = fd_and_path_to_vnode(fd, path, traverseLeafLink, &vnode, 6714 NULL, kernel); 6715 if (status != B_OK) 6716 return status; 6717 6718 status = vfs_stat_vnode(vnode, stat); 6719 6720 put_vnode(vnode); 6721 return status; 6722 } 6723 6724 6725 static status_t 6726 common_path_write_stat(int fd, char* path, bool traverseLeafLink, 6727 const struct stat* stat, int statMask, bool kernel) 6728 { 6729 FUNCTION(("common_write_stat: fd: %d, path '%s', stat %p, stat_mask %d, " 6730 "kernel %d\n", fd, path, stat, statMask, kernel)); 6731 6732 struct vnode* vnode; 6733 status_t status = fd_and_path_to_vnode(fd, path, traverseLeafLink, &vnode, 6734 NULL, kernel); 6735 if (status != B_OK) 6736 return status; 6737 6738 if (HAS_FS_CALL(vnode, write_stat)) 6739 status = FS_CALL(vnode, write_stat, stat, statMask); 6740 else 6741 status = B_READ_ONLY_DEVICE; 6742 6743 put_vnode(vnode); 6744 6745 return status; 6746 } 6747 6748 6749 static int 6750 attr_dir_open(int fd, char* path, bool traverseLeafLink, bool kernel) 6751 { 6752 FUNCTION(("attr_dir_open(fd = %d, path = '%s', kernel = %d)\n", fd, path, 6753 kernel)); 6754 6755 struct vnode* vnode; 6756 status_t status = fd_and_path_to_vnode(fd, path, traverseLeafLink, &vnode, 6757 NULL, kernel); 6758 if (status != B_OK) 6759 return status; 6760 6761 status = open_attr_dir_vnode(vnode, kernel); 6762 if (status < 0) 6763 put_vnode(vnode); 6764 6765 return status; 6766 } 6767 6768 6769 static status_t 6770 attr_dir_close(struct file_descriptor* descriptor) 6771 { 6772 struct vnode* vnode = descriptor->u.vnode; 6773 6774 FUNCTION(("attr_dir_close(descriptor = %p)\n", descriptor)); 6775 6776 if (HAS_FS_CALL(vnode, close_attr_dir)) 6777 return FS_CALL(vnode, close_attr_dir, descriptor->cookie); 6778 6779 return B_OK; 6780 } 6781 6782 6783 static void 6784 attr_dir_free_fd(struct file_descriptor* descriptor) 6785 { 6786 struct vnode* vnode = descriptor->u.vnode; 6787 6788 if (vnode != NULL) { 6789 FS_CALL(vnode, free_attr_dir_cookie, descriptor->cookie); 6790 put_vnode(vnode); 6791 } 6792 } 6793 6794 6795 static status_t 6796 attr_dir_read(struct io_context* ioContext, struct file_descriptor* descriptor, 6797 struct dirent* buffer, size_t bufferSize, uint32* _count) 6798 { 6799 struct vnode* vnode = descriptor->u.vnode; 6800 6801 FUNCTION(("attr_dir_read(descriptor = %p)\n", descriptor)); 6802 6803 if (HAS_FS_CALL(vnode, read_attr_dir)) 6804 return FS_CALL(vnode, read_attr_dir, descriptor->cookie, buffer, 6805 bufferSize, _count); 6806 6807 return B_UNSUPPORTED; 6808 } 6809 6810 6811 static status_t 6812 attr_dir_rewind(struct file_descriptor* descriptor) 6813 { 6814 struct vnode* vnode = descriptor->u.vnode; 6815 6816 FUNCTION(("attr_dir_rewind(descriptor = %p)\n", descriptor)); 6817 6818 if (HAS_FS_CALL(vnode, rewind_attr_dir)) 6819 return FS_CALL(vnode, rewind_attr_dir, descriptor->cookie); 6820 6821 return B_UNSUPPORTED; 6822 } 6823 6824 6825 static int 6826 attr_create(int fd, char* path, const char* name, uint32 type, 6827 int openMode, bool kernel) 6828 { 6829 if (name == NULL || *name == '\0') 6830 return B_BAD_VALUE; 6831 6832 bool traverse = (openMode & (O_NOTRAVERSE | O_NOFOLLOW)) == 0; 6833 struct vnode* vnode; 6834 status_t status = fd_and_path_to_vnode(fd, path, traverse, &vnode, NULL, 6835 kernel); 6836 if (status != B_OK) 6837 return status; 6838 6839 if ((openMode & O_NOFOLLOW) != 0 && S_ISLNK(vnode->Type())) { 6840 status = B_LINK_LIMIT; 6841 goto err; 6842 } 6843 6844 if (!HAS_FS_CALL(vnode, create_attr)) { 6845 status = B_READ_ONLY_DEVICE; 6846 goto err; 6847 } 6848 6849 void* cookie; 6850 status = FS_CALL(vnode, create_attr, name, type, openMode, &cookie); 6851 if (status != B_OK) 6852 goto err; 6853 6854 fd = get_new_fd(FDTYPE_ATTR, NULL, vnode, cookie, openMode, kernel); 6855 if (fd >= 0) 6856 return fd; 6857 6858 status = fd; 6859 6860 FS_CALL(vnode, close_attr, cookie); 6861 FS_CALL(vnode, free_attr_cookie, cookie); 6862 6863 FS_CALL(vnode, remove_attr, name); 6864 6865 err: 6866 put_vnode(vnode); 6867 6868 return status; 6869 } 6870 6871 6872 static int 6873 attr_open(int fd, char* path, const char* name, int openMode, bool kernel) 6874 { 6875 if (name == NULL || *name == '\0') 6876 return B_BAD_VALUE; 6877 6878 bool traverse = (openMode & (O_NOTRAVERSE | O_NOFOLLOW)) == 0; 6879 struct vnode* vnode; 6880 status_t status = fd_and_path_to_vnode(fd, path, traverse, &vnode, NULL, 6881 kernel); 6882 if (status != B_OK) 6883 return status; 6884 6885 if ((openMode & O_NOFOLLOW) != 0 && S_ISLNK(vnode->Type())) { 6886 status = B_LINK_LIMIT; 6887 goto err; 6888 } 6889 6890 if (!HAS_FS_CALL(vnode, open_attr)) { 6891 status = B_UNSUPPORTED; 6892 goto err; 6893 } 6894 6895 void* cookie; 6896 status = FS_CALL(vnode, open_attr, name, openMode, &cookie); 6897 if (status != B_OK) 6898 goto err; 6899 6900 // now we only need a file descriptor for this attribute and we're done 6901 fd = get_new_fd(FDTYPE_ATTR, NULL, vnode, cookie, openMode, kernel); 6902 if (fd >= 0) 6903 return fd; 6904 6905 status = fd; 6906 6907 FS_CALL(vnode, close_attr, cookie); 6908 FS_CALL(vnode, free_attr_cookie, cookie); 6909 6910 err: 6911 put_vnode(vnode); 6912 6913 return status; 6914 } 6915 6916 6917 static status_t 6918 attr_close(struct file_descriptor* descriptor) 6919 { 6920 struct vnode* vnode = descriptor->u.vnode; 6921 6922 FUNCTION(("attr_close(descriptor = %p)\n", descriptor)); 6923 6924 if (HAS_FS_CALL(vnode, close_attr)) 6925 return FS_CALL(vnode, close_attr, descriptor->cookie); 6926 6927 return B_OK; 6928 } 6929 6930 6931 static void 6932 attr_free_fd(struct file_descriptor* descriptor) 6933 { 6934 struct vnode* vnode = descriptor->u.vnode; 6935 6936 if (vnode != NULL) { 6937 FS_CALL(vnode, free_attr_cookie, descriptor->cookie); 6938 put_vnode(vnode); 6939 } 6940 } 6941 6942 6943 static status_t 6944 attr_read(struct file_descriptor* descriptor, off_t pos, void* buffer, 6945 size_t* length) 6946 { 6947 struct vnode* vnode = descriptor->u.vnode; 6948 6949 FUNCTION(("attr_read: buf %p, pos %" B_PRIdOFF ", len %p = %ld\n", buffer, 6950 pos, length, *length)); 6951 6952 if (!HAS_FS_CALL(vnode, read_attr)) 6953 return B_UNSUPPORTED; 6954 6955 return FS_CALL(vnode, read_attr, descriptor->cookie, pos, buffer, length); 6956 } 6957 6958 6959 static status_t 6960 attr_write(struct file_descriptor* descriptor, off_t pos, const void* buffer, 6961 size_t* length) 6962 { 6963 struct vnode* vnode = descriptor->u.vnode; 6964 6965 FUNCTION(("attr_write: buf %p, pos %" B_PRIdOFF ", len %p\n", buffer, pos, 6966 length)); 6967 6968 if (!HAS_FS_CALL(vnode, write_attr)) 6969 return B_UNSUPPORTED; 6970 6971 return FS_CALL(vnode, write_attr, descriptor->cookie, pos, buffer, length); 6972 } 6973 6974 6975 static off_t 6976 attr_seek(struct file_descriptor* descriptor, off_t pos, int seekType) 6977 { 6978 off_t offset; 6979 6980 switch (seekType) { 6981 case SEEK_SET: 6982 offset = 0; 6983 break; 6984 case SEEK_CUR: 6985 offset = descriptor->pos; 6986 break; 6987 case SEEK_END: 6988 { 6989 struct vnode* vnode = descriptor->u.vnode; 6990 if (!HAS_FS_CALL(vnode, read_stat)) 6991 return B_UNSUPPORTED; 6992 6993 struct stat stat; 6994 status_t status = FS_CALL(vnode, read_attr_stat, descriptor->cookie, 6995 &stat); 6996 if (status != B_OK) 6997 return status; 6998 6999 offset = stat.st_size; 7000 break; 7001 } 7002 default: 7003 return B_BAD_VALUE; 7004 } 7005 7006 // assumes off_t is 64 bits wide 7007 if (offset > 0 && LONGLONG_MAX - offset < pos) 7008 return B_BUFFER_OVERFLOW; 7009 7010 pos += offset; 7011 if (pos < 0) 7012 return B_BAD_VALUE; 7013 7014 return descriptor->pos = pos; 7015 } 7016 7017 7018 static status_t 7019 attr_read_stat(struct file_descriptor* descriptor, struct stat* stat) 7020 { 7021 struct vnode* vnode = descriptor->u.vnode; 7022 7023 FUNCTION(("attr_read_stat: stat 0x%p\n", stat)); 7024 7025 if (!HAS_FS_CALL(vnode, read_attr_stat)) 7026 return B_UNSUPPORTED; 7027 7028 return FS_CALL(vnode, read_attr_stat, descriptor->cookie, stat); 7029 } 7030 7031 7032 static status_t 7033 attr_write_stat(struct file_descriptor* descriptor, const struct stat* stat, 7034 int statMask) 7035 { 7036 struct vnode* vnode = descriptor->u.vnode; 7037 7038 FUNCTION(("attr_write_stat: stat = %p, statMask %d\n", stat, statMask)); 7039 7040 if (!HAS_FS_CALL(vnode, write_attr_stat)) 7041 return B_READ_ONLY_DEVICE; 7042 7043 return FS_CALL(vnode, write_attr_stat, descriptor->cookie, stat, statMask); 7044 } 7045 7046 7047 static status_t 7048 attr_remove(int fd, const char* name, bool kernel) 7049 { 7050 struct file_descriptor* descriptor; 7051 struct vnode* vnode; 7052 status_t status; 7053 7054 if (name == NULL || *name == '\0') 7055 return B_BAD_VALUE; 7056 7057 FUNCTION(("attr_remove: fd = %d, name = \"%s\", kernel %d\n", fd, name, 7058 kernel)); 7059 7060 descriptor = get_fd_and_vnode(fd, &vnode, kernel); 7061 if (descriptor == NULL) 7062 return B_FILE_ERROR; 7063 7064 if (HAS_FS_CALL(vnode, remove_attr)) 7065 status = FS_CALL(vnode, remove_attr, name); 7066 else 7067 status = B_READ_ONLY_DEVICE; 7068 7069 put_fd(descriptor); 7070 7071 return status; 7072 } 7073 7074 7075 static status_t 7076 attr_rename(int fromFD, const char* fromName, int toFD, const char* toName, 7077 bool kernel) 7078 { 7079 struct file_descriptor* fromDescriptor; 7080 struct file_descriptor* toDescriptor; 7081 struct vnode* fromVnode; 7082 struct vnode* toVnode; 7083 status_t status; 7084 7085 if (fromName == NULL || *fromName == '\0' || toName == NULL 7086 || *toName == '\0') 7087 return B_BAD_VALUE; 7088 7089 FUNCTION(("attr_rename: from fd = %d, from name = \"%s\", to fd = %d, to " 7090 "name = \"%s\", kernel %d\n", fromFD, fromName, toFD, toName, kernel)); 7091 7092 fromDescriptor = get_fd_and_vnode(fromFD, &fromVnode, kernel); 7093 if (fromDescriptor == NULL) 7094 return B_FILE_ERROR; 7095 7096 toDescriptor = get_fd_and_vnode(toFD, &toVnode, kernel); 7097 if (toDescriptor == NULL) { 7098 status = B_FILE_ERROR; 7099 goto err; 7100 } 7101 7102 // are the files on the same volume? 7103 if (fromVnode->device != toVnode->device) { 7104 status = B_CROSS_DEVICE_LINK; 7105 goto err1; 7106 } 7107 7108 if (HAS_FS_CALL(fromVnode, rename_attr)) { 7109 status = FS_CALL(fromVnode, rename_attr, fromName, toVnode, toName); 7110 } else 7111 status = B_READ_ONLY_DEVICE; 7112 7113 err1: 7114 put_fd(toDescriptor); 7115 err: 7116 put_fd(fromDescriptor); 7117 7118 return status; 7119 } 7120 7121 7122 static int 7123 index_dir_open(dev_t mountID, bool kernel) 7124 { 7125 struct fs_mount* mount; 7126 void* cookie; 7127 7128 FUNCTION(("index_dir_open(mountID = %" B_PRId32 ", kernel = %d)\n", mountID, 7129 kernel)); 7130 7131 status_t status = get_mount(mountID, &mount); 7132 if (status != B_OK) 7133 return status; 7134 7135 if (!HAS_FS_MOUNT_CALL(mount, open_index_dir)) { 7136 status = B_UNSUPPORTED; 7137 goto error; 7138 } 7139 7140 status = FS_MOUNT_CALL(mount, open_index_dir, &cookie); 7141 if (status != B_OK) 7142 goto error; 7143 7144 // get fd for the index directory 7145 int fd; 7146 fd = get_new_fd(FDTYPE_INDEX_DIR, mount, NULL, cookie, O_CLOEXEC, kernel); 7147 if (fd >= 0) 7148 return fd; 7149 7150 // something went wrong 7151 FS_MOUNT_CALL(mount, close_index_dir, cookie); 7152 FS_MOUNT_CALL(mount, free_index_dir_cookie, cookie); 7153 7154 status = fd; 7155 7156 error: 7157 put_mount(mount); 7158 return status; 7159 } 7160 7161 7162 static status_t 7163 index_dir_close(struct file_descriptor* descriptor) 7164 { 7165 struct fs_mount* mount = descriptor->u.mount; 7166 7167 FUNCTION(("index_dir_close(descriptor = %p)\n", descriptor)); 7168 7169 if (HAS_FS_MOUNT_CALL(mount, close_index_dir)) 7170 return FS_MOUNT_CALL(mount, close_index_dir, descriptor->cookie); 7171 7172 return B_OK; 7173 } 7174 7175 7176 static void 7177 index_dir_free_fd(struct file_descriptor* descriptor) 7178 { 7179 struct fs_mount* mount = descriptor->u.mount; 7180 7181 if (mount != NULL) { 7182 FS_MOUNT_CALL(mount, free_index_dir_cookie, descriptor->cookie); 7183 put_mount(mount); 7184 } 7185 } 7186 7187 7188 static status_t 7189 index_dir_read(struct io_context* ioContext, struct file_descriptor* descriptor, 7190 struct dirent* buffer, size_t bufferSize, uint32* _count) 7191 { 7192 struct fs_mount* mount = descriptor->u.mount; 7193 7194 if (HAS_FS_MOUNT_CALL(mount, read_index_dir)) { 7195 return FS_MOUNT_CALL(mount, read_index_dir, descriptor->cookie, buffer, 7196 bufferSize, _count); 7197 } 7198 7199 return B_UNSUPPORTED; 7200 } 7201 7202 7203 static status_t 7204 index_dir_rewind(struct file_descriptor* descriptor) 7205 { 7206 struct fs_mount* mount = descriptor->u.mount; 7207 7208 if (HAS_FS_MOUNT_CALL(mount, rewind_index_dir)) 7209 return FS_MOUNT_CALL(mount, rewind_index_dir, descriptor->cookie); 7210 7211 return B_UNSUPPORTED; 7212 } 7213 7214 7215 static status_t 7216 index_create(dev_t mountID, const char* name, uint32 type, uint32 flags, 7217 bool kernel) 7218 { 7219 FUNCTION(("index_create(mountID = %" B_PRId32 ", name = %s, kernel = %d)\n", 7220 mountID, name, kernel)); 7221 7222 struct fs_mount* mount; 7223 status_t status = get_mount(mountID, &mount); 7224 if (status != B_OK) 7225 return status; 7226 7227 if (!HAS_FS_MOUNT_CALL(mount, create_index)) { 7228 status = B_READ_ONLY_DEVICE; 7229 goto out; 7230 } 7231 7232 status = FS_MOUNT_CALL(mount, create_index, name, type, flags); 7233 7234 out: 7235 put_mount(mount); 7236 return status; 7237 } 7238 7239 7240 #if 0 7241 static status_t 7242 index_read_stat(struct file_descriptor* descriptor, struct stat* stat) 7243 { 7244 struct vnode* vnode = descriptor->u.vnode; 7245 7246 // ToDo: currently unused! 7247 FUNCTION(("index_read_stat: stat 0x%p\n", stat)); 7248 if (!HAS_FS_CALL(vnode, read_index_stat)) 7249 return B_UNSUPPORTED; 7250 7251 return B_UNSUPPORTED; 7252 //return FS_CALL(vnode, read_index_stat, descriptor->cookie, stat); 7253 } 7254 7255 7256 static void 7257 index_free_fd(struct file_descriptor* descriptor) 7258 { 7259 struct vnode* vnode = descriptor->u.vnode; 7260 7261 if (vnode != NULL) { 7262 FS_CALL(vnode, free_index_cookie, descriptor->cookie); 7263 put_vnode(vnode); 7264 } 7265 } 7266 #endif 7267 7268 7269 static status_t 7270 index_name_read_stat(dev_t mountID, const char* name, struct stat* stat, 7271 bool kernel) 7272 { 7273 FUNCTION(("index_remove(mountID = %" B_PRId32 ", name = %s, kernel = %d)\n", 7274 mountID, name, kernel)); 7275 7276 struct fs_mount* mount; 7277 status_t status = get_mount(mountID, &mount); 7278 if (status != B_OK) 7279 return status; 7280 7281 if (!HAS_FS_MOUNT_CALL(mount, read_index_stat)) { 7282 status = B_UNSUPPORTED; 7283 goto out; 7284 } 7285 7286 status = FS_MOUNT_CALL(mount, read_index_stat, name, stat); 7287 7288 out: 7289 put_mount(mount); 7290 return status; 7291 } 7292 7293 7294 static status_t 7295 index_remove(dev_t mountID, const char* name, bool kernel) 7296 { 7297 FUNCTION(("index_remove(mountID = %" B_PRId32 ", name = %s, kernel = %d)\n", 7298 mountID, name, kernel)); 7299 7300 struct fs_mount* mount; 7301 status_t status = get_mount(mountID, &mount); 7302 if (status != B_OK) 7303 return status; 7304 7305 if (!HAS_FS_MOUNT_CALL(mount, remove_index)) { 7306 status = B_READ_ONLY_DEVICE; 7307 goto out; 7308 } 7309 7310 status = FS_MOUNT_CALL(mount, remove_index, name); 7311 7312 out: 7313 put_mount(mount); 7314 return status; 7315 } 7316 7317 7318 /*! TODO: the query FS API is still the pretty much the same as in R5. 7319 It would be nice if the FS would find some more kernel support 7320 for them. 7321 For example, query parsing should be moved into the kernel. 7322 */ 7323 static int 7324 query_open(dev_t device, const char* query, uint32 flags, port_id port, 7325 int32 token, bool kernel) 7326 { 7327 struct fs_mount* mount; 7328 void* cookie; 7329 7330 FUNCTION(("query_open(device = %" B_PRId32 ", query = \"%s\", kernel = %d)\n", 7331 device, query, kernel)); 7332 7333 status_t status = get_mount(device, &mount); 7334 if (status != B_OK) 7335 return status; 7336 7337 if (!HAS_FS_MOUNT_CALL(mount, open_query)) { 7338 status = B_UNSUPPORTED; 7339 goto error; 7340 } 7341 7342 status = FS_MOUNT_CALL(mount, open_query, query, flags, port, token, 7343 &cookie); 7344 if (status != B_OK) 7345 goto error; 7346 7347 // get fd for the index directory 7348 int fd; 7349 fd = get_new_fd(FDTYPE_QUERY, mount, NULL, cookie, O_CLOEXEC, kernel); 7350 if (fd >= 0) 7351 return fd; 7352 7353 status = fd; 7354 7355 // something went wrong 7356 FS_MOUNT_CALL(mount, close_query, cookie); 7357 FS_MOUNT_CALL(mount, free_query_cookie, cookie); 7358 7359 error: 7360 put_mount(mount); 7361 return status; 7362 } 7363 7364 7365 static status_t 7366 query_close(struct file_descriptor* descriptor) 7367 { 7368 struct fs_mount* mount = descriptor->u.mount; 7369 7370 FUNCTION(("query_close(descriptor = %p)\n", descriptor)); 7371 7372 if (HAS_FS_MOUNT_CALL(mount, close_query)) 7373 return FS_MOUNT_CALL(mount, close_query, descriptor->cookie); 7374 7375 return B_OK; 7376 } 7377 7378 7379 static void 7380 query_free_fd(struct file_descriptor* descriptor) 7381 { 7382 struct fs_mount* mount = descriptor->u.mount; 7383 7384 if (mount != NULL) { 7385 FS_MOUNT_CALL(mount, free_query_cookie, descriptor->cookie); 7386 put_mount(mount); 7387 } 7388 } 7389 7390 7391 static status_t 7392 query_read(struct io_context* ioContext, struct file_descriptor* descriptor, 7393 struct dirent* buffer, size_t bufferSize, uint32* _count) 7394 { 7395 struct fs_mount* mount = descriptor->u.mount; 7396 7397 if (HAS_FS_MOUNT_CALL(mount, read_query)) { 7398 return FS_MOUNT_CALL(mount, read_query, descriptor->cookie, buffer, 7399 bufferSize, _count); 7400 } 7401 7402 return B_UNSUPPORTED; 7403 } 7404 7405 7406 static status_t 7407 query_rewind(struct file_descriptor* descriptor) 7408 { 7409 struct fs_mount* mount = descriptor->u.mount; 7410 7411 if (HAS_FS_MOUNT_CALL(mount, rewind_query)) 7412 return FS_MOUNT_CALL(mount, rewind_query, descriptor->cookie); 7413 7414 return B_UNSUPPORTED; 7415 } 7416 7417 7418 // #pragma mark - General File System functions 7419 7420 7421 static dev_t 7422 fs_mount(char* path, const char* device, const char* fsName, uint32 flags, 7423 const char* args, bool kernel) 7424 { 7425 struct ::fs_mount* mount; 7426 status_t status = B_OK; 7427 fs_volume* volume = NULL; 7428 int32 layer = 0; 7429 Vnode* coveredNode = NULL; 7430 7431 FUNCTION(("fs_mount: path = '%s', device = '%s', fs_name = '%s', flags = %#" 7432 B_PRIx32 ", args = '%s'\n", path, device, fsName, flags, args)); 7433 7434 // The path is always safe, we just have to make sure that fsName is 7435 // almost valid - we can't make any assumptions about args, though. 7436 // A NULL fsName is OK, if a device was given and the FS is not virtual. 7437 // We'll get it from the DDM later. 7438 if (fsName == NULL) { 7439 if (!device || flags & B_MOUNT_VIRTUAL_DEVICE) 7440 return B_BAD_VALUE; 7441 } else if (fsName[0] == '\0') 7442 return B_BAD_VALUE; 7443 7444 RecursiveLocker mountOpLocker(sMountOpLock); 7445 7446 // Helper to delete a newly created file device on failure. 7447 // Not exactly beautiful, but helps to keep the code below cleaner. 7448 struct FileDeviceDeleter { 7449 FileDeviceDeleter() : id(-1) {} 7450 ~FileDeviceDeleter() 7451 { 7452 KDiskDeviceManager::Default()->DeleteFileDevice(id); 7453 } 7454 7455 partition_id id; 7456 } fileDeviceDeleter; 7457 7458 // If the file system is not a "virtual" one, the device argument should 7459 // point to a real file/device (if given at all). 7460 // get the partition 7461 KDiskDeviceManager* ddm = KDiskDeviceManager::Default(); 7462 KPartition* partition = NULL; 7463 KPath normalizedDevice; 7464 bool newlyCreatedFileDevice = false; 7465 7466 if (!(flags & B_MOUNT_VIRTUAL_DEVICE) && device != NULL) { 7467 // normalize the device path 7468 status = normalizedDevice.SetTo(device, true); 7469 if (status != B_OK) 7470 return status; 7471 7472 // get a corresponding partition from the DDM 7473 partition = ddm->RegisterPartition(normalizedDevice.Path()); 7474 if (partition == NULL) { 7475 // Partition not found: This either means, the user supplied 7476 // an invalid path, or the path refers to an image file. We try 7477 // to let the DDM create a file device for the path. 7478 partition_id deviceID = ddm->CreateFileDevice( 7479 normalizedDevice.Path(), &newlyCreatedFileDevice); 7480 if (deviceID >= 0) { 7481 partition = ddm->RegisterPartition(deviceID); 7482 if (newlyCreatedFileDevice) 7483 fileDeviceDeleter.id = deviceID; 7484 } 7485 } 7486 7487 if (!partition) { 7488 TRACE(("fs_mount(): Partition `%s' not found.\n", 7489 normalizedDevice.Path())); 7490 return B_ENTRY_NOT_FOUND; 7491 } 7492 7493 device = normalizedDevice.Path(); 7494 // correct path to file device 7495 } 7496 PartitionRegistrar partitionRegistrar(partition, true); 7497 7498 // Write lock the partition's device. For the time being, we keep the lock 7499 // until we're done mounting -- not nice, but ensure, that no-one is 7500 // interfering. 7501 // TODO: Just mark the partition busy while mounting! 7502 KDiskDevice* diskDevice = NULL; 7503 if (partition) { 7504 diskDevice = ddm->WriteLockDevice(partition->Device()->ID()); 7505 if (!diskDevice) { 7506 TRACE(("fs_mount(): Failed to lock disk device!\n")); 7507 return B_ERROR; 7508 } 7509 } 7510 7511 DeviceWriteLocker writeLocker(diskDevice, true); 7512 // this takes over the write lock acquired before 7513 7514 if (partition != NULL) { 7515 // make sure, that the partition is not busy 7516 if (partition->IsBusy()) { 7517 TRACE(("fs_mount(): Partition is busy.\n")); 7518 return B_BUSY; 7519 } 7520 7521 // if no FS name had been supplied, we get it from the partition 7522 if (fsName == NULL) { 7523 KDiskSystem* diskSystem = partition->DiskSystem(); 7524 if (!diskSystem) { 7525 TRACE(("fs_mount(): No FS name was given, and the DDM didn't " 7526 "recognize it.\n")); 7527 return B_BAD_VALUE; 7528 } 7529 7530 if (!diskSystem->IsFileSystem()) { 7531 TRACE(("fs_mount(): No FS name was given, and the DDM found a " 7532 "partitioning system.\n")); 7533 return B_BAD_VALUE; 7534 } 7535 7536 // The disk system name will not change, and the KDiskSystem 7537 // object will not go away while the disk device is locked (and 7538 // the partition has a reference to it), so this is safe. 7539 fsName = diskSystem->Name(); 7540 } 7541 } 7542 7543 mount = new(std::nothrow) (struct ::fs_mount); 7544 if (mount == NULL) 7545 return B_NO_MEMORY; 7546 7547 mount->device_name = strdup(device); 7548 // "device" can be NULL 7549 7550 status = mount->entry_cache.Init(); 7551 if (status != B_OK) 7552 goto err1; 7553 7554 // initialize structure 7555 mount->id = sNextMountID++; 7556 mount->partition = NULL; 7557 mount->root_vnode = NULL; 7558 mount->covers_vnode = NULL; 7559 mount->unmounting = false; 7560 mount->owns_file_device = false; 7561 mount->volume = NULL; 7562 7563 // build up the volume(s) 7564 while (true) { 7565 char* layerFSName = get_file_system_name_for_layer(fsName, layer); 7566 if (layerFSName == NULL) { 7567 if (layer == 0) { 7568 status = B_NO_MEMORY; 7569 goto err1; 7570 } 7571 7572 break; 7573 } 7574 MemoryDeleter layerFSNameDeleter(layerFSName); 7575 7576 volume = (fs_volume*)malloc(sizeof(fs_volume)); 7577 if (volume == NULL) { 7578 status = B_NO_MEMORY; 7579 goto err1; 7580 } 7581 7582 volume->id = mount->id; 7583 volume->partition = partition != NULL ? partition->ID() : -1; 7584 volume->layer = layer++; 7585 volume->private_volume = NULL; 7586 volume->ops = NULL; 7587 volume->sub_volume = NULL; 7588 volume->super_volume = NULL; 7589 volume->file_system = NULL; 7590 volume->file_system_name = NULL; 7591 7592 volume->file_system_name = get_file_system_name(layerFSName); 7593 if (volume->file_system_name == NULL) { 7594 status = B_NO_MEMORY; 7595 free(volume); 7596 goto err1; 7597 } 7598 7599 volume->file_system = get_file_system(layerFSName); 7600 if (volume->file_system == NULL) { 7601 status = B_DEVICE_NOT_FOUND; 7602 free(volume->file_system_name); 7603 free(volume); 7604 goto err1; 7605 } 7606 7607 if (mount->volume == NULL) 7608 mount->volume = volume; 7609 else { 7610 volume->super_volume = mount->volume; 7611 mount->volume->sub_volume = volume; 7612 mount->volume = volume; 7613 } 7614 } 7615 7616 // insert mount struct into list before we call FS's mount() function 7617 // so that vnodes can be created for this mount 7618 rw_lock_write_lock(&sMountLock); 7619 sMountsTable->Insert(mount); 7620 rw_lock_write_unlock(&sMountLock); 7621 7622 ino_t rootID; 7623 7624 if (!sRoot) { 7625 // we haven't mounted anything yet 7626 if (strcmp(path, "/") != 0) { 7627 status = B_ERROR; 7628 goto err2; 7629 } 7630 7631 status = mount->volume->file_system->mount(mount->volume, device, flags, 7632 args, &rootID); 7633 if (status != B_OK || mount->volume->ops == NULL) 7634 goto err2; 7635 } else { 7636 status = path_to_vnode(path, true, &coveredNode, NULL, kernel); 7637 if (status != B_OK) 7638 goto err2; 7639 7640 mount->covers_vnode = coveredNode; 7641 7642 // make sure covered_vnode is a directory 7643 if (!S_ISDIR(coveredNode->Type())) { 7644 status = B_NOT_A_DIRECTORY; 7645 goto err3; 7646 } 7647 7648 if (coveredNode->IsCovered()) { 7649 // this is already a covered vnode 7650 status = B_BUSY; 7651 goto err3; 7652 } 7653 7654 // mount it/them 7655 fs_volume* volume = mount->volume; 7656 while (volume) { 7657 status = volume->file_system->mount(volume, device, flags, args, 7658 &rootID); 7659 if (status != B_OK || volume->ops == NULL) { 7660 if (status == B_OK && volume->ops == NULL) 7661 panic("fs_mount: mount() succeeded but ops is NULL!"); 7662 if (volume->sub_volume) 7663 goto err4; 7664 goto err3; 7665 } 7666 7667 volume = volume->super_volume; 7668 } 7669 7670 volume = mount->volume; 7671 while (volume) { 7672 if (volume->ops->all_layers_mounted != NULL) 7673 volume->ops->all_layers_mounted(volume); 7674 volume = volume->super_volume; 7675 } 7676 } 7677 7678 // the root node is supposed to be owned by the file system - it must 7679 // exist at this point 7680 mount->root_vnode = lookup_vnode(mount->id, rootID); 7681 if (mount->root_vnode == NULL || mount->root_vnode->ref_count != 1) { 7682 panic("fs_mount: file system does not own its root node!\n"); 7683 status = B_ERROR; 7684 goto err4; 7685 } 7686 7687 // set up the links between the root vnode and the vnode it covers 7688 rw_lock_write_lock(&sVnodeLock); 7689 if (coveredNode != NULL) { 7690 if (coveredNode->IsCovered()) { 7691 // the vnode is covered now 7692 status = B_BUSY; 7693 rw_lock_write_unlock(&sVnodeLock); 7694 goto err4; 7695 } 7696 7697 mount->root_vnode->covers = coveredNode; 7698 mount->root_vnode->SetCovering(true); 7699 7700 coveredNode->covered_by = mount->root_vnode; 7701 coveredNode->SetCovered(true); 7702 } 7703 rw_lock_write_unlock(&sVnodeLock); 7704 7705 if (!sRoot) { 7706 sRoot = mount->root_vnode; 7707 mutex_lock(&sIOContextRootLock); 7708 get_current_io_context(true)->root = sRoot; 7709 mutex_unlock(&sIOContextRootLock); 7710 inc_vnode_ref_count(sRoot); 7711 } 7712 7713 // supply the partition (if any) with the mount cookie and mark it mounted 7714 if (partition) { 7715 partition->SetMountCookie(mount->volume->private_volume); 7716 partition->SetVolumeID(mount->id); 7717 7718 // keep a partition reference as long as the partition is mounted 7719 partitionRegistrar.Detach(); 7720 mount->partition = partition; 7721 mount->owns_file_device = newlyCreatedFileDevice; 7722 fileDeviceDeleter.id = -1; 7723 } 7724 7725 notify_mount(mount->id, 7726 coveredNode != NULL ? coveredNode->device : -1, 7727 coveredNode ? coveredNode->id : -1); 7728 7729 return mount->id; 7730 7731 err4: 7732 FS_MOUNT_CALL_NO_PARAMS(mount, unmount); 7733 err3: 7734 if (coveredNode != NULL) 7735 put_vnode(coveredNode); 7736 err2: 7737 rw_lock_write_lock(&sMountLock); 7738 sMountsTable->Remove(mount); 7739 rw_lock_write_unlock(&sMountLock); 7740 err1: 7741 delete mount; 7742 7743 return status; 7744 } 7745 7746 7747 static status_t 7748 fs_unmount(char* path, dev_t mountID, uint32 flags, bool kernel) 7749 { 7750 struct fs_mount* mount; 7751 status_t err; 7752 7753 FUNCTION(("fs_unmount(path '%s', dev %" B_PRId32 ", kernel %d\n", path, 7754 mountID, kernel)); 7755 7756 struct vnode* pathVnode = NULL; 7757 if (path != NULL) { 7758 err = path_to_vnode(path, true, &pathVnode, NULL, kernel); 7759 if (err != B_OK) 7760 return B_ENTRY_NOT_FOUND; 7761 } 7762 7763 RecursiveLocker mountOpLocker(sMountOpLock); 7764 ReadLocker mountLocker(sMountLock); 7765 7766 mount = find_mount(path != NULL ? pathVnode->device : mountID); 7767 if (mount == NULL) { 7768 panic("fs_unmount: find_mount() failed on root vnode @%p of mount\n", 7769 pathVnode); 7770 } 7771 7772 mountLocker.Unlock(); 7773 7774 if (path != NULL) { 7775 put_vnode(pathVnode); 7776 7777 if (mount->root_vnode != pathVnode) { 7778 // not mountpoint 7779 return B_BAD_VALUE; 7780 } 7781 } 7782 7783 // if the volume is associated with a partition, lock the device of the 7784 // partition as long as we are unmounting 7785 KDiskDeviceManager* ddm = KDiskDeviceManager::Default(); 7786 KPartition* partition = mount->partition; 7787 KDiskDevice* diskDevice = NULL; 7788 if (partition != NULL) { 7789 if (partition->Device() == NULL) { 7790 dprintf("fs_unmount(): There is no device!\n"); 7791 return B_ERROR; 7792 } 7793 diskDevice = ddm->WriteLockDevice(partition->Device()->ID()); 7794 if (!diskDevice) { 7795 TRACE(("fs_unmount(): Failed to lock disk device!\n")); 7796 return B_ERROR; 7797 } 7798 } 7799 DeviceWriteLocker writeLocker(diskDevice, true); 7800 7801 // make sure, that the partition is not busy 7802 if (partition != NULL) { 7803 if ((flags & B_UNMOUNT_BUSY_PARTITION) == 0 && partition->IsBusy()) { 7804 TRACE(("fs_unmount(): Partition is busy.\n")); 7805 return B_BUSY; 7806 } 7807 } 7808 7809 // grab the vnode master mutex to keep someone from creating 7810 // a vnode while we're figuring out if we can continue 7811 WriteLocker vnodesWriteLocker(&sVnodeLock); 7812 7813 bool disconnectedDescriptors = false; 7814 7815 while (true) { 7816 bool busy = false; 7817 7818 // cycle through the list of vnodes associated with this mount and 7819 // make sure all of them are not busy or have refs on them 7820 VnodeList::Iterator iterator = mount->vnodes.GetIterator(); 7821 while (struct vnode* vnode = iterator.Next()) { 7822 if (vnode->IsBusy()) { 7823 busy = true; 7824 break; 7825 } 7826 7827 // check the vnode's ref count -- subtract additional references for 7828 // covering 7829 int32 refCount = vnode->ref_count; 7830 if (vnode->covers != NULL) 7831 refCount--; 7832 if (vnode->covered_by != NULL) 7833 refCount--; 7834 7835 if (refCount != 0) { 7836 // there are still vnodes in use on this mount, so we cannot 7837 // unmount yet 7838 busy = true; 7839 break; 7840 } 7841 } 7842 7843 if (!busy) 7844 break; 7845 7846 if ((flags & B_FORCE_UNMOUNT) == 0) 7847 return B_BUSY; 7848 7849 if (disconnectedDescriptors) { 7850 // wait a bit until the last access is finished, and then try again 7851 vnodesWriteLocker.Unlock(); 7852 snooze(100000); 7853 // TODO: if there is some kind of bug that prevents the ref counts 7854 // from getting back to zero, this will fall into an endless loop... 7855 vnodesWriteLocker.Lock(); 7856 continue; 7857 } 7858 7859 // the file system is still busy - but we're forced to unmount it, 7860 // so let's disconnect all open file descriptors 7861 7862 mount->unmounting = true; 7863 // prevent new vnodes from being created 7864 7865 vnodesWriteLocker.Unlock(); 7866 7867 disconnect_mount_or_vnode_fds(mount, NULL); 7868 disconnectedDescriptors = true; 7869 7870 vnodesWriteLocker.Lock(); 7871 } 7872 7873 // We can safely continue. Mark all of the vnodes busy and this mount 7874 // structure in unmounting state. Also undo the vnode covers/covered_by 7875 // links. 7876 mount->unmounting = true; 7877 7878 VnodeList::Iterator iterator = mount->vnodes.GetIterator(); 7879 while (struct vnode* vnode = iterator.Next()) { 7880 // Remove all covers/covered_by links from other mounts' nodes to this 7881 // vnode and adjust the node ref count accordingly. We will release the 7882 // references to the external vnodes below. 7883 if (Vnode* coveredNode = vnode->covers) { 7884 if (Vnode* coveringNode = vnode->covered_by) { 7885 // We have both covered and covering vnodes, so just remove us 7886 // from the chain. 7887 coveredNode->covered_by = coveringNode; 7888 coveringNode->covers = coveredNode; 7889 vnode->ref_count -= 2; 7890 7891 vnode->covered_by = NULL; 7892 vnode->covers = NULL; 7893 vnode->SetCovering(false); 7894 vnode->SetCovered(false); 7895 } else { 7896 // We only have a covered vnode. Remove its link to us. 7897 coveredNode->covered_by = NULL; 7898 coveredNode->SetCovered(false); 7899 vnode->ref_count--; 7900 7901 // If the other node is an external vnode, we keep its link 7902 // link around so we can put the reference later on. Otherwise 7903 // we get rid of it right now. 7904 if (coveredNode->mount == mount) { 7905 vnode->covers = NULL; 7906 coveredNode->ref_count--; 7907 } 7908 } 7909 } else if (Vnode* coveringNode = vnode->covered_by) { 7910 // We only have a covering vnode. Remove its link to us. 7911 coveringNode->covers = NULL; 7912 coveringNode->SetCovering(false); 7913 vnode->ref_count--; 7914 7915 // If the other node is an external vnode, we keep its link 7916 // link around so we can put the reference later on. Otherwise 7917 // we get rid of it right now. 7918 if (coveringNode->mount == mount) { 7919 vnode->covered_by = NULL; 7920 coveringNode->ref_count--; 7921 } 7922 } 7923 7924 vnode->SetBusy(true); 7925 vnode_to_be_freed(vnode); 7926 } 7927 7928 vnodesWriteLocker.Unlock(); 7929 7930 // Free all vnodes associated with this mount. 7931 // They will be removed from the mount list by free_vnode(), so 7932 // we don't have to do this. 7933 while (struct vnode* vnode = mount->vnodes.Head()) { 7934 // Put the references to external covered/covering vnodes we kept above. 7935 if (Vnode* coveredNode = vnode->covers) 7936 put_vnode(coveredNode); 7937 if (Vnode* coveringNode = vnode->covered_by) 7938 put_vnode(coveringNode); 7939 7940 free_vnode(vnode, false); 7941 } 7942 7943 // remove the mount structure from the hash table 7944 rw_lock_write_lock(&sMountLock); 7945 sMountsTable->Remove(mount); 7946 rw_lock_write_unlock(&sMountLock); 7947 7948 mountOpLocker.Unlock(); 7949 7950 FS_MOUNT_CALL_NO_PARAMS(mount, unmount); 7951 notify_unmount(mount->id); 7952 7953 // dereference the partition and mark it unmounted 7954 if (partition) { 7955 partition->SetVolumeID(-1); 7956 partition->SetMountCookie(NULL); 7957 7958 if (mount->owns_file_device) 7959 KDiskDeviceManager::Default()->DeleteFileDevice(partition->ID()); 7960 partition->Unregister(); 7961 } 7962 7963 delete mount; 7964 return B_OK; 7965 } 7966 7967 7968 static status_t 7969 fs_sync(dev_t device) 7970 { 7971 struct fs_mount* mount; 7972 status_t status = get_mount(device, &mount); 7973 if (status != B_OK) 7974 return status; 7975 7976 struct vnode marker; 7977 memset(&marker, 0, sizeof(marker)); 7978 marker.SetBusy(true); 7979 marker.SetRemoved(true); 7980 7981 // First, synchronize all file caches 7982 7983 while (true) { 7984 WriteLocker locker(sVnodeLock); 7985 // Note: That's the easy way. Which is probably OK for sync(), 7986 // since it's a relatively rare call and doesn't need to allow for 7987 // a lot of concurrency. Using a read lock would be possible, but 7988 // also more involved, since we had to lock the individual nodes 7989 // and take care of the locking order, which we might not want to 7990 // do while holding fs_mount::lock. 7991 7992 // synchronize access to vnode list 7993 mutex_lock(&mount->lock); 7994 7995 struct vnode* vnode; 7996 if (!marker.IsRemoved()) { 7997 vnode = mount->vnodes.GetNext(&marker); 7998 mount->vnodes.Remove(&marker); 7999 marker.SetRemoved(true); 8000 } else 8001 vnode = mount->vnodes.First(); 8002 8003 while (vnode != NULL && (vnode->cache == NULL 8004 || vnode->IsRemoved() || vnode->IsBusy())) { 8005 // TODO: we could track writes (and writable mapped vnodes) 8006 // and have a simple flag that we could test for here 8007 vnode = mount->vnodes.GetNext(vnode); 8008 } 8009 8010 if (vnode != NULL) { 8011 // insert marker vnode again 8012 mount->vnodes.Insert(mount->vnodes.GetNext(vnode), &marker); 8013 marker.SetRemoved(false); 8014 } 8015 8016 mutex_unlock(&mount->lock); 8017 8018 if (vnode == NULL) 8019 break; 8020 8021 vnode = lookup_vnode(mount->id, vnode->id); 8022 if (vnode == NULL || vnode->IsBusy()) 8023 continue; 8024 8025 if (vnode->ref_count == 0) { 8026 // this vnode has been unused before 8027 vnode_used(vnode); 8028 } 8029 inc_vnode_ref_count(vnode); 8030 8031 locker.Unlock(); 8032 8033 if (vnode->cache != NULL && !vnode->IsRemoved()) 8034 vnode->cache->WriteModified(); 8035 8036 put_vnode(vnode); 8037 } 8038 8039 // Let the file systems do their synchronizing work 8040 if (HAS_FS_MOUNT_CALL(mount, sync)) 8041 status = FS_MOUNT_CALL_NO_PARAMS(mount, sync); 8042 8043 // Finally, flush the underlying device's write cache (if possible.) 8044 if (mount->partition != NULL && mount->partition->Device() != NULL) 8045 ioctl(mount->partition->Device()->FD(), B_FLUSH_DRIVE_CACHE); 8046 8047 put_mount(mount); 8048 return status; 8049 } 8050 8051 8052 static status_t 8053 fs_read_info(dev_t device, struct fs_info* info) 8054 { 8055 struct fs_mount* mount; 8056 status_t status = get_mount(device, &mount); 8057 if (status != B_OK) 8058 return status; 8059 8060 memset(info, 0, sizeof(struct fs_info)); 8061 8062 if (HAS_FS_MOUNT_CALL(mount, read_fs_info)) 8063 status = FS_MOUNT_CALL(mount, read_fs_info, info); 8064 8065 // fill in info the file system doesn't (have to) know about 8066 if (status == B_OK) { 8067 info->dev = mount->id; 8068 info->root = mount->root_vnode->id; 8069 8070 fs_volume* volume = mount->volume; 8071 while (volume->super_volume != NULL) 8072 volume = volume->super_volume; 8073 8074 strlcpy(info->fsh_name, volume->file_system_name, 8075 sizeof(info->fsh_name)); 8076 if (mount->device_name != NULL) { 8077 strlcpy(info->device_name, mount->device_name, 8078 sizeof(info->device_name)); 8079 } 8080 } 8081 8082 // if the call is not supported by the file system, there are still 8083 // the parts that we filled out ourselves 8084 8085 put_mount(mount); 8086 return status; 8087 } 8088 8089 8090 static status_t 8091 fs_write_info(dev_t device, const struct fs_info* info, int mask) 8092 { 8093 struct fs_mount* mount; 8094 status_t status = get_mount(device, &mount); 8095 if (status != B_OK) 8096 return status; 8097 8098 if (HAS_FS_MOUNT_CALL(mount, write_fs_info)) 8099 status = FS_MOUNT_CALL(mount, write_fs_info, info, mask); 8100 else 8101 status = B_READ_ONLY_DEVICE; 8102 8103 put_mount(mount); 8104 return status; 8105 } 8106 8107 8108 static dev_t 8109 fs_next_device(int32* _cookie) 8110 { 8111 struct fs_mount* mount = NULL; 8112 dev_t device = *_cookie; 8113 8114 rw_lock_read_lock(&sMountLock); 8115 8116 // Since device IDs are assigned sequentially, this algorithm 8117 // does work good enough. It makes sure that the device list 8118 // returned is sorted, and that no device is skipped when an 8119 // already visited device got unmounted. 8120 8121 while (device < sNextMountID) { 8122 mount = find_mount(device++); 8123 if (mount != NULL && mount->volume->private_volume != NULL) 8124 break; 8125 } 8126 8127 *_cookie = device; 8128 8129 if (mount != NULL) 8130 device = mount->id; 8131 else 8132 device = B_BAD_VALUE; 8133 8134 rw_lock_read_unlock(&sMountLock); 8135 8136 return device; 8137 } 8138 8139 8140 ssize_t 8141 fs_read_attr(int fd, const char *attribute, uint32 type, off_t pos, 8142 void *buffer, size_t readBytes) 8143 { 8144 int attrFD = attr_open(fd, NULL, attribute, O_RDONLY, true); 8145 if (attrFD < 0) 8146 return attrFD; 8147 8148 ssize_t bytesRead = _kern_read(attrFD, pos, buffer, readBytes); 8149 8150 _kern_close(attrFD); 8151 8152 return bytesRead; 8153 } 8154 8155 8156 static status_t 8157 get_cwd(char* buffer, size_t size, bool kernel) 8158 { 8159 // Get current working directory from io context 8160 struct io_context* context = get_current_io_context(kernel); 8161 status_t status; 8162 8163 FUNCTION(("vfs_get_cwd: buf %p, size %ld\n", buffer, size)); 8164 8165 mutex_lock(&context->io_mutex); 8166 8167 struct vnode* vnode = context->cwd; 8168 if (vnode) 8169 inc_vnode_ref_count(vnode); 8170 8171 mutex_unlock(&context->io_mutex); 8172 8173 if (vnode) { 8174 status = dir_vnode_to_path(vnode, buffer, size, kernel); 8175 put_vnode(vnode); 8176 } else 8177 status = B_ERROR; 8178 8179 return status; 8180 } 8181 8182 8183 static status_t 8184 set_cwd(int fd, char* path, bool kernel) 8185 { 8186 struct io_context* context; 8187 struct vnode* vnode = NULL; 8188 struct vnode* oldDirectory; 8189 status_t status; 8190 8191 FUNCTION(("set_cwd: path = \'%s\'\n", path)); 8192 8193 // Get vnode for passed path, and bail if it failed 8194 status = fd_and_path_to_vnode(fd, path, true, &vnode, NULL, kernel); 8195 if (status < 0) 8196 return status; 8197 8198 if (!S_ISDIR(vnode->Type())) { 8199 // nope, can't cwd to here 8200 status = B_NOT_A_DIRECTORY; 8201 goto err; 8202 } 8203 8204 // We need to have the permission to enter the directory, too 8205 if (HAS_FS_CALL(vnode, access)) { 8206 status = FS_CALL(vnode, access, X_OK); 8207 if (status != B_OK) 8208 goto err; 8209 } 8210 8211 // Get current io context and lock 8212 context = get_current_io_context(kernel); 8213 mutex_lock(&context->io_mutex); 8214 8215 // save the old current working directory first 8216 oldDirectory = context->cwd; 8217 context->cwd = vnode; 8218 8219 mutex_unlock(&context->io_mutex); 8220 8221 if (oldDirectory) 8222 put_vnode(oldDirectory); 8223 8224 return B_NO_ERROR; 8225 8226 err: 8227 put_vnode(vnode); 8228 return status; 8229 } 8230 8231 8232 static status_t 8233 user_copy_name(char* to, const char* from, size_t length) 8234 { 8235 ssize_t len = user_strlcpy(to, from, length); 8236 if (len < 0) 8237 return len; 8238 if (len >= (ssize_t)length) 8239 return B_NAME_TOO_LONG; 8240 return B_OK; 8241 } 8242 8243 8244 // #pragma mark - kernel mirrored syscalls 8245 8246 8247 dev_t 8248 _kern_mount(const char* path, const char* device, const char* fsName, 8249 uint32 flags, const char* args, size_t argsLength) 8250 { 8251 KPath pathBuffer(path); 8252 if (pathBuffer.InitCheck() != B_OK) 8253 return B_NO_MEMORY; 8254 8255 return fs_mount(pathBuffer.LockBuffer(), device, fsName, flags, args, true); 8256 } 8257 8258 8259 status_t 8260 _kern_unmount(const char* path, uint32 flags) 8261 { 8262 KPath pathBuffer(path); 8263 if (pathBuffer.InitCheck() != B_OK) 8264 return B_NO_MEMORY; 8265 8266 return fs_unmount(pathBuffer.LockBuffer(), -1, flags, true); 8267 } 8268 8269 8270 status_t 8271 _kern_read_fs_info(dev_t device, struct fs_info* info) 8272 { 8273 if (info == NULL) 8274 return B_BAD_VALUE; 8275 8276 return fs_read_info(device, info); 8277 } 8278 8279 8280 status_t 8281 _kern_write_fs_info(dev_t device, const struct fs_info* info, int mask) 8282 { 8283 if (info == NULL) 8284 return B_BAD_VALUE; 8285 8286 return fs_write_info(device, info, mask); 8287 } 8288 8289 8290 status_t 8291 _kern_sync(void) 8292 { 8293 // Note: _kern_sync() is also called from _user_sync() 8294 int32 cookie = 0; 8295 dev_t device; 8296 while ((device = next_dev(&cookie)) >= 0) { 8297 status_t status = fs_sync(device); 8298 if (status != B_OK && status != B_BAD_VALUE) { 8299 dprintf("sync: device %" B_PRIdDEV " couldn't sync: %s\n", device, 8300 strerror(status)); 8301 } 8302 } 8303 8304 return B_OK; 8305 } 8306 8307 8308 dev_t 8309 _kern_next_device(int32* _cookie) 8310 { 8311 return fs_next_device(_cookie); 8312 } 8313 8314 8315 status_t 8316 _kern_get_next_fd_info(team_id teamID, uint32* _cookie, fd_info* info, 8317 size_t infoSize) 8318 { 8319 if (infoSize != sizeof(fd_info)) 8320 return B_BAD_VALUE; 8321 8322 // get the team 8323 Team* team = Team::Get(teamID); 8324 if (team == NULL) 8325 return B_BAD_TEAM_ID; 8326 BReference<Team> teamReference(team, true); 8327 8328 // now that we have a team reference, its I/O context won't go away 8329 io_context* context = team->io_context; 8330 MutexLocker contextLocker(context->io_mutex); 8331 8332 uint32 slot = *_cookie; 8333 8334 struct file_descriptor* descriptor; 8335 while (slot < context->table_size 8336 && (descriptor = context->fds[slot]) == NULL) { 8337 slot++; 8338 } 8339 8340 if (slot >= context->table_size) 8341 return B_ENTRY_NOT_FOUND; 8342 8343 info->number = slot; 8344 info->open_mode = descriptor->open_mode; 8345 8346 struct vnode* vnode = fd_vnode(descriptor); 8347 if (vnode != NULL) { 8348 info->device = vnode->device; 8349 info->node = vnode->id; 8350 } else if (descriptor->u.mount != NULL) { 8351 info->device = descriptor->u.mount->id; 8352 info->node = -1; 8353 } 8354 8355 *_cookie = slot + 1; 8356 return B_OK; 8357 } 8358 8359 8360 int 8361 _kern_open_entry_ref(dev_t device, ino_t inode, const char* name, int openMode, 8362 int perms) 8363 { 8364 if ((openMode & O_CREAT) != 0) { 8365 return file_create_entry_ref(device, inode, name, openMode, perms, 8366 true); 8367 } 8368 8369 return file_open_entry_ref(device, inode, name, openMode, true); 8370 } 8371 8372 8373 /*! \brief Opens a node specified by a FD + path pair. 8374 8375 At least one of \a fd and \a path must be specified. 8376 If only \a fd is given, the function opens the node identified by this 8377 FD. If only a path is given, this path is opened. If both are given and 8378 the path is absolute, \a fd is ignored; a relative path is reckoned off 8379 of the directory (!) identified by \a fd. 8380 8381 \param fd The FD. May be < 0. 8382 \param path The absolute or relative path. May be \c NULL. 8383 \param openMode The open mode. 8384 \return A FD referring to the newly opened node, or an error code, 8385 if an error occurs. 8386 */ 8387 int 8388 _kern_open(int fd, const char* path, int openMode, int perms) 8389 { 8390 KPath pathBuffer(path, KPath::LAZY_ALLOC); 8391 if (pathBuffer.InitCheck() != B_OK) 8392 return B_NO_MEMORY; 8393 8394 if ((openMode & O_CREAT) != 0) 8395 return file_create(fd, pathBuffer.LockBuffer(), openMode, perms, true); 8396 8397 return file_open(fd, pathBuffer.LockBuffer(), openMode, true); 8398 } 8399 8400 8401 /*! \brief Opens a directory specified by entry_ref or node_ref. 8402 8403 The supplied name may be \c NULL, in which case directory identified 8404 by \a device and \a inode will be opened. Otherwise \a device and 8405 \a inode identify the parent directory of the directory to be opened 8406 and \a name its entry name. 8407 8408 \param device If \a name is specified the ID of the device the parent 8409 directory of the directory to be opened resides on, otherwise 8410 the device of the directory itself. 8411 \param inode If \a name is specified the node ID of the parent 8412 directory of the directory to be opened, otherwise node ID of the 8413 directory itself. 8414 \param name The entry name of the directory to be opened. If \c NULL, 8415 the \a device + \a inode pair identify the node to be opened. 8416 \return The FD of the newly opened directory or an error code, if 8417 something went wrong. 8418 */ 8419 int 8420 _kern_open_dir_entry_ref(dev_t device, ino_t inode, const char* name) 8421 { 8422 return dir_open_entry_ref(device, inode, name, true); 8423 } 8424 8425 8426 /*! \brief Opens a directory specified by a FD + path pair. 8427 8428 At least one of \a fd and \a path must be specified. 8429 If only \a fd is given, the function opens the directory identified by this 8430 FD. If only a path is given, this path is opened. If both are given and 8431 the path is absolute, \a fd is ignored; a relative path is reckoned off 8432 of the directory (!) identified by \a fd. 8433 8434 \param fd The FD. May be < 0. 8435 \param path The absolute or relative path. May be \c NULL. 8436 \return A FD referring to the newly opened directory, or an error code, 8437 if an error occurs. 8438 */ 8439 int 8440 _kern_open_dir(int fd, const char* path) 8441 { 8442 KPath pathBuffer(path, KPath::LAZY_ALLOC); 8443 if (pathBuffer.InitCheck() != B_OK) 8444 return B_NO_MEMORY; 8445 8446 return dir_open(fd, pathBuffer.LockBuffer(), true); 8447 } 8448 8449 8450 status_t 8451 _kern_fcntl(int fd, int op, size_t argument) 8452 { 8453 return common_fcntl(fd, op, argument, true); 8454 } 8455 8456 8457 status_t 8458 _kern_fsync(int fd) 8459 { 8460 return common_sync(fd, true); 8461 } 8462 8463 8464 status_t 8465 _kern_lock_node(int fd) 8466 { 8467 return common_lock_node(fd, true); 8468 } 8469 8470 8471 status_t 8472 _kern_unlock_node(int fd) 8473 { 8474 return common_unlock_node(fd, true); 8475 } 8476 8477 8478 status_t 8479 _kern_preallocate(int fd, off_t offset, off_t length) 8480 { 8481 return common_preallocate(fd, offset, length, true); 8482 } 8483 8484 8485 status_t 8486 _kern_create_dir_entry_ref(dev_t device, ino_t inode, const char* name, 8487 int perms) 8488 { 8489 return dir_create_entry_ref(device, inode, name, perms, true); 8490 } 8491 8492 8493 /*! \brief Creates a directory specified by a FD + path pair. 8494 8495 \a path must always be specified (it contains the name of the new directory 8496 at least). If only a path is given, this path identifies the location at 8497 which the directory shall be created. If both \a fd and \a path are given 8498 and the path is absolute, \a fd is ignored; a relative path is reckoned off 8499 of the directory (!) identified by \a fd. 8500 8501 \param fd The FD. May be < 0. 8502 \param path The absolute or relative path. Must not be \c NULL. 8503 \param perms The access permissions the new directory shall have. 8504 \return \c B_OK, if the directory has been created successfully, another 8505 error code otherwise. 8506 */ 8507 status_t 8508 _kern_create_dir(int fd, const char* path, int perms) 8509 { 8510 KPath pathBuffer(path, KPath::DEFAULT); 8511 if (pathBuffer.InitCheck() != B_OK) 8512 return B_NO_MEMORY; 8513 8514 return dir_create(fd, pathBuffer.LockBuffer(), perms, true); 8515 } 8516 8517 8518 status_t 8519 _kern_remove_dir(int fd, const char* path) 8520 { 8521 KPath pathBuffer(path, KPath::LAZY_ALLOC); 8522 if (pathBuffer.InitCheck() != B_OK) 8523 return B_NO_MEMORY; 8524 8525 return dir_remove(fd, pathBuffer.LockBuffer(), true); 8526 } 8527 8528 8529 /*! \brief Reads the contents of a symlink referred to by a FD + path pair. 8530 8531 At least one of \a fd and \a path must be specified. 8532 If only \a fd is given, the function the symlink to be read is the node 8533 identified by this FD. If only a path is given, this path identifies the 8534 symlink to be read. If both are given and the path is absolute, \a fd is 8535 ignored; a relative path is reckoned off of the directory (!) identified 8536 by \a fd. 8537 If this function fails with B_BUFFER_OVERFLOW, the \a _bufferSize pointer 8538 will still be updated to reflect the required buffer size. 8539 8540 \param fd The FD. May be < 0. 8541 \param path The absolute or relative path. May be \c NULL. 8542 \param buffer The buffer into which the contents of the symlink shall be 8543 written. 8544 \param _bufferSize A pointer to the size of the supplied buffer. 8545 \return The length of the link on success or an appropriate error code 8546 */ 8547 status_t 8548 _kern_read_link(int fd, const char* path, char* buffer, size_t* _bufferSize) 8549 { 8550 KPath pathBuffer(path, KPath::LAZY_ALLOC); 8551 if (pathBuffer.InitCheck() != B_OK) 8552 return B_NO_MEMORY; 8553 8554 return common_read_link(fd, pathBuffer.LockBuffer(), 8555 buffer, _bufferSize, true); 8556 } 8557 8558 8559 /*! \brief Creates a symlink specified by a FD + path pair. 8560 8561 \a path must always be specified (it contains the name of the new symlink 8562 at least). If only a path is given, this path identifies the location at 8563 which the symlink shall be created. If both \a fd and \a path are given and 8564 the path is absolute, \a fd is ignored; a relative path is reckoned off 8565 of the directory (!) identified by \a fd. 8566 8567 \param fd The FD. May be < 0. 8568 \param toPath The absolute or relative path. Must not be \c NULL. 8569 \param mode The access permissions the new symlink shall have. 8570 \return \c B_OK, if the symlink has been created successfully, another 8571 error code otherwise. 8572 */ 8573 status_t 8574 _kern_create_symlink(int fd, const char* path, const char* toPath, int mode) 8575 { 8576 KPath pathBuffer(path); 8577 if (pathBuffer.InitCheck() != B_OK) 8578 return B_NO_MEMORY; 8579 8580 return common_create_symlink(fd, pathBuffer.LockBuffer(), 8581 toPath, mode, true); 8582 } 8583 8584 8585 status_t 8586 _kern_create_link(int pathFD, const char* path, int toFD, const char* toPath, 8587 bool traverseLeafLink) 8588 { 8589 KPath pathBuffer(path); 8590 KPath toPathBuffer(toPath); 8591 if (pathBuffer.InitCheck() != B_OK || toPathBuffer.InitCheck() != B_OK) 8592 return B_NO_MEMORY; 8593 8594 return common_create_link(pathFD, pathBuffer.LockBuffer(), toFD, 8595 toPathBuffer.LockBuffer(), traverseLeafLink, true); 8596 } 8597 8598 8599 /*! \brief Removes an entry specified by a FD + path pair from its directory. 8600 8601 \a path must always be specified (it contains at least the name of the entry 8602 to be deleted). If only a path is given, this path identifies the entry 8603 directly. If both \a fd and \a path are given and the path is absolute, 8604 \a fd is ignored; a relative path is reckoned off of the directory (!) 8605 identified by \a fd. 8606 8607 \param fd The FD. May be < 0. 8608 \param path The absolute or relative path. Must not be \c NULL. 8609 \return \c B_OK, if the entry has been removed successfully, another 8610 error code otherwise. 8611 */ 8612 status_t 8613 _kern_unlink(int fd, const char* path) 8614 { 8615 KPath pathBuffer(path); 8616 if (pathBuffer.InitCheck() != B_OK) 8617 return B_NO_MEMORY; 8618 8619 return common_unlink(fd, pathBuffer.LockBuffer(), true); 8620 } 8621 8622 8623 /*! \brief Moves an entry specified by a FD + path pair to a an entry specified 8624 by another FD + path pair. 8625 8626 \a oldPath and \a newPath must always be specified (they contain at least 8627 the name of the entry). If only a path is given, this path identifies the 8628 entry directly. If both a FD and a path are given and the path is absolute, 8629 the FD is ignored; a relative path is reckoned off of the directory (!) 8630 identified by the respective FD. 8631 8632 \param oldFD The FD of the old location. May be < 0. 8633 \param oldPath The absolute or relative path of the old location. Must not 8634 be \c NULL. 8635 \param newFD The FD of the new location. May be < 0. 8636 \param newPath The absolute or relative path of the new location. Must not 8637 be \c NULL. 8638 \return \c B_OK, if the entry has been moved successfully, another 8639 error code otherwise. 8640 */ 8641 status_t 8642 _kern_rename(int oldFD, const char* oldPath, int newFD, const char* newPath) 8643 { 8644 KPath oldPathBuffer(oldPath); 8645 KPath newPathBuffer(newPath); 8646 if (oldPathBuffer.InitCheck() != B_OK || newPathBuffer.InitCheck() != B_OK) 8647 return B_NO_MEMORY; 8648 8649 return common_rename(oldFD, oldPathBuffer.LockBuffer(), 8650 newFD, newPathBuffer.LockBuffer(), true); 8651 } 8652 8653 8654 status_t 8655 _kern_access(int fd, const char* path, int mode, bool effectiveUserGroup) 8656 { 8657 KPath pathBuffer(path, KPath::LAZY_ALLOC); 8658 if (pathBuffer.InitCheck() != B_OK) 8659 return B_NO_MEMORY; 8660 8661 return common_access(fd, pathBuffer.LockBuffer(), mode, effectiveUserGroup, 8662 true); 8663 } 8664 8665 8666 /*! \brief Reads stat data of an entity specified by a FD + path pair. 8667 8668 If only \a fd is given, the stat operation associated with the type 8669 of the FD (node, attr, attr dir etc.) is performed. If only \a path is 8670 given, this path identifies the entry for whose node to retrieve the 8671 stat data. If both \a fd and \a path are given and the path is absolute, 8672 \a fd is ignored; a relative path is reckoned off of the directory (!) 8673 identified by \a fd and specifies the entry whose stat data shall be 8674 retrieved. 8675 8676 \param fd The FD. May be < 0. 8677 \param path The absolute or relative path. Must not be \c NULL. 8678 \param traverseLeafLink If \a path is given, \c true specifies that the 8679 function shall not stick to symlinks, but traverse them. 8680 \param stat The buffer the stat data shall be written into. 8681 \param statSize The size of the supplied stat buffer. 8682 \return \c B_OK, if the the stat data have been read successfully, another 8683 error code otherwise. 8684 */ 8685 status_t 8686 _kern_read_stat(int fd, const char* path, bool traverseLeafLink, 8687 struct stat* stat, size_t statSize) 8688 { 8689 struct stat completeStat; 8690 struct stat* originalStat = NULL; 8691 status_t status; 8692 8693 if (statSize > sizeof(struct stat)) 8694 return B_BAD_VALUE; 8695 8696 // this supports different stat extensions 8697 if (statSize < sizeof(struct stat)) { 8698 originalStat = stat; 8699 stat = &completeStat; 8700 } 8701 8702 status = vfs_read_stat(fd, path, traverseLeafLink, stat, true); 8703 8704 if (status == B_OK && originalStat != NULL) 8705 memcpy(originalStat, stat, statSize); 8706 8707 return status; 8708 } 8709 8710 8711 /*! \brief Writes stat data of an entity specified by a FD + path pair. 8712 8713 If only \a fd is given, the stat operation associated with the type 8714 of the FD (node, attr, attr dir etc.) is performed. If only \a path is 8715 given, this path identifies the entry for whose node to write the 8716 stat data. If both \a fd and \a path are given and the path is absolute, 8717 \a fd is ignored; a relative path is reckoned off of the directory (!) 8718 identified by \a fd and specifies the entry whose stat data shall be 8719 written. 8720 8721 \param fd The FD. May be < 0. 8722 \param path The absolute or relative path. May be \c NULL. 8723 \param traverseLeafLink If \a path is given, \c true specifies that the 8724 function shall not stick to symlinks, but traverse them. 8725 \param stat The buffer containing the stat data to be written. 8726 \param statSize The size of the supplied stat buffer. 8727 \param statMask A mask specifying which parts of the stat data shall be 8728 written. 8729 \return \c B_OK, if the the stat data have been written successfully, 8730 another error code otherwise. 8731 */ 8732 status_t 8733 _kern_write_stat(int fd, const char* path, bool traverseLeafLink, 8734 const struct stat* stat, size_t statSize, int statMask) 8735 { 8736 struct stat completeStat; 8737 8738 if (statSize > sizeof(struct stat)) 8739 return B_BAD_VALUE; 8740 8741 // this supports different stat extensions 8742 if (statSize < sizeof(struct stat)) { 8743 memset((uint8*)&completeStat + statSize, 0, 8744 sizeof(struct stat) - statSize); 8745 memcpy(&completeStat, stat, statSize); 8746 stat = &completeStat; 8747 } 8748 8749 status_t status; 8750 8751 if (path != NULL) { 8752 // path given: write the stat of the node referred to by (fd, path) 8753 KPath pathBuffer(path); 8754 if (pathBuffer.InitCheck() != B_OK) 8755 return B_NO_MEMORY; 8756 8757 status = common_path_write_stat(fd, pathBuffer.LockBuffer(), 8758 traverseLeafLink, stat, statMask, true); 8759 } else { 8760 // no path given: get the FD and use the FD operation 8761 struct file_descriptor* descriptor 8762 = get_fd(get_current_io_context(true), fd); 8763 if (descriptor == NULL) 8764 return B_FILE_ERROR; 8765 8766 if (descriptor->ops->fd_write_stat) 8767 status = descriptor->ops->fd_write_stat(descriptor, stat, statMask); 8768 else 8769 status = B_UNSUPPORTED; 8770 8771 put_fd(descriptor); 8772 } 8773 8774 return status; 8775 } 8776 8777 8778 int 8779 _kern_open_attr_dir(int fd, const char* path, bool traverseLeafLink) 8780 { 8781 KPath pathBuffer(path, KPath::LAZY_ALLOC); 8782 if (pathBuffer.InitCheck() != B_OK) 8783 return B_NO_MEMORY; 8784 8785 return attr_dir_open(fd, pathBuffer.LockBuffer(), traverseLeafLink, true); 8786 } 8787 8788 8789 int 8790 _kern_open_attr(int fd, const char* path, const char* name, uint32 type, 8791 int openMode) 8792 { 8793 KPath pathBuffer(path, KPath::LAZY_ALLOC); 8794 if (pathBuffer.InitCheck() != B_OK) 8795 return B_NO_MEMORY; 8796 8797 if ((openMode & O_CREAT) != 0) { 8798 return attr_create(fd, pathBuffer.LockBuffer(), name, type, openMode, 8799 true); 8800 } 8801 8802 return attr_open(fd, pathBuffer.LockBuffer(), name, openMode, true); 8803 } 8804 8805 8806 status_t 8807 _kern_remove_attr(int fd, const char* name) 8808 { 8809 return attr_remove(fd, name, true); 8810 } 8811 8812 8813 status_t 8814 _kern_rename_attr(int fromFile, const char* fromName, int toFile, 8815 const char* toName) 8816 { 8817 return attr_rename(fromFile, fromName, toFile, toName, true); 8818 } 8819 8820 8821 int 8822 _kern_open_index_dir(dev_t device) 8823 { 8824 return index_dir_open(device, true); 8825 } 8826 8827 8828 status_t 8829 _kern_create_index(dev_t device, const char* name, uint32 type, uint32 flags) 8830 { 8831 return index_create(device, name, type, flags, true); 8832 } 8833 8834 8835 status_t 8836 _kern_read_index_stat(dev_t device, const char* name, struct stat* stat) 8837 { 8838 return index_name_read_stat(device, name, stat, true); 8839 } 8840 8841 8842 status_t 8843 _kern_remove_index(dev_t device, const char* name) 8844 { 8845 return index_remove(device, name, true); 8846 } 8847 8848 8849 status_t 8850 _kern_getcwd(char* buffer, size_t size) 8851 { 8852 TRACE(("_kern_getcwd: buf %p, %ld\n", buffer, size)); 8853 8854 // Call vfs to get current working directory 8855 return get_cwd(buffer, size, true); 8856 } 8857 8858 8859 status_t 8860 _kern_setcwd(int fd, const char* path) 8861 { 8862 KPath pathBuffer(path, KPath::LAZY_ALLOC); 8863 if (pathBuffer.InitCheck() != B_OK) 8864 return B_NO_MEMORY; 8865 8866 return set_cwd(fd, pathBuffer.LockBuffer(), true); 8867 } 8868 8869 8870 // #pragma mark - userland syscalls 8871 8872 8873 dev_t 8874 _user_mount(const char* userPath, const char* userDevice, 8875 const char* userFileSystem, uint32 flags, const char* userArgs, 8876 size_t argsLength) 8877 { 8878 char fileSystem[B_FILE_NAME_LENGTH]; 8879 KPath path, device; 8880 char* args = NULL; 8881 status_t status; 8882 8883 if (!IS_USER_ADDRESS(userPath)) 8884 return B_BAD_ADDRESS; 8885 8886 if (path.InitCheck() != B_OK || device.InitCheck() != B_OK) 8887 return B_NO_MEMORY; 8888 8889 status = user_copy_name(path.LockBuffer(), userPath, 8890 B_PATH_NAME_LENGTH); 8891 if (status != B_OK) 8892 return status; 8893 path.UnlockBuffer(); 8894 8895 if (userFileSystem != NULL) { 8896 if (!IS_USER_ADDRESS(userFileSystem)) 8897 return B_BAD_ADDRESS; 8898 8899 status = user_copy_name(fileSystem, userFileSystem, sizeof(fileSystem)); 8900 if (status != B_OK) 8901 return status; 8902 } 8903 8904 if (userDevice != NULL) { 8905 if (!IS_USER_ADDRESS(userDevice)) 8906 return B_BAD_ADDRESS; 8907 8908 status = user_copy_name(device.LockBuffer(), userDevice, 8909 B_PATH_NAME_LENGTH); 8910 if (status != B_OK) 8911 return status; 8912 device.UnlockBuffer(); 8913 } 8914 8915 if (userArgs != NULL && argsLength > 0) { 8916 if (!IS_USER_ADDRESS(userArgs)) 8917 return B_BAD_ADDRESS; 8918 8919 // this is a safety restriction 8920 if (argsLength >= 65536) 8921 return B_NAME_TOO_LONG; 8922 8923 args = (char*)malloc(argsLength + 1); 8924 if (args == NULL) 8925 return B_NO_MEMORY; 8926 8927 status = user_copy_name(args, userArgs, argsLength + 1); 8928 if (status != B_OK) { 8929 free(args); 8930 return status; 8931 } 8932 } 8933 8934 status = fs_mount(path.LockBuffer(), 8935 userDevice != NULL ? device.Path() : NULL, 8936 userFileSystem ? fileSystem : NULL, flags, args, false); 8937 8938 free(args); 8939 return status; 8940 } 8941 8942 8943 status_t 8944 _user_unmount(const char* userPath, uint32 flags) 8945 { 8946 if (!IS_USER_ADDRESS(userPath)) 8947 return B_BAD_ADDRESS; 8948 8949 KPath pathBuffer; 8950 if (pathBuffer.InitCheck() != B_OK) 8951 return B_NO_MEMORY; 8952 8953 char* path = pathBuffer.LockBuffer(); 8954 8955 status_t status = user_copy_name(path, userPath, B_PATH_NAME_LENGTH); 8956 if (status != B_OK) 8957 return status; 8958 8959 return fs_unmount(path, -1, flags & ~B_UNMOUNT_BUSY_PARTITION, false); 8960 } 8961 8962 8963 status_t 8964 _user_read_fs_info(dev_t device, struct fs_info* userInfo) 8965 { 8966 struct fs_info info; 8967 status_t status; 8968 8969 if (userInfo == NULL) 8970 return B_BAD_VALUE; 8971 8972 if (!IS_USER_ADDRESS(userInfo)) 8973 return B_BAD_ADDRESS; 8974 8975 status = fs_read_info(device, &info); 8976 if (status != B_OK) 8977 return status; 8978 8979 if (user_memcpy(userInfo, &info, sizeof(struct fs_info)) != B_OK) 8980 return B_BAD_ADDRESS; 8981 8982 return B_OK; 8983 } 8984 8985 8986 status_t 8987 _user_write_fs_info(dev_t device, const struct fs_info* userInfo, int mask) 8988 { 8989 struct fs_info info; 8990 8991 if (userInfo == NULL) 8992 return B_BAD_VALUE; 8993 8994 if (!IS_USER_ADDRESS(userInfo) 8995 || user_memcpy(&info, userInfo, sizeof(struct fs_info)) != B_OK) 8996 return B_BAD_ADDRESS; 8997 8998 return fs_write_info(device, &info, mask); 8999 } 9000 9001 9002 dev_t 9003 _user_next_device(int32* _userCookie) 9004 { 9005 int32 cookie; 9006 dev_t device; 9007 9008 if (!IS_USER_ADDRESS(_userCookie) 9009 || user_memcpy(&cookie, _userCookie, sizeof(int32)) != B_OK) 9010 return B_BAD_ADDRESS; 9011 9012 device = fs_next_device(&cookie); 9013 9014 if (device >= B_OK) { 9015 // update user cookie 9016 if (user_memcpy(_userCookie, &cookie, sizeof(int32)) != B_OK) 9017 return B_BAD_ADDRESS; 9018 } 9019 9020 return device; 9021 } 9022 9023 9024 status_t 9025 _user_sync(void) 9026 { 9027 return _kern_sync(); 9028 } 9029 9030 9031 status_t 9032 _user_get_next_fd_info(team_id team, uint32* userCookie, fd_info* userInfo, 9033 size_t infoSize) 9034 { 9035 struct fd_info info; 9036 uint32 cookie; 9037 9038 // only root can do this 9039 if (geteuid() != 0) 9040 return B_NOT_ALLOWED; 9041 9042 if (infoSize != sizeof(fd_info)) 9043 return B_BAD_VALUE; 9044 9045 if (!IS_USER_ADDRESS(userCookie) || !IS_USER_ADDRESS(userInfo) 9046 || user_memcpy(&cookie, userCookie, sizeof(uint32)) != B_OK) 9047 return B_BAD_ADDRESS; 9048 9049 status_t status = _kern_get_next_fd_info(team, &cookie, &info, infoSize); 9050 if (status != B_OK) 9051 return status; 9052 9053 if (user_memcpy(userCookie, &cookie, sizeof(uint32)) != B_OK 9054 || user_memcpy(userInfo, &info, infoSize) != B_OK) 9055 return B_BAD_ADDRESS; 9056 9057 return status; 9058 } 9059 9060 9061 status_t 9062 _user_entry_ref_to_path(dev_t device, ino_t inode, const char* leaf, 9063 char* userPath, size_t pathLength) 9064 { 9065 if (!IS_USER_ADDRESS(userPath)) 9066 return B_BAD_ADDRESS; 9067 9068 KPath path; 9069 if (path.InitCheck() != B_OK) 9070 return B_NO_MEMORY; 9071 9072 // copy the leaf name onto the stack 9073 char stackLeaf[B_FILE_NAME_LENGTH]; 9074 if (leaf != NULL) { 9075 if (!IS_USER_ADDRESS(leaf)) 9076 return B_BAD_ADDRESS; 9077 9078 int status = user_copy_name(stackLeaf, leaf, B_FILE_NAME_LENGTH); 9079 if (status != B_OK) 9080 return status; 9081 9082 leaf = stackLeaf; 9083 } 9084 9085 status_t status = vfs_entry_ref_to_path(device, inode, leaf, 9086 false, path.LockBuffer(), path.BufferSize()); 9087 if (status != B_OK) 9088 return status; 9089 9090 path.UnlockBuffer(); 9091 9092 int length = user_strlcpy(userPath, path.Path(), pathLength); 9093 if (length < 0) 9094 return length; 9095 if (length >= (int)pathLength) 9096 return B_BUFFER_OVERFLOW; 9097 9098 return B_OK; 9099 } 9100 9101 9102 status_t 9103 _user_normalize_path(const char* userPath, bool traverseLink, char* buffer) 9104 { 9105 if (userPath == NULL || buffer == NULL) 9106 return B_BAD_VALUE; 9107 if (!IS_USER_ADDRESS(userPath) || !IS_USER_ADDRESS(buffer)) 9108 return B_BAD_ADDRESS; 9109 9110 // copy path from userland 9111 KPath pathBuffer; 9112 if (pathBuffer.InitCheck() != B_OK) 9113 return B_NO_MEMORY; 9114 char* path = pathBuffer.LockBuffer(); 9115 9116 status_t status = user_copy_name(path, userPath, B_PATH_NAME_LENGTH); 9117 if (status != B_OK) 9118 return status; 9119 9120 status_t error = normalize_path(path, pathBuffer.BufferSize(), traverseLink, 9121 false); 9122 if (error != B_OK) 9123 return error; 9124 9125 // copy back to userland 9126 int len = user_strlcpy(buffer, path, B_PATH_NAME_LENGTH); 9127 if (len < 0) 9128 return len; 9129 if (len >= B_PATH_NAME_LENGTH) 9130 return B_BUFFER_OVERFLOW; 9131 9132 return B_OK; 9133 } 9134 9135 9136 int 9137 _user_open_entry_ref(dev_t device, ino_t inode, const char* userName, 9138 int openMode, int perms) 9139 { 9140 char name[B_FILE_NAME_LENGTH]; 9141 9142 if (userName == NULL || device < 0 || inode < 0) 9143 return B_BAD_VALUE; 9144 if (!IS_USER_ADDRESS(userName)) 9145 return B_BAD_ADDRESS; 9146 status_t status = user_copy_name(name, userName, sizeof(name)); 9147 if (status != B_OK) 9148 return status; 9149 9150 if ((openMode & O_CREAT) != 0) { 9151 return file_create_entry_ref(device, inode, name, openMode, perms, 9152 false); 9153 } 9154 9155 return file_open_entry_ref(device, inode, name, openMode, false); 9156 } 9157 9158 9159 int 9160 _user_open(int fd, const char* userPath, int openMode, int perms) 9161 { 9162 KPath path; 9163 if (path.InitCheck() != B_OK) 9164 return B_NO_MEMORY; 9165 9166 char* buffer = path.LockBuffer(); 9167 9168 if (!IS_USER_ADDRESS(userPath)) 9169 return B_BAD_ADDRESS; 9170 status_t status = user_copy_name(buffer, userPath, B_PATH_NAME_LENGTH); 9171 if (status != B_OK) 9172 return status; 9173 9174 if ((openMode & O_CREAT) != 0) 9175 return file_create(fd, buffer, openMode, perms, false); 9176 9177 return file_open(fd, buffer, openMode, false); 9178 } 9179 9180 9181 int 9182 _user_open_dir_entry_ref(dev_t device, ino_t inode, const char* userName) 9183 { 9184 if (userName != NULL) { 9185 char name[B_FILE_NAME_LENGTH]; 9186 9187 if (!IS_USER_ADDRESS(userName)) 9188 return B_BAD_ADDRESS; 9189 status_t status = user_copy_name(name, userName, sizeof(name)); 9190 if (status != B_OK) 9191 return status; 9192 9193 return dir_open_entry_ref(device, inode, name, false); 9194 } 9195 return dir_open_entry_ref(device, inode, NULL, false); 9196 } 9197 9198 9199 int 9200 _user_open_dir(int fd, const char* userPath) 9201 { 9202 if (userPath == NULL) 9203 return dir_open(fd, NULL, false); 9204 9205 KPath path; 9206 if (path.InitCheck() != B_OK) 9207 return B_NO_MEMORY; 9208 9209 char* buffer = path.LockBuffer(); 9210 9211 if (!IS_USER_ADDRESS(userPath)) 9212 return B_BAD_ADDRESS; 9213 status_t status = user_copy_name(buffer, userPath, B_PATH_NAME_LENGTH); 9214 if (status != B_OK) 9215 return status; 9216 9217 return dir_open(fd, buffer, false); 9218 } 9219 9220 9221 /*! \brief Opens a directory's parent directory and returns the entry name 9222 of the former. 9223 9224 Aside from that it returns the directory's entry name, this method is 9225 equivalent to \code _user_open_dir(fd, "..") \endcode. It really is 9226 equivalent, if \a userName is \c NULL. 9227 9228 If a name buffer is supplied and the name does not fit the buffer, the 9229 function fails. A buffer of size \c B_FILE_NAME_LENGTH should be safe. 9230 9231 \param fd A FD referring to a directory. 9232 \param userName Buffer the directory's entry name shall be written into. 9233 May be \c NULL. 9234 \param nameLength Size of the name buffer. 9235 \return The file descriptor of the opened parent directory, if everything 9236 went fine, an error code otherwise. 9237 */ 9238 int 9239 _user_open_parent_dir(int fd, char* userName, size_t nameLength) 9240 { 9241 bool kernel = false; 9242 9243 if (userName && !IS_USER_ADDRESS(userName)) 9244 return B_BAD_ADDRESS; 9245 9246 // open the parent dir 9247 int parentFD = dir_open(fd, (char*)"..", kernel); 9248 if (parentFD < 0) 9249 return parentFD; 9250 FDCloser fdCloser(parentFD, kernel); 9251 9252 if (userName) { 9253 // get the vnodes 9254 struct vnode* parentVNode = get_vnode_from_fd(parentFD, kernel); 9255 struct vnode* dirVNode = get_vnode_from_fd(fd, kernel); 9256 VNodePutter parentVNodePutter(parentVNode); 9257 VNodePutter dirVNodePutter(dirVNode); 9258 if (!parentVNode || !dirVNode) 9259 return B_FILE_ERROR; 9260 9261 // get the vnode name 9262 char _buffer[offsetof(struct dirent, d_name) + B_FILE_NAME_LENGTH + 1]; 9263 struct dirent* buffer = (struct dirent*)_buffer; 9264 status_t status = get_vnode_name(dirVNode, parentVNode, buffer, 9265 sizeof(_buffer), get_current_io_context(false)); 9266 if (status != B_OK) 9267 return status; 9268 9269 // copy the name to the userland buffer 9270 int len = user_strlcpy(userName, buffer->d_name, nameLength); 9271 if (len < 0) 9272 return len; 9273 if (len >= (int)nameLength) 9274 return B_BUFFER_OVERFLOW; 9275 } 9276 9277 return fdCloser.Detach(); 9278 } 9279 9280 9281 status_t 9282 _user_fcntl(int fd, int op, size_t argument) 9283 { 9284 status_t status = common_fcntl(fd, op, argument, false); 9285 if (op == F_SETLKW) 9286 syscall_restart_handle_post(status); 9287 9288 return status; 9289 } 9290 9291 9292 status_t 9293 _user_fsync(int fd) 9294 { 9295 return common_sync(fd, false); 9296 } 9297 9298 9299 status_t 9300 _user_flock(int fd, int operation) 9301 { 9302 FUNCTION(("_user_fcntl(fd = %d, op = %d)\n", fd, operation)); 9303 9304 // Check if the operation is valid 9305 switch (operation & ~LOCK_NB) { 9306 case LOCK_UN: 9307 case LOCK_SH: 9308 case LOCK_EX: 9309 break; 9310 9311 default: 9312 return B_BAD_VALUE; 9313 } 9314 9315 struct file_descriptor* descriptor; 9316 struct vnode* vnode; 9317 descriptor = get_fd_and_vnode(fd, &vnode, false); 9318 if (descriptor == NULL) 9319 return B_FILE_ERROR; 9320 9321 if (descriptor->type != FDTYPE_FILE) { 9322 put_fd(descriptor); 9323 return B_BAD_VALUE; 9324 } 9325 9326 struct flock flock; 9327 flock.l_start = 0; 9328 flock.l_len = OFF_MAX; 9329 flock.l_whence = 0; 9330 flock.l_type = (operation & LOCK_SH) != 0 ? F_RDLCK : F_WRLCK; 9331 9332 status_t status; 9333 if ((operation & LOCK_UN) != 0) { 9334 if (HAS_FS_CALL(vnode, release_lock)) 9335 status = FS_CALL(vnode, release_lock, descriptor->cookie, &flock); 9336 else 9337 status = release_advisory_lock(vnode, NULL, descriptor, &flock); 9338 } else { 9339 if (HAS_FS_CALL(vnode, acquire_lock)) { 9340 status = FS_CALL(vnode, acquire_lock, descriptor->cookie, &flock, 9341 (operation & LOCK_NB) == 0); 9342 } else { 9343 status = acquire_advisory_lock(vnode, NULL, descriptor, &flock, 9344 (operation & LOCK_NB) == 0); 9345 } 9346 } 9347 9348 syscall_restart_handle_post(status); 9349 9350 put_fd(descriptor); 9351 return status; 9352 } 9353 9354 9355 status_t 9356 _user_lock_node(int fd) 9357 { 9358 return common_lock_node(fd, false); 9359 } 9360 9361 9362 status_t 9363 _user_unlock_node(int fd) 9364 { 9365 return common_unlock_node(fd, false); 9366 } 9367 9368 9369 status_t 9370 _user_preallocate(int fd, off_t offset, off_t length) 9371 { 9372 return common_preallocate(fd, offset, length, false); 9373 } 9374 9375 9376 status_t 9377 _user_create_dir_entry_ref(dev_t device, ino_t inode, const char* userName, 9378 int perms) 9379 { 9380 char name[B_FILE_NAME_LENGTH]; 9381 status_t status; 9382 9383 if (!IS_USER_ADDRESS(userName)) 9384 return B_BAD_ADDRESS; 9385 9386 status = user_copy_name(name, userName, sizeof(name)); 9387 if (status != B_OK) 9388 return status; 9389 9390 return dir_create_entry_ref(device, inode, name, perms, false); 9391 } 9392 9393 9394 status_t 9395 _user_create_dir(int fd, const char* userPath, int perms) 9396 { 9397 KPath pathBuffer; 9398 if (pathBuffer.InitCheck() != B_OK) 9399 return B_NO_MEMORY; 9400 9401 char* path = pathBuffer.LockBuffer(); 9402 9403 if (!IS_USER_ADDRESS(userPath)) 9404 return B_BAD_ADDRESS; 9405 status_t status = user_copy_name(path, userPath, B_PATH_NAME_LENGTH); 9406 if (status != B_OK) 9407 return status; 9408 9409 return dir_create(fd, path, perms, false); 9410 } 9411 9412 9413 status_t 9414 _user_remove_dir(int fd, const char* userPath) 9415 { 9416 KPath pathBuffer; 9417 if (pathBuffer.InitCheck() != B_OK) 9418 return B_NO_MEMORY; 9419 9420 char* path = pathBuffer.LockBuffer(); 9421 9422 if (userPath != NULL) { 9423 if (!IS_USER_ADDRESS(userPath)) 9424 return B_BAD_ADDRESS; 9425 status_t status = user_copy_name(path, userPath, B_PATH_NAME_LENGTH); 9426 if (status != B_OK) 9427 return status; 9428 } 9429 9430 return dir_remove(fd, userPath ? path : NULL, false); 9431 } 9432 9433 9434 status_t 9435 _user_read_link(int fd, const char* userPath, char* userBuffer, 9436 size_t* userBufferSize) 9437 { 9438 KPath pathBuffer, linkBuffer; 9439 if (pathBuffer.InitCheck() != B_OK || linkBuffer.InitCheck() != B_OK) 9440 return B_NO_MEMORY; 9441 9442 size_t bufferSize; 9443 9444 if (!IS_USER_ADDRESS(userBuffer) || !IS_USER_ADDRESS(userBufferSize) 9445 || user_memcpy(&bufferSize, userBufferSize, sizeof(size_t)) != B_OK) 9446 return B_BAD_ADDRESS; 9447 9448 char* path = pathBuffer.LockBuffer(); 9449 char* buffer = linkBuffer.LockBuffer(); 9450 9451 if (userPath) { 9452 if (!IS_USER_ADDRESS(userPath)) 9453 return B_BAD_ADDRESS; 9454 status_t status = user_copy_name(path, userPath, B_PATH_NAME_LENGTH); 9455 if (status != B_OK) 9456 return status; 9457 9458 if (bufferSize > B_PATH_NAME_LENGTH) 9459 bufferSize = B_PATH_NAME_LENGTH; 9460 } 9461 9462 size_t newBufferSize = bufferSize; 9463 status_t status = common_read_link(fd, userPath ? path : NULL, buffer, 9464 &newBufferSize, false); 9465 9466 // we also update the bufferSize in case of errors 9467 // (the real length will be returned in case of B_BUFFER_OVERFLOW) 9468 if (user_memcpy(userBufferSize, &newBufferSize, sizeof(size_t)) != B_OK) 9469 return B_BAD_ADDRESS; 9470 9471 if (status != B_OK) 9472 return status; 9473 9474 bufferSize = min_c(newBufferSize, bufferSize); 9475 if (user_memcpy(userBuffer, buffer, bufferSize) != B_OK) 9476 return B_BAD_ADDRESS; 9477 9478 return B_OK; 9479 } 9480 9481 9482 status_t 9483 _user_create_symlink(int fd, const char* userPath, const char* userToPath, 9484 int mode) 9485 { 9486 KPath pathBuffer; 9487 KPath toPathBuffer; 9488 if (pathBuffer.InitCheck() != B_OK || toPathBuffer.InitCheck() != B_OK) 9489 return B_NO_MEMORY; 9490 9491 char* path = pathBuffer.LockBuffer(); 9492 char* toPath = toPathBuffer.LockBuffer(); 9493 9494 if (!IS_USER_ADDRESS(userPath) || !IS_USER_ADDRESS(userToPath)) 9495 return B_BAD_ADDRESS; 9496 status_t status = user_copy_name(path, userPath, B_PATH_NAME_LENGTH); 9497 if (status != B_OK) 9498 return status; 9499 status = user_copy_name(toPath, userToPath, B_PATH_NAME_LENGTH); 9500 if (status != B_OK) 9501 return status; 9502 9503 return common_create_symlink(fd, path, toPath, mode, false); 9504 } 9505 9506 9507 status_t 9508 _user_create_link(int pathFD, const char* userPath, int toFD, 9509 const char* userToPath, bool traverseLeafLink) 9510 { 9511 KPath pathBuffer; 9512 KPath toPathBuffer; 9513 if (pathBuffer.InitCheck() != B_OK || toPathBuffer.InitCheck() != B_OK) 9514 return B_NO_MEMORY; 9515 9516 char* path = pathBuffer.LockBuffer(); 9517 char* toPath = toPathBuffer.LockBuffer(); 9518 9519 if (!IS_USER_ADDRESS(userPath) || !IS_USER_ADDRESS(userToPath)) 9520 return B_BAD_ADDRESS; 9521 status_t status = user_copy_name(path, userPath, B_PATH_NAME_LENGTH); 9522 if (status != B_OK) 9523 return status; 9524 status = user_copy_name(toPath, userToPath, B_PATH_NAME_LENGTH); 9525 if (status != B_OK) 9526 return status; 9527 9528 status = check_path(toPath); 9529 if (status != B_OK) 9530 return status; 9531 9532 return common_create_link(pathFD, path, toFD, toPath, traverseLeafLink, 9533 false); 9534 } 9535 9536 9537 status_t 9538 _user_unlink(int fd, const char* userPath) 9539 { 9540 KPath pathBuffer; 9541 if (pathBuffer.InitCheck() != B_OK) 9542 return B_NO_MEMORY; 9543 9544 char* path = pathBuffer.LockBuffer(); 9545 9546 if (!IS_USER_ADDRESS(userPath)) 9547 return B_BAD_ADDRESS; 9548 status_t status = user_copy_name(path, userPath, B_PATH_NAME_LENGTH); 9549 if (status != B_OK) 9550 return status; 9551 9552 return common_unlink(fd, path, false); 9553 } 9554 9555 9556 status_t 9557 _user_rename(int oldFD, const char* userOldPath, int newFD, 9558 const char* userNewPath) 9559 { 9560 KPath oldPathBuffer; 9561 KPath newPathBuffer; 9562 if (oldPathBuffer.InitCheck() != B_OK || newPathBuffer.InitCheck() != B_OK) 9563 return B_NO_MEMORY; 9564 9565 char* oldPath = oldPathBuffer.LockBuffer(); 9566 char* newPath = newPathBuffer.LockBuffer(); 9567 9568 if (!IS_USER_ADDRESS(userOldPath) || !IS_USER_ADDRESS(userNewPath)) 9569 return B_BAD_ADDRESS; 9570 status_t status = user_copy_name(oldPath, userOldPath, B_PATH_NAME_LENGTH); 9571 if (status != B_OK) 9572 return status; 9573 status = user_copy_name(newPath, userNewPath, B_PATH_NAME_LENGTH); 9574 if (status != B_OK) 9575 return status; 9576 9577 return common_rename(oldFD, oldPath, newFD, newPath, false); 9578 } 9579 9580 9581 status_t 9582 _user_create_fifo(int fd, const char* userPath, mode_t perms) 9583 { 9584 KPath pathBuffer; 9585 if (pathBuffer.InitCheck() != B_OK) 9586 return B_NO_MEMORY; 9587 9588 char* path = pathBuffer.LockBuffer(); 9589 9590 if (!IS_USER_ADDRESS(userPath)) 9591 return B_BAD_ADDRESS; 9592 status_t status = user_copy_name(path, userPath, B_PATH_NAME_LENGTH); 9593 if (status != B_OK) 9594 return status; 9595 9596 // split into directory vnode and filename path 9597 char filename[B_FILE_NAME_LENGTH]; 9598 struct vnode* dir; 9599 status = fd_and_path_to_dir_vnode(fd, path, &dir, filename, false); 9600 if (status != B_OK) 9601 return status; 9602 9603 VNodePutter _(dir); 9604 9605 // the underlying FS needs to support creating FIFOs 9606 if (!HAS_FS_CALL(dir, create_special_node)) 9607 return B_UNSUPPORTED; 9608 9609 // create the entry -- the FIFO sub node is set up automatically 9610 fs_vnode superVnode; 9611 ino_t nodeID; 9612 status = FS_CALL(dir, create_special_node, filename, NULL, 9613 S_IFIFO | (perms & S_IUMSK), 0, &superVnode, &nodeID); 9614 9615 // create_special_node() acquired a reference for us that we don't need. 9616 if (status == B_OK) 9617 put_vnode(dir->mount->volume, nodeID); 9618 9619 return status; 9620 } 9621 9622 9623 status_t 9624 _user_create_pipe(int* userFDs) 9625 { 9626 // rootfs should support creating FIFOs, but let's be sure 9627 if (!HAS_FS_CALL(sRoot, create_special_node)) 9628 return B_UNSUPPORTED; 9629 9630 // create the node -- the FIFO sub node is set up automatically 9631 fs_vnode superVnode; 9632 ino_t nodeID; 9633 status_t status = FS_CALL(sRoot, create_special_node, NULL, NULL, 9634 S_IFIFO | S_IRUSR | S_IWUSR, 0, &superVnode, &nodeID); 9635 if (status != B_OK) 9636 return status; 9637 9638 // We've got one reference to the node and need another one. 9639 struct vnode* vnode; 9640 status = get_vnode(sRoot->mount->id, nodeID, &vnode, true, false); 9641 if (status != B_OK) { 9642 // that should not happen 9643 dprintf("_user_create_pipe(): Failed to lookup vnode (%" B_PRIdDEV ", " 9644 "%" B_PRIdINO ")\n", sRoot->mount->id, sRoot->id); 9645 return status; 9646 } 9647 9648 // Everything looks good so far. Open two FDs for reading respectively 9649 // writing. 9650 int fds[2]; 9651 fds[0] = open_vnode(vnode, O_RDONLY, false); 9652 fds[1] = open_vnode(vnode, O_WRONLY, false); 9653 9654 FDCloser closer0(fds[0], false); 9655 FDCloser closer1(fds[1], false); 9656 9657 status = (fds[0] >= 0 ? (fds[1] >= 0 ? B_OK : fds[1]) : fds[0]); 9658 9659 // copy FDs to userland 9660 if (status == B_OK) { 9661 if (!IS_USER_ADDRESS(userFDs) 9662 || user_memcpy(userFDs, fds, sizeof(fds)) != B_OK) { 9663 status = B_BAD_ADDRESS; 9664 } 9665 } 9666 9667 // keep FDs, if everything went fine 9668 if (status == B_OK) { 9669 closer0.Detach(); 9670 closer1.Detach(); 9671 } 9672 9673 return status; 9674 } 9675 9676 9677 status_t 9678 _user_access(int fd, const char* userPath, int mode, bool effectiveUserGroup) 9679 { 9680 KPath pathBuffer; 9681 if (pathBuffer.InitCheck() != B_OK) 9682 return B_NO_MEMORY; 9683 9684 char* path = pathBuffer.LockBuffer(); 9685 9686 if (!IS_USER_ADDRESS(userPath)) 9687 return B_BAD_ADDRESS; 9688 status_t status = user_copy_name(path, userPath, B_PATH_NAME_LENGTH); 9689 if (status != B_OK) 9690 return status; 9691 9692 return common_access(fd, path, mode, effectiveUserGroup, false); 9693 } 9694 9695 9696 status_t 9697 _user_read_stat(int fd, const char* userPath, bool traverseLink, 9698 struct stat* userStat, size_t statSize) 9699 { 9700 struct stat stat = {0}; 9701 status_t status; 9702 9703 if (statSize > sizeof(struct stat)) 9704 return B_BAD_VALUE; 9705 9706 if (!IS_USER_ADDRESS(userStat)) 9707 return B_BAD_ADDRESS; 9708 9709 if (userPath != NULL) { 9710 // path given: get the stat of the node referred to by (fd, path) 9711 if (!IS_USER_ADDRESS(userPath)) 9712 return B_BAD_ADDRESS; 9713 9714 KPath pathBuffer; 9715 if (pathBuffer.InitCheck() != B_OK) 9716 return B_NO_MEMORY; 9717 9718 char* path = pathBuffer.LockBuffer(); 9719 9720 status = user_copy_name(path, userPath, B_PATH_NAME_LENGTH); 9721 if (status != B_OK) 9722 return status; 9723 9724 status = common_path_read_stat(fd, path, traverseLink, &stat, false); 9725 } else { 9726 // no path given: get the FD and use the FD operation 9727 struct file_descriptor* descriptor 9728 = get_fd(get_current_io_context(false), fd); 9729 if (descriptor == NULL) 9730 return B_FILE_ERROR; 9731 9732 if (descriptor->ops->fd_read_stat) 9733 status = descriptor->ops->fd_read_stat(descriptor, &stat); 9734 else 9735 status = B_UNSUPPORTED; 9736 9737 put_fd(descriptor); 9738 } 9739 9740 if (status != B_OK) 9741 return status; 9742 9743 return user_memcpy(userStat, &stat, statSize); 9744 } 9745 9746 9747 status_t 9748 _user_write_stat(int fd, const char* userPath, bool traverseLeafLink, 9749 const struct stat* userStat, size_t statSize, int statMask) 9750 { 9751 if (statSize > sizeof(struct stat)) 9752 return B_BAD_VALUE; 9753 9754 struct stat stat; 9755 9756 if (!IS_USER_ADDRESS(userStat) 9757 || user_memcpy(&stat, userStat, statSize) < B_OK) 9758 return B_BAD_ADDRESS; 9759 9760 // clear additional stat fields 9761 if (statSize < sizeof(struct stat)) 9762 memset((uint8*)&stat + statSize, 0, sizeof(struct stat) - statSize); 9763 9764 status_t status; 9765 9766 if (userPath != NULL) { 9767 // path given: write the stat of the node referred to by (fd, path) 9768 if (!IS_USER_ADDRESS(userPath)) 9769 return B_BAD_ADDRESS; 9770 9771 KPath pathBuffer; 9772 if (pathBuffer.InitCheck() != B_OK) 9773 return B_NO_MEMORY; 9774 9775 char* path = pathBuffer.LockBuffer(); 9776 9777 status = user_copy_name(path, userPath, B_PATH_NAME_LENGTH); 9778 if (status != B_OK) 9779 return status; 9780 9781 status = common_path_write_stat(fd, path, traverseLeafLink, &stat, 9782 statMask, false); 9783 } else { 9784 // no path given: get the FD and use the FD operation 9785 struct file_descriptor* descriptor 9786 = get_fd(get_current_io_context(false), fd); 9787 if (descriptor == NULL) 9788 return B_FILE_ERROR; 9789 9790 if (descriptor->ops->fd_write_stat) { 9791 status = descriptor->ops->fd_write_stat(descriptor, &stat, 9792 statMask); 9793 } else 9794 status = B_UNSUPPORTED; 9795 9796 put_fd(descriptor); 9797 } 9798 9799 return status; 9800 } 9801 9802 9803 int 9804 _user_open_attr_dir(int fd, const char* userPath, bool traverseLeafLink) 9805 { 9806 KPath pathBuffer; 9807 if (pathBuffer.InitCheck() != B_OK) 9808 return B_NO_MEMORY; 9809 9810 char* path = pathBuffer.LockBuffer(); 9811 9812 if (userPath != NULL) { 9813 if (!IS_USER_ADDRESS(userPath)) 9814 return B_BAD_ADDRESS; 9815 status_t status = user_copy_name(path, userPath, B_PATH_NAME_LENGTH); 9816 if (status != B_OK) 9817 return status; 9818 } 9819 9820 return attr_dir_open(fd, userPath ? path : NULL, traverseLeafLink, false); 9821 } 9822 9823 9824 ssize_t 9825 _user_read_attr(int fd, const char* userAttribute, off_t pos, void* userBuffer, 9826 size_t readBytes) 9827 { 9828 char attribute[B_FILE_NAME_LENGTH]; 9829 9830 if (userAttribute == NULL) 9831 return B_BAD_VALUE; 9832 if (!IS_USER_ADDRESS(userAttribute)) 9833 return B_BAD_ADDRESS; 9834 status_t status = user_copy_name(attribute, userAttribute, sizeof(attribute)); 9835 if (status != B_OK) 9836 return status; 9837 9838 int attr = attr_open(fd, NULL, attribute, O_RDONLY, false); 9839 if (attr < 0) 9840 return attr; 9841 9842 ssize_t bytes = _user_read(attr, pos, userBuffer, readBytes); 9843 _user_close(attr); 9844 9845 return bytes; 9846 } 9847 9848 9849 ssize_t 9850 _user_write_attr(int fd, const char* userAttribute, uint32 type, off_t pos, 9851 const void* buffer, size_t writeBytes) 9852 { 9853 char attribute[B_FILE_NAME_LENGTH]; 9854 9855 if (userAttribute == NULL) 9856 return B_BAD_VALUE; 9857 if (!IS_USER_ADDRESS(userAttribute)) 9858 return B_BAD_ADDRESS; 9859 status_t status = user_copy_name(attribute, userAttribute, sizeof(attribute)); 9860 if (status != B_OK) 9861 return status; 9862 9863 // Try to support the BeOS typical truncation as well as the position 9864 // argument 9865 int attr = attr_create(fd, NULL, attribute, type, 9866 O_CREAT | O_WRONLY | (pos != 0 ? 0 : O_TRUNC), false); 9867 if (attr < 0) 9868 return attr; 9869 9870 ssize_t bytes = _user_write(attr, pos, buffer, writeBytes); 9871 _user_close(attr); 9872 9873 return bytes; 9874 } 9875 9876 9877 status_t 9878 _user_stat_attr(int fd, const char* userAttribute, 9879 struct attr_info* userAttrInfo) 9880 { 9881 char attribute[B_FILE_NAME_LENGTH]; 9882 9883 if (userAttribute == NULL || userAttrInfo == NULL) 9884 return B_BAD_VALUE; 9885 if (!IS_USER_ADDRESS(userAttribute) || !IS_USER_ADDRESS(userAttrInfo)) 9886 return B_BAD_ADDRESS; 9887 status_t status = user_copy_name(attribute, userAttribute, 9888 sizeof(attribute)); 9889 if (status != B_OK) 9890 return status; 9891 9892 int attr = attr_open(fd, NULL, attribute, O_RDONLY, false); 9893 if (attr < 0) 9894 return attr; 9895 9896 struct file_descriptor* descriptor 9897 = get_fd(get_current_io_context(false), attr); 9898 if (descriptor == NULL) { 9899 _user_close(attr); 9900 return B_FILE_ERROR; 9901 } 9902 9903 struct stat stat; 9904 if (descriptor->ops->fd_read_stat) 9905 status = descriptor->ops->fd_read_stat(descriptor, &stat); 9906 else 9907 status = B_UNSUPPORTED; 9908 9909 put_fd(descriptor); 9910 _user_close(attr); 9911 9912 if (status == B_OK) { 9913 attr_info info; 9914 info.type = stat.st_type; 9915 info.size = stat.st_size; 9916 9917 if (user_memcpy(userAttrInfo, &info, sizeof(struct attr_info)) != B_OK) 9918 return B_BAD_ADDRESS; 9919 } 9920 9921 return status; 9922 } 9923 9924 9925 int 9926 _user_open_attr(int fd, const char* userPath, const char* userName, 9927 uint32 type, int openMode) 9928 { 9929 char name[B_FILE_NAME_LENGTH]; 9930 9931 if (!IS_USER_ADDRESS(userName)) 9932 return B_BAD_ADDRESS; 9933 status_t status = user_copy_name(name, userName, B_FILE_NAME_LENGTH); 9934 if (status != B_OK) 9935 return status; 9936 9937 KPath pathBuffer; 9938 if (pathBuffer.InitCheck() != B_OK) 9939 return B_NO_MEMORY; 9940 9941 char* path = pathBuffer.LockBuffer(); 9942 9943 if (userPath != NULL) { 9944 if (!IS_USER_ADDRESS(userPath)) 9945 return B_BAD_ADDRESS; 9946 status = user_copy_name(path, userPath, B_PATH_NAME_LENGTH); 9947 if (status != B_OK) 9948 return status; 9949 } 9950 9951 if ((openMode & O_CREAT) != 0) { 9952 return attr_create(fd, userPath ? path : NULL, name, type, openMode, 9953 false); 9954 } 9955 9956 return attr_open(fd, userPath ? path : NULL, name, openMode, false); 9957 } 9958 9959 9960 status_t 9961 _user_remove_attr(int fd, const char* userName) 9962 { 9963 char name[B_FILE_NAME_LENGTH]; 9964 9965 if (!IS_USER_ADDRESS(userName)) 9966 return B_BAD_ADDRESS; 9967 status_t status = user_copy_name(name, userName, B_FILE_NAME_LENGTH); 9968 if (status != B_OK) 9969 return status; 9970 9971 return attr_remove(fd, name, false); 9972 } 9973 9974 9975 status_t 9976 _user_rename_attr(int fromFile, const char* userFromName, int toFile, 9977 const char* userToName) 9978 { 9979 if (!IS_USER_ADDRESS(userFromName) 9980 || !IS_USER_ADDRESS(userToName)) 9981 return B_BAD_ADDRESS; 9982 9983 KPath fromNameBuffer(B_FILE_NAME_LENGTH); 9984 KPath toNameBuffer(B_FILE_NAME_LENGTH); 9985 if (fromNameBuffer.InitCheck() != B_OK || toNameBuffer.InitCheck() != B_OK) 9986 return B_NO_MEMORY; 9987 9988 char* fromName = fromNameBuffer.LockBuffer(); 9989 char* toName = toNameBuffer.LockBuffer(); 9990 9991 status_t status = user_copy_name(fromName, userFromName, B_FILE_NAME_LENGTH); 9992 if (status != B_OK) 9993 return status; 9994 status = user_copy_name(toName, userToName, B_FILE_NAME_LENGTH); 9995 if (status != B_OK) 9996 return status; 9997 9998 return attr_rename(fromFile, fromName, toFile, toName, false); 9999 } 10000 10001 10002 int 10003 _user_open_index_dir(dev_t device) 10004 { 10005 return index_dir_open(device, false); 10006 } 10007 10008 10009 status_t 10010 _user_create_index(dev_t device, const char* userName, uint32 type, 10011 uint32 flags) 10012 { 10013 char name[B_FILE_NAME_LENGTH]; 10014 10015 if (!IS_USER_ADDRESS(userName)) 10016 return B_BAD_ADDRESS; 10017 status_t status = user_copy_name(name, userName, B_FILE_NAME_LENGTH); 10018 if (status != B_OK) 10019 return status; 10020 10021 return index_create(device, name, type, flags, false); 10022 } 10023 10024 10025 status_t 10026 _user_read_index_stat(dev_t device, const char* userName, struct stat* userStat) 10027 { 10028 char name[B_FILE_NAME_LENGTH]; 10029 struct stat stat = {0}; 10030 status_t status; 10031 10032 if (!IS_USER_ADDRESS(userName) || !IS_USER_ADDRESS(userStat)) 10033 return B_BAD_ADDRESS; 10034 status = user_copy_name(name, userName, B_FILE_NAME_LENGTH); 10035 if (status != B_OK) 10036 return status; 10037 10038 status = index_name_read_stat(device, name, &stat, false); 10039 if (status == B_OK) { 10040 if (user_memcpy(userStat, &stat, sizeof(stat)) != B_OK) 10041 return B_BAD_ADDRESS; 10042 } 10043 10044 return status; 10045 } 10046 10047 10048 status_t 10049 _user_remove_index(dev_t device, const char* userName) 10050 { 10051 char name[B_FILE_NAME_LENGTH]; 10052 10053 if (!IS_USER_ADDRESS(userName)) 10054 return B_BAD_ADDRESS; 10055 status_t status = user_copy_name(name, userName, B_FILE_NAME_LENGTH); 10056 if (status != B_OK) 10057 return status; 10058 10059 return index_remove(device, name, false); 10060 } 10061 10062 10063 status_t 10064 _user_getcwd(char* userBuffer, size_t size) 10065 { 10066 if (size == 0) 10067 return B_BAD_VALUE; 10068 if (!IS_USER_ADDRESS(userBuffer)) 10069 return B_BAD_ADDRESS; 10070 10071 if (size > kMaxPathLength) 10072 size = kMaxPathLength; 10073 10074 KPath pathBuffer(size); 10075 if (pathBuffer.InitCheck() != B_OK) 10076 return B_NO_MEMORY; 10077 10078 TRACE(("user_getcwd: buf %p, %ld\n", userBuffer, size)); 10079 10080 char* path = pathBuffer.LockBuffer(); 10081 10082 status_t status = get_cwd(path, size, false); 10083 if (status != B_OK) 10084 return status; 10085 10086 // Copy back the result 10087 if (user_strlcpy(userBuffer, path, size) < B_OK) 10088 return B_BAD_ADDRESS; 10089 10090 return status; 10091 } 10092 10093 10094 status_t 10095 _user_setcwd(int fd, const char* userPath) 10096 { 10097 TRACE(("user_setcwd: path = %p\n", userPath)); 10098 10099 KPath pathBuffer; 10100 if (pathBuffer.InitCheck() != B_OK) 10101 return B_NO_MEMORY; 10102 10103 char* path = pathBuffer.LockBuffer(); 10104 10105 if (userPath != NULL) { 10106 if (!IS_USER_ADDRESS(userPath)) 10107 return B_BAD_ADDRESS; 10108 status_t status = user_copy_name(path, userPath, B_PATH_NAME_LENGTH); 10109 if (status != B_OK) 10110 return status; 10111 } 10112 10113 return set_cwd(fd, userPath != NULL ? path : NULL, false); 10114 } 10115 10116 10117 status_t 10118 _user_change_root(const char* userPath) 10119 { 10120 // only root is allowed to chroot() 10121 if (geteuid() != 0) 10122 return B_NOT_ALLOWED; 10123 10124 // alloc path buffer 10125 KPath pathBuffer; 10126 if (pathBuffer.InitCheck() != B_OK) 10127 return B_NO_MEMORY; 10128 10129 // copy userland path to kernel 10130 char* path = pathBuffer.LockBuffer(); 10131 if (userPath != NULL) { 10132 if (!IS_USER_ADDRESS(userPath)) 10133 return B_BAD_ADDRESS; 10134 status_t status = user_copy_name(path, userPath, B_PATH_NAME_LENGTH); 10135 if (status != B_OK) 10136 return status; 10137 } 10138 10139 // get the vnode 10140 struct vnode* vnode; 10141 status_t status = path_to_vnode(path, true, &vnode, NULL, false); 10142 if (status != B_OK) 10143 return status; 10144 10145 // set the new root 10146 struct io_context* context = get_current_io_context(false); 10147 mutex_lock(&sIOContextRootLock); 10148 struct vnode* oldRoot = context->root; 10149 context->root = vnode; 10150 mutex_unlock(&sIOContextRootLock); 10151 10152 put_vnode(oldRoot); 10153 10154 return B_OK; 10155 } 10156 10157 10158 int 10159 _user_open_query(dev_t device, const char* userQuery, size_t queryLength, 10160 uint32 flags, port_id port, int32 token) 10161 { 10162 if (device < 0 || userQuery == NULL || queryLength == 0) 10163 return B_BAD_VALUE; 10164 10165 if (!IS_USER_ADDRESS(userQuery)) 10166 return B_BAD_ADDRESS; 10167 10168 // this is a safety restriction 10169 if (queryLength >= 65536) 10170 return B_NAME_TOO_LONG; 10171 10172 BStackOrHeapArray<char, 128> query(queryLength + 1); 10173 if (!query.IsValid()) 10174 return B_NO_MEMORY; 10175 10176 if (user_strlcpy(query, userQuery, queryLength + 1) < B_OK) 10177 return B_BAD_ADDRESS; 10178 10179 return query_open(device, query, flags, port, token, false); 10180 } 10181 10182 10183 #include "vfs_request_io.cpp" 10184