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