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