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