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