1 /* 2 * Copyright 2003-2013, Axel Dörfler, axeld@pinc-software.de. 3 * Copyright 2014, Ingo Weinhold, ingo_weinhold@gmx.de. 4 * Copyright 2017, Jessica Hamilton, jessica.l.hamilton@gmail.com. 5 * Distributed under the terms of the MIT License. 6 */ 7 8 9 #include <boot/vfs.h> 10 11 #include <errno.h> 12 #include <fcntl.h> 13 #include <string.h> 14 #include <sys/uio.h> 15 #include <unistd.h> 16 17 #include <StorageDefs.h> 18 19 #include <AutoDeleter.h> 20 21 #include <boot/platform.h> 22 #include <boot/partitions.h> 23 #include <boot/stdio.h> 24 #include <boot/stage2.h> 25 #include <syscall_utils.h> 26 27 #include "package_support.h" 28 #include "RootFileSystem.h" 29 #include "file_systems/packagefs/packagefs.h" 30 31 32 using namespace boot; 33 34 //#define TRACE_VFS 35 #ifdef TRACE_VFS 36 # define TRACE(x) dprintf x 37 #else 38 # define TRACE(x) ; 39 #endif 40 41 42 struct __DIR { 43 Directory* directory; 44 void* cookie; 45 46 char _direntBuffer[sizeof(dirent) + B_FILE_NAME_LENGTH + 1]; 47 dirent* entry() { return (dirent*)_direntBuffer; } 48 }; 49 50 51 class Descriptor { 52 public: 53 Descriptor(Node *node, void *cookie); 54 ~Descriptor(); 55 56 ssize_t ReadAt(off_t pos, void *buffer, size_t bufferSize); 57 ssize_t Read(void *buffer, size_t bufferSize); 58 ssize_t WriteAt(off_t pos, const void *buffer, size_t bufferSize); 59 ssize_t Write(const void *buffer, size_t bufferSize); 60 61 void Stat(struct stat &stat); 62 status_t Seek(off_t position, int mode); 63 64 off_t Offset() const { return fOffset; } 65 int32 RefCount() const { return fRefCount; } 66 67 status_t Acquire(); 68 status_t Release(); 69 70 Node *GetNode() const { return fNode; } 71 72 private: 73 Node *fNode; 74 void *fCookie; 75 off_t fOffset; 76 int32 fRefCount; 77 }; 78 79 #define MAX_VFS_DESCRIPTORS 64 80 81 NodeList gBootDevices; 82 NodeList gPartitions; 83 RootFileSystem *gRoot; 84 static Descriptor *sDescriptors[MAX_VFS_DESCRIPTORS]; 85 static Node *sBootDevice; 86 87 88 Node::Node() 89 : 90 fRefCount(1) 91 { 92 } 93 94 95 Node::~Node() 96 { 97 } 98 99 100 status_t 101 Node::Open(void **_cookie, int mode) 102 { 103 TRACE(("%p::Open()\n", this)); 104 return Acquire(); 105 } 106 107 108 status_t 109 Node::Close(void *cookie) 110 { 111 TRACE(("%p::Close()\n", this)); 112 return Release(); 113 } 114 115 116 status_t 117 Node::ReadLink(char* buffer, size_t bufferSize) 118 { 119 return B_BAD_VALUE; 120 } 121 122 123 status_t 124 Node::GetName(char *nameBuffer, size_t bufferSize) const 125 { 126 return B_ERROR; 127 } 128 129 130 status_t 131 Node::GetFileMap(struct file_map_run *runs, int32 *count) 132 { 133 return B_ERROR; 134 } 135 136 137 int32 138 Node::Type() const 139 { 140 return 0; 141 } 142 143 144 off_t 145 Node::Size() const 146 { 147 return 0LL; 148 } 149 150 151 ino_t 152 Node::Inode() const 153 { 154 return 0; 155 } 156 157 158 void 159 Node::Stat(struct stat& stat) 160 { 161 stat.st_mode = Type(); 162 stat.st_size = Size(); 163 stat.st_ino = Inode(); 164 } 165 166 167 status_t 168 Node::Acquire() 169 { 170 fRefCount++; 171 TRACE(("%p::Acquire(), fRefCount = %" B_PRId32 "\n", this, fRefCount)); 172 return B_OK; 173 } 174 175 176 status_t 177 Node::Release() 178 { 179 TRACE(("%p::Release(), fRefCount = %" B_PRId32 "\n", this, fRefCount)); 180 if (--fRefCount == 0) { 181 TRACE(("delete node: %p\n", this)); 182 delete this; 183 return 1; 184 } 185 186 return B_OK; 187 } 188 189 190 // #pragma mark - 191 192 193 ConsoleNode::ConsoleNode() 194 : Node() 195 { 196 } 197 198 199 ssize_t 200 ConsoleNode::Read(void *buffer, size_t bufferSize) 201 { 202 return ReadAt(NULL, -1, buffer, bufferSize); 203 } 204 205 206 ssize_t 207 ConsoleNode::Write(const void *buffer, size_t bufferSize) 208 { 209 return WriteAt(NULL, -1, buffer, bufferSize); 210 } 211 212 213 // #pragma mark - 214 215 216 Directory::Directory() 217 : Node() 218 { 219 } 220 221 222 ssize_t 223 Directory::ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize) 224 { 225 return B_ERROR; 226 } 227 228 229 ssize_t 230 Directory::WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize) 231 { 232 return B_ERROR; 233 } 234 235 236 int32 237 Directory::Type() const 238 { 239 return S_IFDIR; 240 } 241 242 243 Node* 244 Directory::Lookup(const char* name, bool traverseLinks) 245 { 246 Node* node = LookupDontTraverse(name); 247 if (node == NULL) 248 return NULL; 249 250 if (!traverseLinks || !S_ISLNK(node->Type())) 251 return node; 252 253 // the node is a symbolic link, so we have to resolve the path 254 char* linkPath = (char*)malloc(B_PATH_NAME_LENGTH); 255 if (linkPath == NULL) { 256 node->Release(); 257 return NULL; 258 } 259 260 status_t error = node->ReadLink(linkPath, B_PATH_NAME_LENGTH); 261 262 node->Release(); 263 // we don't need this one anymore 264 265 if (error != B_OK) { 266 free(linkPath); 267 return NULL; 268 } 269 270 // let open_from() do the real work 271 int fd = open_from(this, linkPath, O_RDONLY); 272 if (fd < 0) { 273 free(linkPath); 274 return NULL; 275 } 276 277 free(linkPath); 278 node = get_node_from(fd); 279 if (node != NULL) 280 node->Acquire(); 281 282 close(fd); 283 return node; 284 } 285 286 287 status_t 288 Directory::CreateFile(const char *name, mode_t permissions, Node **_node) 289 { 290 return EROFS; 291 } 292 293 294 // #pragma mark - 295 296 297 MemoryDisk::MemoryDisk(const uint8* data, size_t size, const char* name) 298 : Node(), 299 fData(data), 300 fSize(size) 301 { 302 strlcpy(fName, name, sizeof(fName)); 303 } 304 305 306 ssize_t 307 MemoryDisk::ReadAt(void* cookie, off_t pos, void* buffer, size_t bufferSize) 308 { 309 if (pos < 0) 310 return B_BAD_VALUE; 311 if ((size_t)pos >= fSize) 312 return 0; 313 314 if (pos + bufferSize > fSize) 315 bufferSize = fSize - pos; 316 317 memcpy(buffer, fData + pos, bufferSize); 318 return bufferSize; 319 } 320 321 322 ssize_t 323 MemoryDisk::WriteAt(void* cookie, off_t pos, const void* buffer, 324 size_t bufferSize) 325 { 326 return B_NOT_ALLOWED; 327 } 328 329 330 off_t 331 MemoryDisk::Size() const 332 { 333 return fSize; 334 } 335 336 337 status_t 338 MemoryDisk::GetName(char *nameBuffer, size_t bufferSize) const 339 { 340 if (!nameBuffer) 341 return B_BAD_VALUE; 342 343 strlcpy(nameBuffer, fName, bufferSize); 344 return B_OK; 345 } 346 347 348 // #pragma mark - 349 350 351 Descriptor::Descriptor(Node *node, void *cookie) 352 : 353 fNode(node), 354 fCookie(cookie), 355 fOffset(0), 356 fRefCount(1) 357 { 358 } 359 360 361 Descriptor::~Descriptor() 362 { 363 } 364 365 366 ssize_t 367 Descriptor::Read(void *buffer, size_t bufferSize) 368 { 369 ssize_t bytesRead = fNode->ReadAt(fCookie, fOffset, buffer, bufferSize); 370 if (bytesRead > B_OK) 371 fOffset += bytesRead; 372 373 return bytesRead; 374 } 375 376 377 ssize_t 378 Descriptor::ReadAt(off_t pos, void *buffer, size_t bufferSize) 379 { 380 return fNode->ReadAt(fCookie, pos, buffer, bufferSize); 381 } 382 383 384 ssize_t 385 Descriptor::Write(const void *buffer, size_t bufferSize) 386 { 387 ssize_t bytesWritten = fNode->WriteAt(fCookie, fOffset, buffer, bufferSize); 388 if (bytesWritten > B_OK) 389 fOffset += bytesWritten; 390 391 return bytesWritten; 392 } 393 394 395 ssize_t 396 Descriptor::WriteAt(off_t pos, const void *buffer, size_t bufferSize) 397 { 398 return fNode->WriteAt(fCookie, pos, buffer, bufferSize); 399 } 400 401 402 void 403 Descriptor::Stat(struct stat &stat) 404 { 405 fNode->Stat(stat); 406 } 407 408 409 status_t 410 Descriptor::Seek(off_t position, int mode) 411 { 412 off_t newPosition; 413 switch (mode) 414 { 415 case SEEK_SET: 416 newPosition = position; 417 break; 418 case SEEK_CUR: 419 newPosition = fOffset + position; 420 break; 421 case SEEK_END: 422 { 423 struct stat st; 424 Stat(st); 425 newPosition = st.st_size + position; 426 break; 427 } 428 default: 429 return B_BAD_VALUE; 430 } 431 432 if (newPosition < 0) 433 return B_BAD_VALUE; 434 435 fOffset = newPosition; 436 return B_OK; 437 } 438 439 440 status_t 441 Descriptor::Acquire() 442 { 443 fRefCount++; 444 return B_OK; 445 } 446 447 448 status_t 449 Descriptor::Release() 450 { 451 if (--fRefCount == 0) { 452 status_t status = fNode->Close(fCookie); 453 if (status != B_OK) 454 return status; 455 } 456 457 return B_OK; 458 } 459 460 461 // #pragma mark - 462 463 464 BootVolume::BootVolume() 465 : 466 fRootDirectory(NULL), 467 fSystemDirectory(NULL), 468 fPackageVolumeInfo(NULL), 469 fPackageVolumeState(NULL) 470 { 471 } 472 473 474 BootVolume::~BootVolume() 475 { 476 Unset(); 477 } 478 479 480 status_t 481 BootVolume::SetTo(Directory* rootDirectory, 482 PackageVolumeInfo* packageVolumeInfo, 483 PackageVolumeState* packageVolumeState) 484 { 485 Unset(); 486 487 status_t error = _SetTo(rootDirectory, packageVolumeInfo, 488 packageVolumeState); 489 if (error != B_OK) 490 Unset(); 491 492 return error; 493 } 494 495 496 void 497 BootVolume::Unset() 498 { 499 if (fRootDirectory != NULL) { 500 fRootDirectory->Release(); 501 fRootDirectory = NULL; 502 } 503 504 if (fSystemDirectory != NULL) { 505 fSystemDirectory->Release(); 506 fSystemDirectory = NULL; 507 } 508 509 if (fPackageVolumeInfo != NULL) { 510 fPackageVolumeInfo->ReleaseReference(); 511 fPackageVolumeInfo = NULL; 512 fPackageVolumeState = NULL; 513 } 514 } 515 516 517 status_t 518 BootVolume::_SetTo(Directory* rootDirectory, 519 PackageVolumeInfo* packageVolumeInfo, 520 PackageVolumeState* packageVolumeState) 521 { 522 Unset(); 523 524 if (rootDirectory == NULL) 525 return B_BAD_VALUE; 526 527 fRootDirectory = rootDirectory; 528 fRootDirectory->Acquire(); 529 530 // find the system directory 531 Node* systemNode = fRootDirectory->Lookup("system", true); 532 if (systemNode == NULL || !S_ISDIR(systemNode->Type())) { 533 if (systemNode != NULL) 534 systemNode->Release(); 535 Unset(); 536 return B_ENTRY_NOT_FOUND; 537 } 538 539 fSystemDirectory = static_cast<Directory*>(systemNode); 540 541 if (packageVolumeInfo == NULL) { 542 // get a package volume info 543 BReference<PackageVolumeInfo> packageVolumeInfoReference( 544 new(std::nothrow) PackageVolumeInfo); 545 status_t error = packageVolumeInfoReference->SetTo(fSystemDirectory, 546 "packages"); 547 if (error != B_OK) { 548 // apparently not packaged 549 return B_OK; 550 } 551 552 fPackageVolumeInfo = packageVolumeInfoReference.Detach(); 553 } else { 554 fPackageVolumeInfo = packageVolumeInfo; 555 fPackageVolumeInfo->AcquireReference(); 556 } 557 558 fPackageVolumeState = packageVolumeState != NULL 559 ? packageVolumeState : fPackageVolumeInfo->States().Head(); 560 561 // try opening the system package 562 int packageFD = _OpenSystemPackage(); 563 if (packageFD < 0) 564 return packageFD; 565 566 // mount packagefs 567 Directory* packageRootDirectory; 568 status_t error = packagefs_mount_file(packageFD, fSystemDirectory, 569 packageRootDirectory); 570 close(packageFD); 571 if (error != B_OK) { 572 Unset(); 573 return error; 574 } 575 576 fSystemDirectory->Release(); 577 fSystemDirectory = packageRootDirectory; 578 579 return B_OK; 580 } 581 582 583 int 584 BootVolume::_OpenSystemPackage() 585 { 586 // open the packages directory 587 Node* packagesNode = fSystemDirectory->Lookup("packages", false); 588 if (packagesNode == NULL) 589 return -1; 590 MethodDeleter<Node, status_t, &Node::Release> 591 packagesNodeReleaser(packagesNode); 592 593 if (!S_ISDIR(packagesNode->Type())) 594 return -1; 595 Directory* packageDirectory = (Directory*)packagesNode; 596 597 // open the system package 598 return open_from(packageDirectory, fPackageVolumeState->SystemPackage(), 599 O_RDONLY); 600 } 601 602 603 // #pragma mark - 604 605 606 status_t 607 vfs_init(stage2_args *args) 608 { 609 gRoot = new(nothrow) RootFileSystem(); 610 if (gRoot == NULL) 611 return B_NO_MEMORY; 612 613 return B_OK; 614 } 615 616 617 status_t 618 register_boot_file_system(BootVolume& bootVolume) 619 { 620 Directory* rootDirectory = bootVolume.RootDirectory(); 621 gRoot->AddLink("boot", rootDirectory); 622 623 Partition *partition; 624 status_t status = gRoot->GetPartitionFor(rootDirectory, &partition); 625 if (status != B_OK) { 626 dprintf("register_boot_file_system(): could not locate boot volume in " 627 "root!\n"); 628 return status; 629 } 630 631 gBootVolume.SetInt64(BOOT_VOLUME_PARTITION_OFFSET, 632 partition->offset); 633 634 if (bootVolume.IsPackaged()) { 635 gBootVolume.SetBool(BOOT_VOLUME_PACKAGED, true); 636 PackageVolumeState* state = bootVolume.GetPackageVolumeState(); 637 if (state->Name() != NULL) 638 gBootVolume.AddString(BOOT_VOLUME_PACKAGES_STATE, state->Name()); 639 } 640 641 Node *device = get_node_from(partition->FD()); 642 if (device == NULL) { 643 dprintf("register_boot_file_system(): could not get boot device!\n"); 644 return B_ERROR; 645 } 646 647 return platform_register_boot_device(device); 648 } 649 650 651 /*! Gets the boot device, scans all of its partitions, gets the 652 boot partition, and mounts its file system. 653 654 \param args The stage 2 arguments. 655 \param _bootVolume On success set to the boot volume. 656 \return \c B_OK on success, another error code otherwise. 657 */ 658 status_t 659 get_boot_file_system(stage2_args* args, BootVolume& _bootVolume) 660 { 661 status_t error = platform_add_boot_device(args, &gBootDevices); 662 if (error != B_OK) 663 return error; 664 665 NodeIterator iterator = gBootDevices.GetIterator(); 666 while (iterator.HasNext()) { 667 Node *device = iterator.Next(); 668 669 error = add_partitions_for(device, false, true); 670 if (error != B_OK) 671 continue; 672 673 NodeList bootPartitions; 674 error = platform_get_boot_partitions(args, device, &gPartitions, &bootPartitions); 675 if (error != B_OK) 676 continue; 677 678 NodeIterator partitionIterator = bootPartitions.GetIterator(); 679 while (partitionIterator.HasNext()) { 680 Partition *partition = (Partition*)partitionIterator.Next(); 681 682 Directory *fileSystem; 683 error = partition->Mount(&fileSystem, true); 684 if (error != B_OK) { 685 // this partition doesn't contain any known file system; we 686 // don't need it anymore 687 gPartitions.Remove(partition); 688 delete partition; 689 continue; 690 } 691 692 // init the BootVolume 693 error = _bootVolume.SetTo(fileSystem); 694 if (error != B_OK) 695 continue; 696 697 sBootDevice = device; 698 return B_OK; 699 } 700 } 701 702 return B_ERROR; 703 } 704 705 706 /** Mounts all file systems recognized on the given device by 707 * calling the add_partitions_for() function on them. 708 */ 709 710 status_t 711 mount_file_systems(stage2_args *args) 712 { 713 // mount other partitions on boot device (if any) 714 NodeIterator iterator = gPartitions.GetIterator(); 715 716 Partition *partition = NULL; 717 while ((partition = (Partition *)iterator.Next()) != NULL) { 718 // don't scan known partitions again 719 if (partition->IsFileSystem()) 720 continue; 721 722 // remove the partition if it doesn't contain a (known) file system 723 if (partition->Scan(true) != B_OK && !partition->IsFileSystem()) { 724 gPartitions.Remove(partition); 725 delete partition; 726 } 727 } 728 729 // add all block devices the platform has for us 730 731 status_t status = platform_add_block_devices(args, &gBootDevices); 732 if (status < B_OK) 733 return status; 734 735 iterator = gBootDevices.GetIterator(); 736 Node *device = NULL, *last = NULL; 737 while ((device = iterator.Next()) != NULL) { 738 // don't scan former boot device again 739 if (device == sBootDevice) 740 continue; 741 742 if (add_partitions_for(device, true) == B_OK) { 743 // ToDo: we can't delete the object here, because it must 744 // be removed from the list before we know that it was 745 // deleted. 746 747 /* // if the Release() deletes the object, we need to skip it 748 if (device->Release() > 0) { 749 list_remove_item(&gBootDevices, device); 750 device = last; 751 } 752 */ 753 (void)last; 754 } 755 last = device; 756 } 757 758 if (gPartitions.IsEmpty()) 759 return B_ENTRY_NOT_FOUND; 760 761 #if 0 762 void *cookie; 763 if (gRoot->Open(&cookie, O_RDONLY) == B_OK) { 764 Directory *directory; 765 while (gRoot->GetNextNode(cookie, (Node **)&directory) == B_OK) { 766 char name[256]; 767 if (directory->GetName(name, sizeof(name)) == B_OK) 768 printf(":: %s (%p)\n", name, directory); 769 770 void *subCookie; 771 if (directory->Open(&subCookie, O_RDONLY) == B_OK) { 772 while (directory->GetNextEntry(subCookie, name, sizeof(name)) == B_OK) { 773 printf("\t%s\n", name); 774 } 775 directory->Close(subCookie); 776 } 777 } 778 gRoot->Close(cookie); 779 } 780 #endif 781 782 return B_OK; 783 } 784 785 786 /*! Resolves \a directory + \a path to a node. 787 Note that \a path will be modified by the function. 788 */ 789 static status_t 790 get_node_for_path(Directory *directory, char *path, Node **_node) 791 { 792 directory->Acquire(); 793 // balance Acquire()/Release() calls 794 795 while (true) { 796 Node *nextNode; 797 char *nextPath; 798 799 // walk to find the next path component ("path" will point to a single 800 // path component), and filter out multiple slashes 801 for (nextPath = path + 1; nextPath[0] != '\0' && nextPath[0] != '/'; nextPath++); 802 803 if (*nextPath == '/') { 804 *nextPath = '\0'; 805 do 806 nextPath++; 807 while (*nextPath == '/'); 808 } 809 810 nextNode = directory->Lookup(path, true); 811 directory->Release(); 812 813 if (nextNode == NULL) 814 return B_ENTRY_NOT_FOUND; 815 816 path = nextPath; 817 if (S_ISDIR(nextNode->Type())) 818 directory = (Directory *)nextNode; 819 else if (path[0]) 820 return B_NOT_ALLOWED; 821 822 // are we done? 823 if (path[0] == '\0') { 824 *_node = nextNode; 825 return B_OK; 826 } 827 } 828 829 return B_ENTRY_NOT_FOUND; 830 } 831 832 833 /*! Version of get_node_for_path() not modifying \a path. 834 */ 835 static status_t 836 get_node_for_path(Directory* directory, const char* path, Node** _node) 837 { 838 char* mutablePath = strdup(path); 839 if (mutablePath == NULL) 840 return B_NO_MEMORY; 841 MemoryDeleter mutablePathDeleter(mutablePath); 842 843 return get_node_for_path(directory, mutablePath, _node); 844 } 845 846 // #pragma mark - 847 848 849 static Descriptor * 850 get_descriptor(int fd) 851 { 852 if (fd < 0 || fd >= MAX_VFS_DESCRIPTORS) 853 return NULL; 854 855 return sDescriptors[fd]; 856 } 857 858 859 static void 860 free_descriptor(int fd) 861 { 862 if (fd >= MAX_VFS_DESCRIPTORS) 863 return; 864 865 delete sDescriptors[fd]; 866 sDescriptors[fd] = NULL; 867 } 868 869 870 /** Reserves an entry of the descriptor table and 871 * assigns the given node to it. 872 */ 873 874 int 875 open_node(Node *node, int mode) 876 { 877 if (node == NULL) 878 return B_ERROR; 879 880 // get free descriptor 881 882 int fd = 0; 883 for (; fd < MAX_VFS_DESCRIPTORS; fd++) { 884 if (sDescriptors[fd] == NULL) 885 break; 886 } 887 if (fd == MAX_VFS_DESCRIPTORS) 888 return B_ERROR; 889 890 TRACE(("got descriptor %d for node %p\n", fd, node)); 891 892 // we got a free descriptor entry, now try to open the node 893 894 void *cookie; 895 status_t status = node->Open(&cookie, mode); 896 if (status < B_OK) 897 return status; 898 899 TRACE(("could open node at %p\n", node)); 900 901 Descriptor *descriptor = new(nothrow) Descriptor(node, cookie); 902 if (descriptor == NULL) 903 return B_NO_MEMORY; 904 905 sDescriptors[fd] = descriptor; 906 907 return fd; 908 } 909 910 911 int 912 dup(int fd) 913 { 914 Descriptor *descriptor = get_descriptor(fd); 915 if (descriptor == NULL) 916 RETURN_AND_SET_ERRNO(B_FILE_ERROR); 917 918 descriptor->Acquire(); 919 RETURN_AND_SET_ERRNO(fd); 920 } 921 922 923 off_t 924 lseek(int fd, off_t offset, int whence) 925 { 926 Descriptor* descriptor = get_descriptor(fd); 927 if (descriptor == NULL) 928 RETURN_AND_SET_ERRNO(B_FILE_ERROR); 929 930 status_t error = descriptor->Seek(offset, whence); 931 if (error != B_OK) 932 RETURN_AND_SET_ERRNO(B_FILE_ERROR); 933 934 return descriptor->Offset(); 935 } 936 937 938 int 939 ftruncate(int fd, off_t newSize) 940 { 941 dprintf("ftruncate() not implemented!\n"); 942 RETURN_AND_SET_ERRNO(B_FILE_ERROR); 943 } 944 945 946 ssize_t 947 read_pos(int fd, off_t offset, void *buffer, size_t bufferSize) 948 { 949 Descriptor *descriptor = get_descriptor(fd); 950 if (descriptor == NULL) 951 RETURN_AND_SET_ERRNO(B_FILE_ERROR); 952 953 RETURN_AND_SET_ERRNO(descriptor->ReadAt(offset, buffer, bufferSize)); 954 } 955 956 957 ssize_t 958 pread(int fd, void* buffer, size_t bufferSize, off_t offset) 959 { 960 return read_pos(fd, offset, buffer, bufferSize); 961 } 962 963 964 ssize_t 965 read(int fd, void *buffer, size_t bufferSize) 966 { 967 Descriptor *descriptor = get_descriptor(fd); 968 if (descriptor == NULL) 969 RETURN_AND_SET_ERRNO(B_FILE_ERROR); 970 971 RETURN_AND_SET_ERRNO(descriptor->Read(buffer, bufferSize)); 972 } 973 974 975 ssize_t 976 write_pos(int fd, off_t offset, const void *buffer, size_t bufferSize) 977 { 978 Descriptor *descriptor = get_descriptor(fd); 979 if (descriptor == NULL) 980 RETURN_AND_SET_ERRNO(B_FILE_ERROR); 981 982 RETURN_AND_SET_ERRNO(descriptor->WriteAt(offset, buffer, bufferSize)); 983 } 984 985 986 ssize_t 987 pwrite(int fd, const void* buffer, size_t bufferSize, off_t offset) 988 { 989 return write_pos(fd, offset, buffer, bufferSize); 990 } 991 992 993 ssize_t 994 write(int fd, const void *buffer, size_t bufferSize) 995 { 996 Descriptor *descriptor = get_descriptor(fd); 997 if (descriptor == NULL) 998 RETURN_AND_SET_ERRNO(B_FILE_ERROR); 999 1000 RETURN_AND_SET_ERRNO(descriptor->Write(buffer, bufferSize)); 1001 } 1002 1003 1004 ssize_t 1005 writev(int fd, const struct iovec* vecs, int count) 1006 { 1007 size_t totalWritten = 0; 1008 1009 if (count < 0) 1010 RETURN_AND_SET_ERRNO(B_BAD_VALUE); 1011 1012 for (int i = 0; i < count; i++) { 1013 ssize_t written = write(fd, vecs[i].iov_base, vecs[i].iov_len); 1014 if (written < 0) 1015 return totalWritten == 0 ? written : totalWritten; 1016 1017 totalWritten += written; 1018 1019 if ((size_t)written != vecs[i].iov_len) 1020 break; 1021 } 1022 1023 return totalWritten; 1024 } 1025 1026 1027 int 1028 open(const char *name, int mode, ...) 1029 { 1030 mode_t permissions = 0; 1031 if ((mode & O_CREAT) != 0) { 1032 va_list args; 1033 va_start(args, mode); 1034 permissions = va_arg(args, int) /*& ~__gUmask*/; 1035 // adapt the permissions as required by POSIX 1036 va_end(args); 1037 } 1038 1039 // we always start at the top (there is no notion of a current directory (yet?)) 1040 RETURN_AND_SET_ERRNO(open_from(gRoot, name, mode, permissions)); 1041 } 1042 1043 1044 int 1045 open_from(Directory *directory, const char *name, int mode, mode_t permissions) 1046 { 1047 if (name[0] == '/') { 1048 // ignore the directory and start from root if we are asked to do that 1049 directory = gRoot; 1050 name++; 1051 } 1052 1053 char* path = (char*)malloc(B_PATH_NAME_LENGTH); 1054 if (path == NULL) 1055 return B_NO_MEMORY; 1056 1057 if (strlcpy(path, name, B_PATH_NAME_LENGTH) >= B_PATH_NAME_LENGTH) { 1058 free(path); 1059 return B_NAME_TOO_LONG; 1060 } 1061 1062 Node *node; 1063 status_t error = get_node_for_path(directory, path, &node); 1064 if (error != B_OK) { 1065 if (error != B_ENTRY_NOT_FOUND) { 1066 free(path); 1067 return error; 1068 } 1069 1070 if ((mode & O_CREAT) == 0) { 1071 free(path); 1072 return B_ENTRY_NOT_FOUND; 1073 } 1074 1075 // try to resolve the parent directory 1076 strlcpy(path, name, B_PATH_NAME_LENGTH); 1077 if (char* lastSlash = strrchr(path, '/')) { 1078 if (lastSlash[1] == '\0') { 1079 free(path); 1080 return B_ENTRY_NOT_FOUND; 1081 } 1082 1083 *lastSlash = '\0'; 1084 name = lastSlash + 1; 1085 1086 // resolve the directory 1087 if (get_node_for_path(directory, path, &node) != B_OK) { 1088 free(path); 1089 return B_ENTRY_NOT_FOUND; 1090 } 1091 1092 if (node->Type() != S_IFDIR) { 1093 node->Release(); 1094 free(path); 1095 return B_NOT_A_DIRECTORY; 1096 } 1097 1098 directory = static_cast<Directory*>(node); 1099 } else 1100 directory->Acquire(); 1101 1102 // create the file 1103 error = directory->CreateFile(name, permissions, &node); 1104 directory->Release(); 1105 1106 if (error != B_OK) { 1107 free(path); 1108 return error; 1109 } 1110 } else if ((mode & O_EXCL) != 0) { 1111 node->Release(); 1112 free(path); 1113 return B_FILE_EXISTS; 1114 } 1115 1116 int fd = open_node(node, mode); 1117 1118 node->Release(); 1119 free(path); 1120 return fd; 1121 } 1122 1123 1124 /** Since we don't have directory functions yet, this 1125 * function is needed to get the contents of a directory. 1126 * It should be removed once readdir() & co. are in place. 1127 */ 1128 1129 Node * 1130 get_node_from(int fd) 1131 { 1132 Descriptor *descriptor = get_descriptor(fd); 1133 if (descriptor == NULL) 1134 return NULL; 1135 1136 return descriptor->GetNode(); 1137 } 1138 1139 1140 status_t 1141 get_stat(Directory* directory, const char* path, struct stat& st) 1142 { 1143 Node* node; 1144 status_t error = get_node_for_path(directory, path, &node); 1145 if (error != B_OK) 1146 return error; 1147 1148 node->Stat(st); 1149 node->Release(); 1150 return B_OK; 1151 } 1152 1153 1154 Directory* 1155 directory_from(DIR* dir) 1156 { 1157 return dir != NULL ? dir->directory : NULL; 1158 } 1159 1160 1161 int 1162 close(int fd) 1163 { 1164 Descriptor *descriptor = get_descriptor(fd); 1165 if (descriptor == NULL) 1166 RETURN_AND_SET_ERRNO(B_FILE_ERROR); 1167 1168 status_t status = descriptor->Release(); 1169 if (!descriptor->RefCount()) 1170 free_descriptor(fd); 1171 1172 RETURN_AND_SET_ERRNO(status); 1173 } 1174 1175 1176 // ToDo: remove this kludge when possible 1177 int 1178 #if defined(fstat) && !defined(main) 1179 _fstat(int fd, struct stat *stat, size_t /*statSize*/) 1180 #else 1181 fstat(int fd, struct stat *stat) 1182 #endif 1183 { 1184 if (stat == NULL) 1185 RETURN_AND_SET_ERRNO(B_BAD_VALUE); 1186 1187 Descriptor *descriptor = get_descriptor(fd); 1188 if (descriptor == NULL) 1189 RETURN_AND_SET_ERRNO(B_FILE_ERROR); 1190 1191 descriptor->Stat(*stat); 1192 return 0; 1193 } 1194 1195 1196 DIR* 1197 open_directory(Directory* baseDirectory, const char* path) 1198 { 1199 DIR* dir = new(std::nothrow) DIR; 1200 if (dir == NULL) { 1201 errno = B_NO_MEMORY; 1202 return NULL; 1203 } 1204 ObjectDeleter<DIR> dirDeleter(dir); 1205 1206 Node* node; 1207 status_t error = get_node_for_path(baseDirectory, path, &node); 1208 if (error != B_OK) { 1209 errno = error; 1210 return NULL; 1211 } 1212 MethodDeleter<Node, status_t, &Node::Release> nodeReleaser(node); 1213 1214 if (!S_ISDIR(node->Type())) { 1215 errno = error; 1216 return NULL; 1217 } 1218 1219 dir->directory = static_cast<Directory*>(node); 1220 1221 error = dir->directory->Open(&dir->cookie, O_RDONLY); 1222 if (error != B_OK) { 1223 errno = error; 1224 return NULL; 1225 } 1226 1227 nodeReleaser.Detach(); 1228 return dirDeleter.Detach(); 1229 } 1230 1231 1232 DIR* 1233 opendir(const char* dirName) 1234 { 1235 return open_directory(gRoot, dirName); 1236 } 1237 1238 1239 int 1240 closedir(DIR* dir) 1241 { 1242 if (dir != NULL) { 1243 dir->directory->Close(dir->cookie); 1244 dir->directory->Release(); 1245 delete dir; 1246 } 1247 1248 return 0; 1249 } 1250 1251 1252 struct dirent* 1253 readdir(DIR* dir) 1254 { 1255 if (dir == NULL) { 1256 errno = B_BAD_VALUE; 1257 return NULL; 1258 } 1259 1260 for (;;) { 1261 status_t error = dir->directory->GetNextEntry(dir->cookie, 1262 dir->entry()->d_name, B_FILE_NAME_LENGTH); 1263 if (error != B_OK) { 1264 errno = error; 1265 return NULL; 1266 } 1267 1268 dir->entry()->d_pdev = 0; 1269 // not supported 1270 dir->entry()->d_pino = dir->directory->Inode(); 1271 dir->entry()->d_dev = dir->entry()->d_pdev; 1272 // not supported 1273 1274 if (strcmp(dir->entry()->d_name, ".") == 0 1275 || strcmp(dir->entry()->d_name, "..") == 0) { 1276 // Note: That's obviously not correct for "..", but we can't 1277 // retrieve that information. 1278 dir->entry()->d_ino = dir->entry()->d_pino; 1279 } else { 1280 Node* node = dir->directory->Lookup(dir->entry()->d_name, false); 1281 if (node == NULL) 1282 continue; 1283 1284 dir->entry()->d_ino = node->Inode(); 1285 node->Release(); 1286 } 1287 1288 return dir->entry(); 1289 } 1290 } 1291 1292 1293 void 1294 rewinddir(DIR* dir) 1295 { 1296 if (dir == NULL) { 1297 errno = B_BAD_VALUE; 1298 return; 1299 } 1300 1301 status_t error = dir->directory->Rewind(dir->cookie); 1302 if (error != B_OK) 1303 errno = error; 1304 } 1305