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