1 /* 2 * Copyright 2003-2013, Axel Dörfler, axeld@pinc-software.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include <boot/vfs.h> 8 9 #include <errno.h> 10 #include <fcntl.h> 11 #include <string.h> 12 #include <sys/uio.h> 13 #include <unistd.h> 14 15 #include <StorageDefs.h> 16 17 #include <AutoDeleter.h> 18 19 #include <boot/platform.h> 20 #include <boot/partitions.h> 21 #include <boot/stdio.h> 22 #include <boot/stage2.h> 23 #include <syscall_utils.h> 24 25 #include "RootFileSystem.h" 26 #include "file_systems/packagefs/packagefs.h" 27 28 29 using namespace boot; 30 31 //#define TRACE_VFS 32 #ifdef TRACE_VFS 33 # define TRACE(x) dprintf x 34 #else 35 # define TRACE(x) ; 36 #endif 37 38 39 class Descriptor { 40 public: 41 Descriptor(Node *node, void *cookie); 42 ~Descriptor(); 43 44 ssize_t ReadAt(off_t pos, void *buffer, size_t bufferSize); 45 ssize_t Read(void *buffer, size_t bufferSize); 46 ssize_t WriteAt(off_t pos, const void *buffer, size_t bufferSize); 47 ssize_t Write(const void *buffer, size_t bufferSize); 48 49 status_t Stat(struct stat &stat); 50 51 off_t Offset() const { return fOffset; } 52 int32 RefCount() const { return fRefCount; } 53 54 status_t Acquire(); 55 status_t Release(); 56 57 Node *GetNode() const { return fNode; } 58 59 private: 60 Node *fNode; 61 void *fCookie; 62 off_t fOffset; 63 int32 fRefCount; 64 }; 65 66 #define MAX_VFS_DESCRIPTORS 64 67 68 NodeList gBootDevices; 69 NodeList gPartitions; 70 RootFileSystem *gRoot; 71 static Descriptor *sDescriptors[MAX_VFS_DESCRIPTORS]; 72 static Node *sBootDevice; 73 74 75 Node::Node() 76 : 77 fRefCount(1) 78 { 79 } 80 81 82 Node::~Node() 83 { 84 } 85 86 87 status_t 88 Node::Open(void **_cookie, int mode) 89 { 90 TRACE(("%p::Open()\n", this)); 91 return Acquire(); 92 } 93 94 95 status_t 96 Node::Close(void *cookie) 97 { 98 TRACE(("%p::Close()\n", this)); 99 return Release(); 100 } 101 102 103 status_t 104 Node::ReadLink(char* buffer, size_t bufferSize) 105 { 106 return B_BAD_VALUE; 107 } 108 109 110 status_t 111 Node::GetName(char *nameBuffer, size_t bufferSize) const 112 { 113 return B_ERROR; 114 } 115 116 117 status_t 118 Node::GetFileMap(struct file_map_run *runs, int32 *count) 119 { 120 return B_ERROR; 121 } 122 123 124 int32 125 Node::Type() const 126 { 127 return 0; 128 } 129 130 131 off_t 132 Node::Size() const 133 { 134 return 0LL; 135 } 136 137 138 ino_t 139 Node::Inode() const 140 { 141 return 0; 142 } 143 144 145 status_t 146 Node::Acquire() 147 { 148 fRefCount++; 149 TRACE(("%p::Acquire(), fRefCount = %ld\n", this, fRefCount)); 150 return B_OK; 151 } 152 153 154 status_t 155 Node::Release() 156 { 157 TRACE(("%p::Release(), fRefCount = %ld\n", this, fRefCount)); 158 if (--fRefCount == 0) { 159 TRACE(("delete node: %p\n", this)); 160 delete this; 161 return 1; 162 } 163 164 return B_OK; 165 } 166 167 168 // #pragma mark - 169 170 171 ConsoleNode::ConsoleNode() 172 : Node() 173 { 174 } 175 176 177 ssize_t 178 ConsoleNode::Read(void *buffer, size_t bufferSize) 179 { 180 return ReadAt(NULL, -1, buffer, bufferSize); 181 } 182 183 184 ssize_t 185 ConsoleNode::Write(const void *buffer, size_t bufferSize) 186 { 187 return WriteAt(NULL, -1, buffer, bufferSize); 188 } 189 190 191 // #pragma mark - 192 193 194 Directory::Directory() 195 : Node() 196 { 197 } 198 199 200 ssize_t 201 Directory::ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize) 202 { 203 return B_ERROR; 204 } 205 206 207 ssize_t 208 Directory::WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize) 209 { 210 return B_ERROR; 211 } 212 213 214 int32 215 Directory::Type() const 216 { 217 return S_IFDIR; 218 } 219 220 221 Node* 222 Directory::Lookup(const char* name, bool traverseLinks) 223 { 224 Node* node = LookupDontTraverse(name); 225 if (node == NULL) 226 return NULL; 227 228 if (!traverseLinks || !S_ISLNK(node->Type())) 229 return node; 230 231 // the node is a symbolic link, so we have to resolve the path 232 char linkPath[B_PATH_NAME_LENGTH]; 233 status_t error = node->ReadLink(linkPath, sizeof(linkPath)); 234 235 node->Release(); 236 // we don't need this one anymore 237 238 if (error != B_OK) 239 return NULL; 240 241 // let open_from() do the real work 242 int fd = open_from(this, linkPath, O_RDONLY); 243 if (fd < 0) 244 return NULL; 245 246 node = get_node_from(fd); 247 if (node != NULL) 248 node->Acquire(); 249 250 close(fd); 251 return node; 252 } 253 254 255 status_t 256 Directory::CreateFile(const char *name, mode_t permissions, Node **_node) 257 { 258 return EROFS; 259 } 260 261 262 // #pragma mark - 263 264 265 MemoryDisk::MemoryDisk(const uint8* data, size_t size, const char* name) 266 : Node(), 267 fData(data), 268 fSize(size) 269 { 270 strlcpy(fName, name, sizeof(fName)); 271 } 272 273 274 ssize_t 275 MemoryDisk::ReadAt(void* cookie, off_t pos, void* buffer, size_t bufferSize) 276 { 277 if (pos >= fSize) 278 return 0; 279 280 if (pos + bufferSize > fSize) 281 bufferSize = fSize - pos; 282 283 memcpy(buffer, fData + pos, bufferSize); 284 return bufferSize; 285 } 286 287 288 ssize_t 289 MemoryDisk::WriteAt(void* cookie, off_t pos, const void* buffer, 290 size_t bufferSize) 291 { 292 return B_NOT_ALLOWED; 293 } 294 295 296 off_t 297 MemoryDisk::Size() const 298 { 299 return fSize; 300 } 301 302 303 status_t 304 MemoryDisk::GetName(char *nameBuffer, size_t bufferSize) const 305 { 306 if (!nameBuffer) 307 return B_BAD_VALUE; 308 309 strlcpy(nameBuffer, fName, bufferSize); 310 return B_OK; 311 } 312 313 314 // #pragma mark - 315 316 317 Descriptor::Descriptor(Node *node, void *cookie) 318 : 319 fNode(node), 320 fCookie(cookie), 321 fOffset(0), 322 fRefCount(1) 323 { 324 } 325 326 327 Descriptor::~Descriptor() 328 { 329 } 330 331 332 ssize_t 333 Descriptor::Read(void *buffer, size_t bufferSize) 334 { 335 ssize_t bytesRead = fNode->ReadAt(fCookie, fOffset, buffer, bufferSize); 336 if (bytesRead > B_OK) 337 fOffset += bytesRead; 338 339 return bytesRead; 340 } 341 342 343 ssize_t 344 Descriptor::ReadAt(off_t pos, void *buffer, size_t bufferSize) 345 { 346 return fNode->ReadAt(fCookie, pos, buffer, bufferSize); 347 } 348 349 350 ssize_t 351 Descriptor::Write(const void *buffer, size_t bufferSize) 352 { 353 ssize_t bytesWritten = fNode->WriteAt(fCookie, fOffset, buffer, bufferSize); 354 if (bytesWritten > B_OK) 355 fOffset += bytesWritten; 356 357 return bytesWritten; 358 } 359 360 361 ssize_t 362 Descriptor::WriteAt(off_t pos, const void *buffer, size_t bufferSize) 363 { 364 return fNode->WriteAt(fCookie, pos, buffer, bufferSize); 365 } 366 367 368 status_t 369 Descriptor::Stat(struct stat &stat) 370 { 371 stat.st_mode = fNode->Type(); 372 stat.st_size = fNode->Size(); 373 stat.st_ino = fNode->Inode(); 374 375 return B_OK; 376 } 377 378 379 status_t 380 Descriptor::Acquire() 381 { 382 fRefCount++; 383 return B_OK; 384 } 385 386 387 status_t 388 Descriptor::Release() 389 { 390 if (--fRefCount == 0) { 391 status_t status = fNode->Close(fCookie); 392 if (status != B_OK) 393 return status; 394 } 395 396 return B_OK; 397 } 398 399 400 // #pragma mark - 401 402 403 BootVolume::BootVolume() 404 : 405 fRootDirectory(NULL), 406 fSystemDirectory(NULL), 407 fPackaged(false) 408 { 409 } 410 411 412 BootVolume::~BootVolume() 413 { 414 Unset(); 415 } 416 417 418 status_t 419 BootVolume::SetTo(Directory* rootDirectory) 420 { 421 Unset(); 422 423 if (rootDirectory == NULL) 424 return B_BAD_VALUE; 425 426 fRootDirectory = rootDirectory; 427 fRootDirectory->Acquire(); 428 429 // find the system directory 430 Node* systemNode = fRootDirectory->Lookup("system", true); 431 if (systemNode == NULL || !S_ISDIR(systemNode->Type())) { 432 if (systemNode != NULL) 433 systemNode->Release(); 434 Unset(); 435 return B_ENTRY_NOT_FOUND; 436 } 437 438 fSystemDirectory = static_cast<Directory*>(systemNode); 439 440 // try opening the system package 441 int packageFD = _OpenSystemPackage(); 442 fPackaged = packageFD >= 0; 443 if (!fPackaged) 444 return B_OK; 445 446 // the system is packaged -- mount the packagefs 447 Directory* packageRootDirectory; 448 status_t error = packagefs_mount_file(packageFD, fSystemDirectory, 449 packageRootDirectory); 450 close(packageFD); 451 if (error != B_OK) { 452 Unset(); 453 return error; 454 } 455 456 fSystemDirectory->Release(); 457 fSystemDirectory = packageRootDirectory; 458 459 return B_OK; 460 } 461 462 463 void 464 BootVolume::Unset() 465 { 466 if (fRootDirectory != NULL) { 467 fRootDirectory->Release(); 468 fRootDirectory = NULL; 469 } 470 471 if (fSystemDirectory != NULL) { 472 fSystemDirectory->Release(); 473 fSystemDirectory = NULL; 474 } 475 476 fPackaged = false; 477 } 478 479 480 int 481 BootVolume::_OpenSystemPackage() 482 { 483 // open the packages directory 484 Node* packagesNode = fSystemDirectory->Lookup("packages", false); 485 if (packagesNode == NULL) 486 return -1; 487 MethodDeleter<Node, status_t> packagesNodeReleaser(packagesNode, 488 &Node::Release); 489 490 if (!S_ISDIR(packagesNode->Type())) 491 return -1; 492 Directory* packageDirectory = (Directory*)packagesNode; 493 494 // search for the system package 495 int fd = -1; 496 void* cookie; 497 if (packageDirectory->Open(&cookie, O_RDONLY) == B_OK) { 498 char name[B_FILE_NAME_LENGTH]; 499 while (packageDirectory->GetNextEntry(cookie, name, sizeof(name)) 500 == B_OK) { 501 // The name must end with ".hpkg". 502 size_t nameLength = strlen(name); 503 if (nameLength < 6 || strcmp(name + nameLength - 5, ".hpkg") != 0) 504 continue; 505 506 // The name must either be "haiku.hpkg" or start with "haiku-". 507 if (strcmp(name, "haiku.hpkg") == 0 508 || strncmp(name, "haiku-", 6) == 0) { 509 fd = open_from(packageDirectory, name, O_RDONLY); 510 break; 511 } 512 } 513 packageDirectory->Close(cookie); 514 } 515 516 return fd; 517 } 518 519 520 // #pragma mark - 521 522 523 status_t 524 vfs_init(stage2_args *args) 525 { 526 gRoot = new(nothrow) RootFileSystem(); 527 if (gRoot == NULL) 528 return B_NO_MEMORY; 529 530 return B_OK; 531 } 532 533 534 status_t 535 register_boot_file_system(BootVolume& bootVolume) 536 { 537 Directory* rootDirectory = bootVolume.RootDirectory(); 538 gRoot->AddLink("boot", rootDirectory); 539 540 Partition *partition; 541 status_t status = gRoot->GetPartitionFor(rootDirectory, &partition); 542 if (status != B_OK) { 543 dprintf("register_boot_file_system(): could not locate boot volume in " 544 "root!\n"); 545 return status; 546 } 547 548 gBootVolume.SetInt64(BOOT_VOLUME_PARTITION_OFFSET, 549 partition->offset); 550 if (bootVolume.IsPackaged()) 551 gBootVolume.SetBool(BOOT_VOLUME_PACKAGED, true); 552 553 Node *device = get_node_from(partition->FD()); 554 if (device == NULL) { 555 dprintf("register_boot_file_system(): could not get boot device!\n"); 556 return B_ERROR; 557 } 558 559 return platform_register_boot_device(device); 560 } 561 562 563 /*! Gets the boot device, scans all of its partitions, gets the 564 boot partition, and mounts its file system. 565 566 \param args The stage 2 arguments. 567 \param _bootVolume On success set to the boot volume. 568 \return \c B_OK on success, another error code otherwise. 569 */ 570 status_t 571 get_boot_file_system(stage2_args* args, BootVolume& _bootVolume) 572 { 573 Node *device; 574 status_t error = platform_add_boot_device(args, &gBootDevices); 575 if (error != B_OK) 576 return error; 577 578 // the boot device must be the first device in the list 579 device = gBootDevices.First(); 580 581 error = add_partitions_for(device, false, true); 582 if (error != B_OK) 583 return error; 584 585 Partition *partition; 586 error = platform_get_boot_partition(args, device, &gPartitions, &partition); 587 if (error != B_OK) 588 return error; 589 590 Directory *fileSystem; 591 error = partition->Mount(&fileSystem, true); 592 if (error != B_OK) { 593 // this partition doesn't contain any known file system; we 594 // don't need it anymore 595 gPartitions.Remove(partition); 596 delete partition; 597 return error; 598 } 599 600 // init the BootVolume 601 error = _bootVolume.SetTo(fileSystem); 602 if (error != B_OK) 603 return error; 604 605 sBootDevice = device; 606 return B_OK; 607 } 608 609 610 /** Mounts all file systems recognized on the given device by 611 * calling the add_partitions_for() function on them. 612 */ 613 614 status_t 615 mount_file_systems(stage2_args *args) 616 { 617 // mount other partitions on boot device (if any) 618 NodeIterator iterator = gPartitions.GetIterator(); 619 620 Partition *partition = NULL; 621 while ((partition = (Partition *)iterator.Next()) != NULL) { 622 // don't scan known partitions again 623 if (partition->IsFileSystem()) 624 continue; 625 626 // remove the partition if it doesn't contain a (known) file system 627 if (partition->Scan(true) != B_OK && !partition->IsFileSystem()) { 628 gPartitions.Remove(partition); 629 delete partition; 630 } 631 } 632 633 // add all block devices the platform has for us 634 635 status_t status = platform_add_block_devices(args, &gBootDevices); 636 if (status < B_OK) 637 return status; 638 639 iterator = gBootDevices.GetIterator(); 640 Node *device = NULL, *last = NULL; 641 while ((device = iterator.Next()) != NULL) { 642 // don't scan former boot device again 643 if (device == sBootDevice) 644 continue; 645 646 if (add_partitions_for(device, true) == B_OK) { 647 // ToDo: we can't delete the object here, because it must 648 // be removed from the list before we know that it was 649 // deleted. 650 651 /* // if the Release() deletes the object, we need to skip it 652 if (device->Release() > 0) { 653 list_remove_item(&gBootDevices, device); 654 device = last; 655 } 656 */ 657 (void)last; 658 } 659 last = device; 660 } 661 662 if (gPartitions.IsEmpty()) 663 return B_ENTRY_NOT_FOUND; 664 665 #if 0 666 void *cookie; 667 if (gRoot->Open(&cookie, O_RDONLY) == B_OK) { 668 Directory *directory; 669 while (gRoot->GetNextNode(cookie, (Node **)&directory) == B_OK) { 670 char name[256]; 671 if (directory->GetName(name, sizeof(name)) == B_OK) 672 printf(":: %s (%p)\n", name, directory); 673 674 void *subCookie; 675 if (directory->Open(&subCookie, O_RDONLY) == B_OK) { 676 while (directory->GetNextEntry(subCookie, name, sizeof(name)) == B_OK) { 677 printf("\t%s\n", name); 678 } 679 directory->Close(subCookie); 680 } 681 } 682 gRoot->Close(cookie); 683 } 684 #endif 685 686 return B_OK; 687 } 688 689 690 /*! Resolves \a directory + \a path to a node. 691 Note that \a path will be modified by the function. 692 */ 693 static status_t 694 get_node_for_path(Directory *directory, char *path, Node **_node) 695 { 696 directory->Acquire(); 697 // balance Acquire()/Release() calls 698 699 while (true) { 700 Node *nextNode; 701 char *nextPath; 702 703 // walk to find the next path component ("path" will point to a single 704 // path component), and filter out multiple slashes 705 for (nextPath = path + 1; nextPath[0] != '\0' && nextPath[0] != '/'; nextPath++); 706 707 if (*nextPath == '/') { 708 *nextPath = '\0'; 709 do 710 nextPath++; 711 while (*nextPath == '/'); 712 } 713 714 nextNode = directory->Lookup(path, true); 715 directory->Release(); 716 717 if (nextNode == NULL) 718 return B_ENTRY_NOT_FOUND; 719 720 path = nextPath; 721 if (S_ISDIR(nextNode->Type())) 722 directory = (Directory *)nextNode; 723 else if (path[0]) 724 return B_NOT_ALLOWED; 725 726 // are we done? 727 if (path[0] == '\0') { 728 *_node = nextNode; 729 return B_OK; 730 } 731 } 732 733 return B_ENTRY_NOT_FOUND; 734 } 735 736 737 // #pragma mark - 738 739 740 static Descriptor * 741 get_descriptor(int fd) 742 { 743 if (fd < 0 || fd >= MAX_VFS_DESCRIPTORS) 744 return NULL; 745 746 return sDescriptors[fd]; 747 } 748 749 750 static void 751 free_descriptor(int fd) 752 { 753 if (fd >= MAX_VFS_DESCRIPTORS) 754 return; 755 756 delete sDescriptors[fd]; 757 sDescriptors[fd] = NULL; 758 } 759 760 761 /** Reserves an entry of the descriptor table and 762 * assigns the given node to it. 763 */ 764 765 int 766 open_node(Node *node, int mode) 767 { 768 if (node == NULL) 769 return B_ERROR; 770 771 // get free descriptor 772 773 int fd = 0; 774 for (; fd < MAX_VFS_DESCRIPTORS; fd++) { 775 if (sDescriptors[fd] == NULL) 776 break; 777 } 778 if (fd == MAX_VFS_DESCRIPTORS) 779 return B_ERROR; 780 781 TRACE(("got descriptor %d for node %p\n", fd, node)); 782 783 // we got a free descriptor entry, now try to open the node 784 785 void *cookie; 786 status_t status = node->Open(&cookie, mode); 787 if (status < B_OK) 788 return status; 789 790 TRACE(("could open node at %p\n", node)); 791 792 Descriptor *descriptor = new(nothrow) Descriptor(node, cookie); 793 if (descriptor == NULL) 794 return B_NO_MEMORY; 795 796 sDescriptors[fd] = descriptor; 797 798 return fd; 799 } 800 801 802 int 803 dup(int fd) 804 { 805 Descriptor *descriptor = get_descriptor(fd); 806 if (descriptor == NULL) 807 RETURN_AND_SET_ERRNO(B_FILE_ERROR); 808 809 descriptor->Acquire(); 810 RETURN_AND_SET_ERRNO(fd); 811 } 812 813 814 ssize_t 815 read_pos(int fd, off_t offset, void *buffer, size_t bufferSize) 816 { 817 Descriptor *descriptor = get_descriptor(fd); 818 if (descriptor == NULL) 819 RETURN_AND_SET_ERRNO(B_FILE_ERROR); 820 821 RETURN_AND_SET_ERRNO(descriptor->ReadAt(offset, buffer, bufferSize)); 822 } 823 824 825 ssize_t 826 pread(int fd, void* buffer, size_t bufferSize, off_t offset) 827 { 828 return read_pos(fd, offset, buffer, bufferSize); 829 } 830 831 832 ssize_t 833 read(int fd, void *buffer, size_t bufferSize) 834 { 835 Descriptor *descriptor = get_descriptor(fd); 836 if (descriptor == NULL) 837 RETURN_AND_SET_ERRNO(B_FILE_ERROR); 838 839 RETURN_AND_SET_ERRNO(descriptor->Read(buffer, bufferSize)); 840 } 841 842 843 ssize_t 844 write_pos(int fd, off_t offset, const void *buffer, size_t bufferSize) 845 { 846 Descriptor *descriptor = get_descriptor(fd); 847 if (descriptor == NULL) 848 RETURN_AND_SET_ERRNO(B_FILE_ERROR); 849 850 RETURN_AND_SET_ERRNO(descriptor->WriteAt(offset, buffer, bufferSize)); 851 } 852 853 854 ssize_t 855 write(int fd, const void *buffer, size_t bufferSize) 856 { 857 Descriptor *descriptor = get_descriptor(fd); 858 if (descriptor == NULL) 859 RETURN_AND_SET_ERRNO(B_FILE_ERROR); 860 861 RETURN_AND_SET_ERRNO(descriptor->Write(buffer, bufferSize)); 862 } 863 864 865 ssize_t 866 writev(int fd, const struct iovec* vecs, size_t count) 867 { 868 size_t totalWritten = 0; 869 870 for (size_t i = 0; i < count; i++) { 871 ssize_t written = write(fd, vecs[i].iov_base, vecs[i].iov_len); 872 if (written < 0) 873 return totalWritten == 0 ? written : totalWritten; 874 875 totalWritten += written; 876 877 if ((size_t)written != vecs[i].iov_len) 878 break; 879 } 880 881 return totalWritten; 882 } 883 884 885 int 886 open(const char *name, int mode, ...) 887 { 888 mode_t permissions = 0; 889 if ((mode & O_CREAT) != 0) { 890 va_list args; 891 va_start(args, mode); 892 permissions = va_arg(args, int) /*& ~__gUmask*/; 893 // adapt the permissions as required by POSIX 894 va_end(args); 895 } 896 897 // we always start at the top (there is no notion of a current directory (yet?)) 898 RETURN_AND_SET_ERRNO(open_from(gRoot, name, mode, permissions)); 899 } 900 901 902 int 903 open_from(Directory *directory, const char *name, int mode, mode_t permissions) 904 { 905 if (name[0] == '/') { 906 // ignore the directory and start from root if we are asked to do that 907 directory = gRoot; 908 name++; 909 } 910 911 char path[B_PATH_NAME_LENGTH]; 912 if (strlcpy(path, name, sizeof(path)) >= sizeof(path)) 913 return B_NAME_TOO_LONG; 914 915 Node *node; 916 status_t error = get_node_for_path(directory, path, &node); 917 if (error != B_OK) { 918 if (error != B_ENTRY_NOT_FOUND) 919 return error; 920 921 if ((mode & O_CREAT) == 0) 922 return B_ENTRY_NOT_FOUND; 923 924 // try to resolve the parent directory 925 strlcpy(path, name, sizeof(path)); 926 if (char* lastSlash = strrchr(path, '/')) { 927 if (lastSlash[1] == '\0') 928 return B_ENTRY_NOT_FOUND; 929 930 lastSlash = '\0'; 931 name = lastSlash + 1; 932 933 // resolve the directory 934 if (get_node_for_path(directory, path, &node) != B_OK) 935 return B_ENTRY_NOT_FOUND; 936 937 if (node->Type() != S_IFDIR) { 938 node->Release(); 939 return B_NOT_A_DIRECTORY; 940 } 941 942 directory = static_cast<Directory*>(node); 943 } else 944 directory->Acquire(); 945 946 // create the file 947 error = directory->CreateFile(name, permissions, &node); 948 directory->Release(); 949 950 if (error != B_OK) 951 return error; 952 } else if ((mode & O_EXCL) != 0) { 953 node->Release(); 954 return B_FILE_EXISTS; 955 } 956 957 int fd = open_node(node, mode); 958 959 node->Release(); 960 return fd; 961 } 962 963 964 /** Since we don't have directory functions yet, this 965 * function is needed to get the contents of a directory. 966 * It should be removed once readdir() & co. are in place. 967 */ 968 969 Node * 970 get_node_from(int fd) 971 { 972 Descriptor *descriptor = get_descriptor(fd); 973 if (descriptor == NULL) 974 return NULL; 975 976 return descriptor->GetNode(); 977 } 978 979 980 int 981 close(int fd) 982 { 983 Descriptor *descriptor = get_descriptor(fd); 984 if (descriptor == NULL) 985 RETURN_AND_SET_ERRNO(B_FILE_ERROR); 986 987 status_t status = descriptor->Release(); 988 if (!descriptor->RefCount()) 989 free_descriptor(fd); 990 991 RETURN_AND_SET_ERRNO(status); 992 } 993 994 995 // ToDo: remove this kludge when possible 996 int 997 #if defined(fstat) && !defined(main) 998 _fstat(int fd, struct stat *stat, size_t /*statSize*/) 999 #else 1000 fstat(int fd, struct stat *stat) 1001 #endif 1002 { 1003 if (stat == NULL) 1004 RETURN_AND_SET_ERRNO(B_BAD_VALUE); 1005 1006 Descriptor *descriptor = get_descriptor(fd); 1007 if (descriptor == NULL) 1008 RETURN_AND_SET_ERRNO(B_FILE_ERROR); 1009 1010 RETURN_AND_SET_ERRNO(descriptor->Stat(*stat)); 1011 } 1012