1 /* 2 * Copyright 2003-2008, Axel Dörfler, axeld@pinc-software.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include <boot/vfs.h> 8 9 #include <errno.h> 10 #include <fcntl.h> 11 #include <string.h> 12 #include <sys/uio.h> 13 #include <unistd.h> 14 15 #include <StorageDefs.h> 16 17 #include <boot/platform.h> 18 #include <boot/partitions.h> 19 #include <boot/stdio.h> 20 #include <boot/stage2.h> 21 #include <util/kernel_cpp.h> 22 #include <syscall_utils.h> 23 24 #include "RootFileSystem.h" 25 26 27 using namespace boot; 28 29 //#define TRACE_VFS 30 #ifdef TRACE_VFS 31 # define TRACE(x) dprintf x 32 #else 33 # define TRACE(x) ; 34 #endif 35 36 37 class Descriptor { 38 public: 39 Descriptor(Node *node, void *cookie); 40 ~Descriptor(); 41 42 ssize_t ReadAt(off_t pos, void *buffer, size_t bufferSize); 43 ssize_t Read(void *buffer, size_t bufferSize); 44 ssize_t WriteAt(off_t pos, const void *buffer, size_t bufferSize); 45 ssize_t Write(const void *buffer, size_t bufferSize); 46 47 status_t Stat(struct stat &stat); 48 49 off_t Offset() const { return fOffset; } 50 int32 RefCount() const { return fRefCount; } 51 52 status_t Acquire(); 53 status_t Release(); 54 55 Node *GetNode() const { return fNode; } 56 57 private: 58 Node *fNode; 59 void *fCookie; 60 off_t fOffset; 61 int32 fRefCount; 62 }; 63 64 #define MAX_VFS_DESCRIPTORS 64 65 66 NodeList gBootDevices; 67 NodeList gPartitions; 68 RootFileSystem *gRoot; 69 static Descriptor *sDescriptors[MAX_VFS_DESCRIPTORS]; 70 static Node *sBootDevice; 71 72 73 Node::Node() 74 : 75 fRefCount(1) 76 { 77 } 78 79 80 Node::~Node() 81 { 82 } 83 84 85 status_t 86 Node::Open(void **_cookie, int mode) 87 { 88 TRACE(("%p::Open()\n", this)); 89 return Acquire(); 90 } 91 92 93 status_t 94 Node::Close(void *cookie) 95 { 96 TRACE(("%p::Close()\n", this)); 97 return Release(); 98 } 99 100 101 status_t 102 Node::GetName(char *nameBuffer, size_t bufferSize) const 103 { 104 return B_ERROR; 105 } 106 107 108 status_t 109 Node::GetFileMap(struct file_map_run *runs, int32 *count) 110 { 111 return B_ERROR; 112 } 113 114 115 int32 116 Node::Type() const 117 { 118 return 0; 119 } 120 121 122 off_t 123 Node::Size() const 124 { 125 return 0LL; 126 } 127 128 129 ino_t 130 Node::Inode() const 131 { 132 return 0; 133 } 134 135 136 status_t 137 Node::Acquire() 138 { 139 fRefCount++; 140 TRACE(("%p::Acquire(), fRefCount = %ld\n", this, fRefCount)); 141 return B_OK; 142 } 143 144 145 status_t 146 Node::Release() 147 { 148 TRACE(("%p::Release(), fRefCount = %ld\n", this, fRefCount)); 149 if (--fRefCount == 0) { 150 TRACE(("delete node: %p\n", this)); 151 delete this; 152 return 1; 153 } 154 155 return B_OK; 156 } 157 158 159 // #pragma mark - 160 161 162 ConsoleNode::ConsoleNode() 163 : Node() 164 { 165 } 166 167 168 ssize_t 169 ConsoleNode::Read(void *buffer, size_t bufferSize) 170 { 171 return ReadAt(NULL, -1, buffer, bufferSize); 172 } 173 174 175 ssize_t 176 ConsoleNode::Write(const void *buffer, size_t bufferSize) 177 { 178 return WriteAt(NULL, -1, buffer, bufferSize); 179 } 180 181 182 // #pragma mark - 183 184 185 Directory::Directory() 186 : Node() 187 { 188 } 189 190 191 ssize_t 192 Directory::ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize) 193 { 194 return B_ERROR; 195 } 196 197 198 ssize_t 199 Directory::WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize) 200 { 201 return B_ERROR; 202 } 203 204 205 int32 206 Directory::Type() const 207 { 208 return S_IFDIR; 209 } 210 211 212 status_t 213 Directory::CreateFile(const char *name, mode_t permissions, Node **_node) 214 { 215 return EROFS; 216 } 217 218 219 // #pragma mark - 220 221 222 MemoryDisk::MemoryDisk(const uint8* data, size_t size, const char* name) 223 : Node(), 224 fData(data), 225 fSize(size) 226 { 227 strlcpy(fName, name, sizeof(fName)); 228 } 229 230 231 ssize_t 232 MemoryDisk::ReadAt(void* cookie, off_t pos, void* buffer, size_t bufferSize) 233 { 234 if (pos >= fSize) 235 return 0; 236 237 if (pos + bufferSize > fSize) 238 bufferSize = fSize - pos; 239 240 memcpy(buffer, fData + pos, bufferSize); 241 return bufferSize; 242 } 243 244 245 ssize_t 246 MemoryDisk::WriteAt(void* cookie, off_t pos, const void* buffer, 247 size_t bufferSize) 248 { 249 return B_NOT_ALLOWED; 250 } 251 252 253 off_t 254 MemoryDisk::Size() const 255 { 256 return fSize; 257 } 258 259 260 status_t 261 MemoryDisk::GetName(char *nameBuffer, size_t bufferSize) const 262 { 263 if (!nameBuffer) 264 return B_BAD_VALUE; 265 266 strlcpy(nameBuffer, fName, bufferSize); 267 return B_OK; 268 } 269 270 271 // #pragma mark - 272 273 274 Descriptor::Descriptor(Node *node, void *cookie) 275 : 276 fNode(node), 277 fCookie(cookie), 278 fOffset(0), 279 fRefCount(1) 280 { 281 } 282 283 284 Descriptor::~Descriptor() 285 { 286 } 287 288 289 ssize_t 290 Descriptor::Read(void *buffer, size_t bufferSize) 291 { 292 ssize_t bytesRead = fNode->ReadAt(fCookie, fOffset, buffer, bufferSize); 293 if (bytesRead > B_OK) 294 fOffset += bytesRead; 295 296 return bytesRead; 297 } 298 299 300 ssize_t 301 Descriptor::ReadAt(off_t pos, void *buffer, size_t bufferSize) 302 { 303 return fNode->ReadAt(fCookie, pos, buffer, bufferSize); 304 } 305 306 307 ssize_t 308 Descriptor::Write(const void *buffer, size_t bufferSize) 309 { 310 ssize_t bytesWritten = fNode->WriteAt(fCookie, fOffset, buffer, bufferSize); 311 if (bytesWritten > B_OK) 312 fOffset += bytesWritten; 313 314 return bytesWritten; 315 } 316 317 318 ssize_t 319 Descriptor::WriteAt(off_t pos, const void *buffer, size_t bufferSize) 320 { 321 return fNode->WriteAt(fCookie, pos, buffer, bufferSize); 322 } 323 324 325 status_t 326 Descriptor::Stat(struct stat &stat) 327 { 328 stat.st_mode = fNode->Type(); 329 stat.st_size = fNode->Size(); 330 stat.st_ino = fNode->Inode(); 331 332 return B_OK; 333 } 334 335 336 status_t 337 Descriptor::Acquire() 338 { 339 fRefCount++; 340 return B_OK; 341 } 342 343 344 status_t 345 Descriptor::Release() 346 { 347 if (--fRefCount == 0) { 348 status_t status = fNode->Close(fCookie); 349 if (status != B_OK) 350 return status; 351 } 352 353 return B_OK; 354 } 355 356 357 // #pragma mark - 358 359 360 status_t 361 vfs_init(stage2_args *args) 362 { 363 gRoot = new(nothrow) RootFileSystem(); 364 if (gRoot == NULL) 365 return B_NO_MEMORY; 366 367 return B_OK; 368 } 369 370 371 status_t 372 register_boot_file_system(Directory *volume) 373 { 374 gRoot->AddLink("boot", volume); 375 376 Partition *partition; 377 status_t status = gRoot->GetPartitionFor(volume, &partition); 378 if (status != B_OK) { 379 dprintf("register_boot_file_system(): could not locate boot volume in root!\n"); 380 return status; 381 } 382 383 gKernelArgs.boot_volume.SetInt64(BOOT_VOLUME_PARTITION_OFFSET, 384 partition->offset); 385 386 Node *device = get_node_from(partition->FD()); 387 if (device == NULL) { 388 dprintf("register_boot_file_system(): could not get boot device!\n"); 389 return B_ERROR; 390 } 391 392 return platform_register_boot_device(device); 393 } 394 395 396 /** Gets the boot device, scans all of its partitions, gets the 397 * boot partition, and mounts its file system. 398 * Returns the file system's root node or NULL for failure. 399 */ 400 401 Directory * 402 get_boot_file_system(stage2_args *args) 403 { 404 Node *device; 405 if (platform_add_boot_device(args, &gBootDevices) < B_OK) 406 return NULL; 407 408 // the boot device must be the first device in the list 409 device = gBootDevices.First(); 410 411 if (add_partitions_for(device, false, true) < B_OK) 412 return NULL; 413 414 Partition *partition; 415 if (platform_get_boot_partition(args, device, &gPartitions, &partition) < B_OK) 416 return NULL; 417 418 Directory *fileSystem; 419 status_t status = partition->Mount(&fileSystem, true); 420 421 if (status < B_OK) { 422 // this partition doesn't contain any known file system; we 423 // don't need it anymore 424 gPartitions.Remove(partition); 425 delete partition; 426 return NULL; 427 } 428 429 sBootDevice = device; 430 return fileSystem; 431 } 432 433 434 /** Mounts all file systems recognized on the given device by 435 * calling the add_partitions_for() function on them. 436 */ 437 438 status_t 439 mount_file_systems(stage2_args *args) 440 { 441 // mount other partitions on boot device (if any) 442 NodeIterator iterator = gPartitions.GetIterator(); 443 444 Partition *partition = NULL; 445 while ((partition = (Partition *)iterator.Next()) != NULL) { 446 // don't scan known partitions again 447 if (partition->IsFileSystem()) 448 continue; 449 450 // remove the partition if it doesn't contain a (known) file system 451 if (partition->Scan(true) != B_OK && !partition->IsFileSystem()) { 452 gPartitions.Remove(partition); 453 delete partition; 454 } 455 } 456 457 // add all block devices the platform has for us 458 459 status_t status = platform_add_block_devices(args, &gBootDevices); 460 if (status < B_OK) 461 return status; 462 463 iterator = gBootDevices.GetIterator(); 464 Node *device = NULL, *last = NULL; 465 while ((device = iterator.Next()) != NULL) { 466 // don't scan former boot device again 467 if (device == sBootDevice) 468 continue; 469 470 if (add_partitions_for(device, true) == B_OK) { 471 // ToDo: we can't delete the object here, because it must 472 // be removed from the list before we know that it was 473 // deleted. 474 475 /* // if the Release() deletes the object, we need to skip it 476 if (device->Release() > 0) { 477 list_remove_item(&gBootDevices, device); 478 device = last; 479 } 480 */ 481 } 482 last = device; 483 } 484 485 if (gPartitions.IsEmpty()) 486 return B_ENTRY_NOT_FOUND; 487 488 #if 0 489 void *cookie; 490 if (gRoot->Open(&cookie, O_RDONLY) == B_OK) { 491 Directory *directory; 492 while (gRoot->GetNextNode(cookie, (Node **)&directory) == B_OK) { 493 char name[256]; 494 if (directory->GetName(name, sizeof(name)) == B_OK) 495 printf(":: %s (%p)\n", name, directory); 496 497 void *subCookie; 498 if (directory->Open(&subCookie, O_RDONLY) == B_OK) { 499 while (directory->GetNextEntry(subCookie, name, sizeof(name)) == B_OK) { 500 printf("\t%s\n", name); 501 } 502 directory->Close(subCookie); 503 } 504 } 505 gRoot->Close(cookie); 506 } 507 #endif 508 509 return B_OK; 510 } 511 512 513 /*! Resolves \a directory + \a path to a node. 514 Note that \a path will be modified by the function. 515 */ 516 static status_t 517 get_node_for_path(Directory *directory, char *path, Node **_node) 518 { 519 directory->Acquire(); 520 // balance Acquire()/Release() calls 521 522 while (true) { 523 Node *nextNode; 524 char *nextPath; 525 526 // walk to find the next path component ("path" will point to a single 527 // path component), and filter out multiple slashes 528 for (nextPath = path + 1; nextPath[0] != '\0' && nextPath[0] != '/'; nextPath++); 529 530 if (*nextPath == '/') { 531 *nextPath = '\0'; 532 do 533 nextPath++; 534 while (*nextPath == '/'); 535 } 536 537 nextNode = directory->Lookup(path, true); 538 directory->Release(); 539 540 if (nextNode == NULL) 541 return B_ENTRY_NOT_FOUND; 542 543 path = nextPath; 544 if (S_ISDIR(nextNode->Type())) 545 directory = (Directory *)nextNode; 546 else if (path[0]) 547 return B_NOT_ALLOWED; 548 549 // are we done? 550 if (path[0] == '\0') { 551 *_node = nextNode; 552 return B_OK; 553 } 554 } 555 556 return B_ENTRY_NOT_FOUND; 557 } 558 559 560 // #pragma mark - 561 562 563 static Descriptor * 564 get_descriptor(int fd) 565 { 566 if (fd < 0 || fd >= MAX_VFS_DESCRIPTORS) 567 return NULL; 568 569 return sDescriptors[fd]; 570 } 571 572 573 static void 574 free_descriptor(int fd) 575 { 576 if (fd >= MAX_VFS_DESCRIPTORS) 577 return; 578 579 delete sDescriptors[fd]; 580 sDescriptors[fd] = NULL; 581 } 582 583 584 /** Reserves an entry of the descriptor table and 585 * assigns the given node to it. 586 */ 587 588 int 589 open_node(Node *node, int mode) 590 { 591 if (node == NULL) 592 return B_ERROR; 593 594 // get free descriptor 595 596 int fd = 0; 597 for (; fd < MAX_VFS_DESCRIPTORS; fd++) { 598 if (sDescriptors[fd] == NULL) 599 break; 600 } 601 if (fd == MAX_VFS_DESCRIPTORS) 602 return B_ERROR; 603 604 TRACE(("got descriptor %d for node %p\n", fd, node)); 605 606 // we got a free descriptor entry, now try to open the node 607 608 void *cookie; 609 status_t status = node->Open(&cookie, mode); 610 if (status < B_OK) 611 return status; 612 613 TRACE(("could open node at %p\n", node)); 614 615 Descriptor *descriptor = new(nothrow) Descriptor(node, cookie); 616 if (descriptor == NULL) 617 return B_NO_MEMORY; 618 619 sDescriptors[fd] = descriptor; 620 621 return fd; 622 } 623 624 625 int 626 dup(int fd) 627 { 628 Descriptor *descriptor = get_descriptor(fd); 629 if (descriptor == NULL) 630 RETURN_AND_SET_ERRNO(B_FILE_ERROR); 631 632 descriptor->Acquire(); 633 RETURN_AND_SET_ERRNO(fd); 634 } 635 636 637 ssize_t 638 read_pos(int fd, off_t offset, void *buffer, size_t bufferSize) 639 { 640 Descriptor *descriptor = get_descriptor(fd); 641 if (descriptor == NULL) 642 RETURN_AND_SET_ERRNO(B_FILE_ERROR); 643 644 RETURN_AND_SET_ERRNO(descriptor->ReadAt(offset, buffer, bufferSize)); 645 } 646 647 648 ssize_t 649 read(int fd, void *buffer, size_t bufferSize) 650 { 651 Descriptor *descriptor = get_descriptor(fd); 652 if (descriptor == NULL) 653 RETURN_AND_SET_ERRNO(B_FILE_ERROR); 654 655 RETURN_AND_SET_ERRNO(descriptor->Read(buffer, bufferSize)); 656 } 657 658 659 ssize_t 660 write_pos(int fd, off_t offset, const void *buffer, size_t bufferSize) 661 { 662 Descriptor *descriptor = get_descriptor(fd); 663 if (descriptor == NULL) 664 RETURN_AND_SET_ERRNO(B_FILE_ERROR); 665 666 RETURN_AND_SET_ERRNO(descriptor->WriteAt(offset, buffer, bufferSize)); 667 } 668 669 670 ssize_t 671 write(int fd, const void *buffer, size_t bufferSize) 672 { 673 Descriptor *descriptor = get_descriptor(fd); 674 if (descriptor == NULL) 675 RETURN_AND_SET_ERRNO(B_FILE_ERROR); 676 677 RETURN_AND_SET_ERRNO(descriptor->Write(buffer, bufferSize)); 678 } 679 680 681 ssize_t 682 writev(int fd, const struct iovec* vecs, size_t count) 683 { 684 size_t totalWritten = 0; 685 686 for (size_t i = 0; i < count; i++) { 687 ssize_t written = write(fd, vecs[i].iov_base, vecs[i].iov_len); 688 if (written < 0) 689 return totalWritten == 0 ? written : totalWritten; 690 691 totalWritten += written; 692 693 if ((size_t)written != vecs[i].iov_len) 694 break; 695 } 696 697 return totalWritten; 698 } 699 700 701 int 702 open(const char *name, int mode, ...) 703 { 704 mode_t permissions = 0; 705 if ((mode & O_CREAT) != 0) { 706 va_list args; 707 va_start(args, mode); 708 permissions = va_arg(args, int) /*& ~__gUmask*/; 709 // adapt the permissions as required by POSIX 710 va_end(args); 711 } 712 713 // we always start at the top (there is no notion of a current directory (yet?)) 714 RETURN_AND_SET_ERRNO(open_from(gRoot, name, mode, permissions)); 715 } 716 717 718 int 719 open_from(Directory *directory, const char *name, int mode, mode_t permissions) 720 { 721 if (name[0] == '/') { 722 // ignore the directory and start from root if we are asked to do that 723 directory = gRoot; 724 name++; 725 } 726 727 char path[B_PATH_NAME_LENGTH]; 728 if (strlcpy(path, name, sizeof(path)) >= sizeof(path)) 729 return B_NAME_TOO_LONG; 730 731 Node *node; 732 status_t error = get_node_for_path(directory, path, &node); 733 if (error != B_OK) { 734 if (error != B_ENTRY_NOT_FOUND) 735 return error; 736 737 if ((mode & O_CREAT) == 0) 738 return B_ENTRY_NOT_FOUND; 739 740 // try to resolve the parent directory 741 strlcpy(path, name, sizeof(path)); 742 if (char* lastSlash = strrchr(path, '/')) { 743 if (lastSlash[1] == '\0') 744 return B_ENTRY_NOT_FOUND; 745 746 lastSlash = '\0'; 747 name = lastSlash + 1; 748 749 // resolve the directory 750 if (get_node_for_path(directory, path, &node) != B_OK) 751 return B_ENTRY_NOT_FOUND; 752 753 if (node->Type() != S_IFDIR) { 754 node->Release(); 755 return B_NOT_A_DIRECTORY; 756 } 757 758 directory = static_cast<Directory*>(node); 759 } else 760 directory->Acquire(); 761 762 // create the file 763 error = directory->CreateFile(name, permissions, &node); 764 directory->Release(); 765 766 if (error != B_OK) 767 return error; 768 } else if ((mode & O_EXCL) != 0) { 769 node->Release(); 770 return B_FILE_EXISTS; 771 } 772 773 int fd = open_node(node, mode); 774 775 node->Release(); 776 return fd; 777 } 778 779 780 /** Since we don't have directory functions yet, this 781 * function is needed to get the contents of a directory. 782 * It should be removed once readdir() & co. are in place. 783 */ 784 785 Node * 786 get_node_from(int fd) 787 { 788 Descriptor *descriptor = get_descriptor(fd); 789 if (descriptor == NULL) 790 return NULL; 791 792 return descriptor->GetNode(); 793 } 794 795 796 int 797 close(int fd) 798 { 799 Descriptor *descriptor = get_descriptor(fd); 800 if (descriptor == NULL) 801 RETURN_AND_SET_ERRNO(B_FILE_ERROR); 802 803 status_t status = descriptor->Release(); 804 if (!descriptor->RefCount()) 805 free_descriptor(fd); 806 807 RETURN_AND_SET_ERRNO(status); 808 } 809 810 811 // ToDo: remove this kludge when possible 812 int 813 #if defined(fstat) && !defined(main) 814 _fstat(int fd, struct stat *stat, size_t /*statSize*/) 815 #else 816 fstat(int fd, struct stat *stat) 817 #endif 818 { 819 if (stat == NULL) 820 RETURN_AND_SET_ERRNO(B_BAD_VALUE); 821 822 Descriptor *descriptor = get_descriptor(fd); 823 if (descriptor == NULL) 824 RETURN_AND_SET_ERRNO(B_FILE_ERROR); 825 826 RETURN_AND_SET_ERRNO(descriptor->Stat(*stat)); 827 } 828