1 /* 2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "kernel_interface.h" 8 9 #include <dirent.h> 10 11 #include <algorithm> 12 #include <new> 13 14 #include <fs_info.h> 15 #include <fs_interface.h> 16 #include <KernelExport.h> 17 #include <io_requests.h> 18 19 #include <AutoDeleter.h> 20 21 #include "DebugSupport.h" 22 #include "Directory.h" 23 #include "GlobalFactory.h" 24 #include "LeafNode.h" 25 #include "Volume.h" 26 27 28 static const uint32 kOptimalIOSize = 64 * 1024; 29 30 31 // #pragma mark - helper functions 32 33 34 static bool 35 is_user_in_group(gid_t gid) 36 { 37 gid_t groups[NGROUPS_MAX]; 38 int groupCount = getgroups(NGROUPS_MAX, groups); 39 for (int i = 0; i < groupCount; i++) { 40 if (gid == groups[i]) 41 return true; 42 } 43 44 return (gid == getegid()); 45 } 46 47 48 static bool 49 set_dirent_name(struct dirent* buffer, size_t bufferSize, const char* name, 50 size_t nameLen) 51 { 52 size_t length = (buffer->d_name + nameLen + 1) - (char*)buffer; 53 if (length > bufferSize) 54 return false; 55 56 memcpy(buffer->d_name, name, nameLen); 57 buffer->d_name[nameLen] = '\0'; 58 buffer->d_reclen = length; 59 return true; 60 } 61 62 63 static status_t 64 check_access(Node* node, int mode) 65 { 66 // write access requested? 67 if (mode & W_OK) 68 return B_READ_ONLY_DEVICE; 69 70 // get node permissions 71 int userPermissions = (node->Mode() & S_IRWXU) >> 6; 72 int groupPermissions = (node->Mode() & S_IRWXG) >> 3; 73 int otherPermissions = node->Mode() & S_IRWXO; 74 75 // get the permissions for this uid/gid 76 int permissions = 0; 77 uid_t uid = geteuid(); 78 79 if (uid == 0) { 80 // user is root 81 // root has always read/write permission, but at least one of the 82 // X bits must be set for execute permission 83 permissions = userPermissions | groupPermissions | otherPermissions 84 | S_IROTH | S_IWOTH; 85 } else if (uid == node->UserID()) { 86 // user is node owner 87 permissions = userPermissions; 88 } else if (is_user_in_group(node->GroupID())) { 89 // user is in owning group 90 permissions = groupPermissions; 91 } else { 92 // user is one of the others 93 permissions = otherPermissions; 94 } 95 96 return (mode & ~permissions) == 0 ? B_OK : B_NOT_ALLOWED; 97 } 98 99 100 // #pragma mark - Volume 101 102 103 static status_t 104 packagefs_mount(fs_volume* fsVolume, const char* device, uint32 flags, 105 const char* parameters, ino_t* _rootID) 106 { 107 FUNCTION("fsVolume: %p, device: \"%s\", flags: %#lx, parameters: \"%s\"\n", 108 fsVolume, device, flags, parameters); 109 110 // create a Volume object 111 Volume* volume = new(std::nothrow) Volume(fsVolume); 112 if (volume == NULL) 113 RETURN_ERROR(B_NO_MEMORY); 114 ObjectDeleter<Volume> volumeDeleter(volume); 115 116 status_t error = volume->Mount(); 117 if (error != B_OK) 118 return error; 119 120 // set return values 121 *_rootID = volume->RootDirectory()->ID(); 122 fsVolume->private_volume = volumeDeleter.Detach(); 123 fsVolume->ops = &gPackageFSVolumeOps; 124 125 return B_OK; 126 } 127 128 129 static status_t 130 packagefs_unmount(fs_volume* fsVolume) 131 { 132 Volume* volume = (Volume*)fsVolume->private_volume; 133 134 FUNCTION("volume: %p\n", volume); 135 136 volume->Unmount(); 137 delete volume; 138 139 return B_OK; 140 } 141 142 143 static status_t 144 packagefs_read_fs_info(fs_volume* fsVolume, struct fs_info* info) 145 { 146 FUNCTION("volume: %p, info: %p\n", fsVolume->private_volume, info); 147 148 info->flags = B_FS_IS_READONLY; 149 info->block_size = 4096; 150 info->io_size = kOptimalIOSize; 151 info->total_blocks = info->free_blocks = 1; 152 strlcpy(info->volume_name, "Package FS", sizeof(info->volume_name)); 153 return B_OK; 154 } 155 156 157 // #pragma mark - VNodes 158 159 160 static status_t 161 packagefs_lookup(fs_volume* fsVolume, fs_vnode* fsDir, const char* entryName, 162 ino_t* _vnid) 163 { 164 Volume* volume = (Volume*)fsVolume->private_volume; 165 Node* dir = (Node*)fsDir->private_node; 166 167 FUNCTION("volume: %p, dir: %p (%lld), entry: \"%s\"\n", volume, dir, 168 dir->ID(), entryName); 169 170 if (!S_ISDIR(dir->Mode())) 171 return B_NOT_A_DIRECTORY; 172 173 // resolve "." 174 if (strcmp(entryName, ".") == 0) { 175 Node* node; 176 *_vnid = dir->ID(); 177 return volume->GetVNode(*_vnid, node); 178 } 179 180 // resolve ".." 181 if (strcmp(entryName, "..") == 0) { 182 Node* node; 183 *_vnid = dir->Parent()->ID(); 184 return volume->GetVNode(*_vnid, node); 185 } 186 187 // resolve normal entries -- look up the node 188 NodeReadLocker dirLocker(dir); 189 Node* node = dynamic_cast<Directory*>(dir)->FindChild(entryName); 190 if (node == NULL) 191 return B_ENTRY_NOT_FOUND; 192 BReference<Node> nodeReference(node); 193 dirLocker.Unlock(); 194 195 // get the vnode reference 196 *_vnid = node->ID(); 197 RETURN_ERROR(volume->GetVNode(*_vnid, node)); 198 } 199 200 201 static status_t 202 packagefs_get_vnode(fs_volume* fsVolume, ino_t vnid, fs_vnode* fsNode, 203 int* _type, uint32* _flags, bool reenter) 204 { 205 Volume* volume = (Volume*)fsVolume->private_volume; 206 207 FUNCTION("volume: %p, vnid: %lld\n", volume, vnid); 208 209 VolumeReadLocker volumeLocker(volume); 210 Node* node = volume->FindNode(vnid); 211 if (node == NULL) 212 return B_ENTRY_NOT_FOUND; 213 BReference<Node> nodeReference(node); 214 volumeLocker.Unlock(); 215 216 NodeWriteLocker nodeLocker(node); 217 status_t error = node->VFSInit(volume->ID()); 218 if (error != B_OK) 219 RETURN_ERROR(error); 220 nodeLocker.Unlock(); 221 222 fsNode->private_node = nodeReference.Detach(); 223 fsNode->ops = &gPackageFSVnodeOps; 224 *_type = node->Mode() & S_IFMT; 225 *_flags = 0; 226 227 return B_OK; 228 } 229 230 231 static status_t 232 packagefs_put_vnode(fs_volume* fsVolume, fs_vnode* fsNode, bool reenter) 233 { 234 Volume* volume = (Volume*)fsVolume->private_volume; 235 Node* node = (Node*)fsNode->private_node; 236 237 FUNCTION("volume: %p, node: %p\n", volume, node); 238 TOUCH(volume); 239 240 NodeWriteLocker nodeLocker(node); 241 node->VFSUninit(); 242 nodeLocker.Unlock(); 243 244 node->ReleaseReference(); 245 246 return B_OK; 247 } 248 249 250 // #pragma mark - Request I/O 251 252 253 static status_t 254 packagefs_io(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie, 255 io_request* request) 256 { 257 Volume* volume = (Volume*)fsVolume->private_volume; 258 Node* node = (Node*)fsNode->private_node; 259 260 FUNCTION("volume: %p, node: %p (%lld), cookie: %p, request: %p\n", volume, 261 node, node->ID(), cookie, request); 262 TOUCH(volume); 263 264 if (io_request_is_write(request)) 265 RETURN_ERROR(B_READ_ONLY_DEVICE); 266 267 status_t error = node->Read(request); 268 notify_io_request(request, error); 269 return error; 270 } 271 272 273 // #pragma mark - Nodes 274 275 276 static status_t 277 packagefs_read_symlink(fs_volume* fsVolume, fs_vnode* fsNode, char* buffer, 278 size_t* _bufferSize) 279 { 280 Volume* volume = (Volume*)fsVolume->private_volume; 281 Node* node = (Node*)fsNode->private_node; 282 283 FUNCTION("volume: %p, node: %p (%lld)\n", volume, node, node->ID()); 284 TOUCH(volume); 285 286 NodeReadLocker nodeLocker(node); 287 288 if (!S_ISLNK(node->Mode())) 289 return B_BAD_VALUE; 290 291 const char* linkPath = dynamic_cast<LeafNode*>(node)->SymlinkPath(); 292 if (linkPath == NULL) { 293 *_bufferSize = 0; 294 return B_OK; 295 } 296 297 size_t toCopy = std::min(strlen(linkPath), *_bufferSize); 298 memcpy(buffer, linkPath, toCopy); 299 *_bufferSize = toCopy; 300 301 return B_OK; 302 } 303 304 305 static status_t 306 packagefs_access(fs_volume* fsVolume, fs_vnode* fsNode, int mode) 307 { 308 Volume* volume = (Volume*)fsVolume->private_volume; 309 Node* node = (Node*)fsNode->private_node; 310 311 FUNCTION("volume: %p, node: %p (%lld)\n", volume, node, node->ID()); 312 TOUCH(volume); 313 314 NodeReadLocker nodeLocker(node); 315 return check_access(node, mode); 316 } 317 318 319 static status_t 320 packagefs_read_stat(fs_volume* fsVolume, fs_vnode* fsNode, struct stat* st) 321 { 322 Volume* volume = (Volume*)fsVolume->private_volume; 323 Node* node = (Node*)fsNode->private_node; 324 325 FUNCTION("volume: %p, node: %p (%lld)\n", volume, node, node->ID()); 326 TOUCH(volume); 327 328 NodeReadLocker nodeLocker(node); 329 330 st->st_mode = node->Mode(); 331 st->st_nlink = 1; 332 st->st_uid = node->UserID(); 333 st->st_gid = node->GroupID(); 334 st->st_size = node->FileSize(); 335 st->st_blksize = kOptimalIOSize; 336 st->st_mtim = node->ModifiedTime(); 337 st->st_atim = st->st_mtim; 338 st->st_ctim = st->st_mtim; 339 // TODO: Perhaps manage a changed time (particularly for directories)? 340 st->st_crtim = st->st_mtim; 341 342 return B_OK; 343 } 344 345 346 // #pragma mark - Files 347 348 349 struct FileCookie { 350 int openMode; 351 352 FileCookie(int openMode) 353 : 354 openMode(openMode) 355 { 356 } 357 }; 358 359 360 static status_t 361 packagefs_open(fs_volume* fsVolume, fs_vnode* fsNode, int openMode, 362 void** _cookie) 363 { 364 Volume* volume = (Volume*)fsVolume->private_volume; 365 Node* node = (Node*)fsNode->private_node; 366 367 FUNCTION("volume: %p, node: %p (%lld), openMode %#x\n", volume, node, 368 node->ID(), openMode); 369 TOUCH(volume); 370 371 NodeReadLocker nodeLocker(node); 372 373 // check the open mode and permissions 374 if (S_ISDIR(node->Mode()) && (openMode & O_RWMASK) != O_RDONLY) 375 return B_IS_A_DIRECTORY; 376 377 if ((openMode & O_RWMASK) != O_RDONLY) 378 return B_NOT_ALLOWED; 379 380 status_t error = check_access(node, R_OK); 381 if (error != B_OK) 382 return error; 383 384 // allocate the cookie 385 FileCookie* cookie = new(std::nothrow) FileCookie(openMode); 386 if (cookie == NULL) 387 RETURN_ERROR(B_NO_MEMORY); 388 389 *_cookie = cookie; 390 391 return B_OK; 392 } 393 394 395 static status_t 396 packagefs_close(fs_volume* fs, fs_vnode* _node, void* cookie) 397 { 398 return B_OK; 399 } 400 401 402 static status_t 403 packagefs_free_cookie(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie) 404 { 405 Volume* volume = (Volume*)fsVolume->private_volume; 406 Node* node = (Node*)fsNode->private_node; 407 FileCookie* cookie = (FileCookie*)_cookie; 408 409 FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume, node, 410 node->ID(), cookie); 411 TOUCH(volume); 412 TOUCH(node); 413 414 delete cookie; 415 416 return B_OK; 417 } 418 419 420 static status_t 421 packagefs_read(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie, 422 off_t offset, void* buffer, size_t* bufferSize) 423 { 424 Volume* volume = (Volume*)fsVolume->private_volume; 425 Node* node = (Node*)fsNode->private_node; 426 FileCookie* cookie = (FileCookie*)_cookie; 427 428 FUNCTION("volume: %p, node: %p (%lld), cookie: %p, offset: %lld, " 429 "buffer: %p, size: %lu\n", volume, node, node->ID(), cookie, offset, 430 buffer, *bufferSize); 431 TOUCH(volume); 432 433 if ((cookie->openMode & O_RWMASK) != O_RDONLY) 434 return EBADF; 435 436 return node->Read(offset, buffer, bufferSize); 437 } 438 439 440 // #pragma mark - Directories 441 442 443 struct DirectoryCookie : DirectoryIterator { 444 Directory* directory; 445 int32 state; 446 bool registered; 447 448 DirectoryCookie(Directory* directory) 449 : 450 directory(directory), 451 state(0), 452 registered(false) 453 { 454 Rewind(); 455 } 456 457 ~DirectoryCookie() 458 { 459 if (registered) 460 directory->RemoveDirectoryIterator(this); 461 } 462 463 void Rewind() 464 { 465 if (registered) 466 directory->RemoveDirectoryIterator(this); 467 registered = false; 468 469 state = 0; 470 node = directory; 471 } 472 473 Node* Current(const char*& _name) const 474 { 475 if (node == NULL) 476 return NULL; 477 478 if (state == 0) 479 _name = "."; 480 else if (state == 1) 481 _name = ".."; 482 else 483 _name = node->Name(); 484 485 return node; 486 } 487 488 Node* Next() 489 { 490 if (state == 0) { 491 state = 1; 492 node = directory->Parent(); 493 if (node == NULL) 494 node = directory; 495 return node; 496 } 497 498 if (state == 1) { 499 node = directory->FirstChild(); 500 state = 2; 501 } else { 502 if (node != NULL) 503 node = directory->NextChild(node); 504 } 505 506 if (node == NULL) { 507 if (registered) { 508 directory->RemoveDirectoryIterator(this); 509 registered = false; 510 } 511 512 return NULL; 513 } 514 515 if (!registered) { 516 directory->AddDirectoryIterator(this); 517 registered = true; 518 } 519 520 return node; 521 } 522 }; 523 524 525 static status_t 526 packagefs_open_dir(fs_volume* fsVolume, fs_vnode* fsNode, void** _cookie) 527 { 528 Volume* volume = (Volume*)fsVolume->private_volume; 529 Node* node = (Node*)fsNode->private_node; 530 531 FUNCTION("volume: %p, node: %p (%lld)\n", volume, node, node->ID()); 532 TOUCH(volume); 533 534 if (!S_ISDIR(node->Mode())) 535 return B_NOT_A_DIRECTORY; 536 537 Directory* dir = dynamic_cast<Directory*>(node); 538 539 status_t error = check_access(dir, R_OK); 540 if (error != B_OK) 541 return error; 542 543 // create a cookie 544 NodeWriteLocker dirLocker(dir); 545 DirectoryCookie* cookie = new(std::nothrow) DirectoryCookie(dir); 546 if (cookie == NULL) 547 RETURN_ERROR(B_NO_MEMORY); 548 549 *_cookie = cookie; 550 return B_OK; 551 } 552 553 554 static status_t 555 packagefs_close_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie) 556 { 557 return B_OK; 558 } 559 560 561 static status_t 562 packagefs_free_dir_cookie(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie) 563 { 564 Volume* volume = (Volume*)fsVolume->private_volume; 565 Node* node = (Node*)fsNode->private_node; 566 DirectoryCookie* cookie = (DirectoryCookie*)_cookie; 567 568 FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume, node, 569 node->ID(), cookie); 570 TOUCH(volume); 571 TOUCH(node); 572 573 NodeWriteLocker dirLocker(node); 574 delete cookie; 575 576 return B_OK; 577 } 578 579 580 static status_t 581 packagefs_read_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie, 582 struct dirent* buffer, size_t bufferSize, uint32* _count) 583 { 584 Volume* volume = (Volume*)fsVolume->private_volume; 585 Node* node = (Node*)fsNode->private_node; 586 DirectoryCookie* cookie = (DirectoryCookie*)_cookie; 587 588 FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume, node, 589 node->ID(), cookie); 590 TOUCH(volume); 591 TOUCH(node); 592 593 NodeWriteLocker dirLocker(cookie->directory); 594 595 uint32 maxCount = *_count; 596 uint32 count = 0; 597 598 dirent* previousEntry = NULL; 599 600 const char* name; 601 while (Node* child = cookie->Current(name)) { 602 // don't read more entries than requested 603 if (count >= maxCount) 604 break; 605 606 // align the buffer for subsequent entries 607 if (count > 0) { 608 addr_t offset = (addr_t)buffer % 8; 609 if (offset > 0) { 610 offset = 8 - offset; 611 if (bufferSize <= offset) 612 break; 613 614 previousEntry->d_reclen += offset; 615 buffer = (dirent*)((addr_t)buffer + offset); 616 bufferSize -= offset; 617 } 618 } 619 620 // fill in the entry name -- checks whether the entry fits into the 621 // buffer 622 if (!set_dirent_name(buffer, bufferSize, name, strlen(name))) { 623 if (count == 0) 624 RETURN_ERROR(B_BUFFER_OVERFLOW); 625 break; 626 } 627 628 // fill in the other data 629 buffer->d_dev = volume->ID(); 630 buffer->d_ino = child->ID(); 631 632 count++; 633 previousEntry = buffer; 634 bufferSize -= buffer->d_reclen; 635 buffer = (dirent*)((addr_t)buffer + buffer->d_reclen); 636 637 cookie->Next(); 638 } 639 640 *_count = count; 641 return B_OK; 642 } 643 644 645 static status_t 646 packagefs_rewind_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie) 647 { 648 Volume* volume = (Volume*)fsVolume->private_volume; 649 Node* node = (Node*)fsNode->private_node; 650 DirectoryCookie* cookie = (DirectoryCookie*)_cookie; 651 652 FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume, node, 653 node->ID(), cookie); 654 TOUCH(volume); 655 TOUCH(node); 656 657 NodeWriteLocker dirLocker(node); 658 cookie->Rewind(); 659 660 return B_OK; 661 } 662 663 664 // #pragma mark - Attribute Directories 665 666 667 struct AttributeDirectoryCookie { 668 Node* node; 669 PackageNode* packageNode; 670 PackageNodeAttribute* attribute; 671 672 AttributeDirectoryCookie(Node* node) 673 : 674 node(node), 675 packageNode(node->GetPackageNode()), 676 attribute(NULL) 677 { 678 if (packageNode != NULL) { 679 packageNode->AcquireReference(); 680 attribute = packageNode->Attributes().Head(); 681 } 682 } 683 684 ~AttributeDirectoryCookie() 685 { 686 if (packageNode != NULL) 687 packageNode->ReleaseReference(); 688 } 689 690 PackageNodeAttribute* Current() const 691 { 692 return attribute; 693 } 694 695 void Next() 696 { 697 if (attribute == NULL) 698 return; 699 700 attribute = packageNode->Attributes().GetNext(attribute); 701 } 702 703 void Rewind() 704 { 705 if (packageNode != NULL) 706 attribute = packageNode->Attributes().Head(); 707 } 708 }; 709 710 711 status_t 712 packagefs_open_attr_dir(fs_volume* fsVolume, fs_vnode* fsNode, void** _cookie) 713 { 714 Volume* volume = (Volume*)fsVolume->private_volume; 715 Node* node = (Node*)fsNode->private_node; 716 717 FUNCTION("volume: %p, node: %p (%lld)\n", volume, node, node->ID()); 718 TOUCH(volume); 719 720 status_t error = check_access(node, R_OK); 721 if (error != B_OK) 722 return error; 723 724 // create a cookie 725 NodeReadLocker nodeLocker(node); 726 AttributeDirectoryCookie* cookie 727 = new(std::nothrow) AttributeDirectoryCookie(node); 728 if (cookie == NULL) 729 RETURN_ERROR(B_NO_MEMORY); 730 731 *_cookie = cookie; 732 return B_OK; 733 } 734 735 736 status_t 737 packagefs_close_attr_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie) 738 { 739 return B_OK; 740 } 741 742 743 status_t 744 packagefs_free_attr_dir_cookie(fs_volume* fsVolume, fs_vnode* fsNode, 745 void* _cookie) 746 { 747 Volume* volume = (Volume*)fsVolume->private_volume; 748 Node* node = (Node*)fsNode->private_node; 749 AttributeDirectoryCookie* cookie = (AttributeDirectoryCookie*)_cookie; 750 751 FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume, node, 752 node->ID(), cookie); 753 TOUCH(volume); 754 TOUCH(node); 755 756 delete cookie; 757 758 return B_OK; 759 } 760 761 762 status_t 763 packagefs_read_attr_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie, 764 struct dirent* buffer, size_t bufferSize, uint32* _count) 765 { 766 Volume* volume = (Volume*)fsVolume->private_volume; 767 Node* node = (Node*)fsNode->private_node; 768 AttributeDirectoryCookie* cookie = (AttributeDirectoryCookie*)_cookie; 769 770 FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume, node, 771 node->ID(), cookie); 772 TOUCH(volume); 773 TOUCH(node); 774 775 uint32 maxCount = *_count; 776 uint32 count = 0; 777 778 dirent* previousEntry = NULL; 779 780 while (PackageNodeAttribute* attribute = cookie->Current()) { 781 // don't read more entries than requested 782 if (count >= maxCount) 783 break; 784 785 // align the buffer for subsequent entries 786 if (count > 0) { 787 addr_t offset = (addr_t)buffer % 8; 788 if (offset > 0) { 789 offset = 8 - offset; 790 if (bufferSize <= offset) 791 break; 792 793 previousEntry->d_reclen += offset; 794 buffer = (dirent*)((addr_t)buffer + offset); 795 bufferSize -= offset; 796 } 797 } 798 799 // fill in the entry name -- checks whether the entry fits into the 800 // buffer 801 const char* name = attribute->Name(); 802 if (!set_dirent_name(buffer, bufferSize, name, strlen(name))) { 803 if (count == 0) 804 RETURN_ERROR(B_BUFFER_OVERFLOW); 805 break; 806 } 807 808 // fill in the other data 809 buffer->d_dev = volume->ID(); 810 buffer->d_ino = node->ID(); 811 812 count++; 813 previousEntry = buffer; 814 bufferSize -= buffer->d_reclen; 815 buffer = (dirent*)((addr_t)buffer + buffer->d_reclen); 816 817 cookie->Next(); 818 } 819 820 *_count = count; 821 return B_OK; 822 } 823 824 825 status_t 826 packagefs_rewind_attr_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie) 827 { 828 Volume* volume = (Volume*)fsVolume->private_volume; 829 Node* node = (Node*)fsNode->private_node; 830 AttributeDirectoryCookie* cookie = (AttributeDirectoryCookie*)_cookie; 831 832 FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume, node, 833 node->ID(), cookie); 834 TOUCH(volume); 835 TOUCH(node); 836 837 cookie->Rewind(); 838 839 return B_OK; 840 } 841 842 843 // #pragma mark - Attribute Operations 844 845 846 struct AttributeCookie { 847 PackageNode* packageNode; 848 Package* package; 849 PackageNodeAttribute* attribute; 850 int openMode; 851 852 AttributeCookie(PackageNode* packageNode, PackageNodeAttribute* attribute, 853 int openMode) 854 : 855 packageNode(packageNode), 856 package(packageNode->GetPackage()), 857 attribute(attribute), 858 openMode(openMode) 859 { 860 packageNode->AcquireReference(); 861 package->AcquireReference(); 862 } 863 864 ~AttributeCookie() 865 { 866 packageNode->ReleaseReference(); 867 package->ReleaseReference(); 868 } 869 }; 870 871 872 status_t 873 packagefs_open_attr(fs_volume* fsVolume, fs_vnode* fsNode, const char* name, 874 int openMode, void** _cookie) 875 { 876 Volume* volume = (Volume*)fsVolume->private_volume; 877 Node* node = (Node*)fsNode->private_node; 878 879 FUNCTION("volume: %p, node: %p (%lld), name: \"%s\", openMode %#x\n", 880 volume, node, node->ID(), name, openMode); 881 TOUCH(volume); 882 883 NodeReadLocker nodeLocker(node); 884 885 // check the open mode and permissions 886 if ((openMode & O_RWMASK) != O_RDONLY) 887 return B_NOT_ALLOWED; 888 889 status_t error = check_access(node, R_OK); 890 if (error != B_OK) 891 return error; 892 893 // get the package node and the respectively named attribute 894 PackageNode* packageNode = node->GetPackageNode(); 895 PackageNodeAttribute* attribute = packageNode != NULL 896 ? packageNode->FindAttribute(name) : NULL; 897 if (attribute == NULL) 898 return B_ENTRY_NOT_FOUND; 899 900 // allocate the cookie 901 AttributeCookie* cookie = new(std::nothrow) AttributeCookie(packageNode, 902 attribute, openMode); 903 if (cookie == NULL) 904 RETURN_ERROR(B_NO_MEMORY); 905 906 *_cookie = cookie; 907 908 return B_OK; 909 } 910 911 912 status_t 913 packagefs_close_attr(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie) 914 { 915 return B_OK; 916 } 917 918 919 status_t 920 packagefs_free_attr_cookie(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie) 921 { 922 Volume* volume = (Volume*)fsVolume->private_volume; 923 Node* node = (Node*)fsNode->private_node; 924 AttributeCookie* cookie = (AttributeCookie*)_cookie; 925 926 FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume, node, 927 node->ID(), cookie); 928 TOUCH(volume); 929 TOUCH(node); 930 931 delete cookie; 932 933 return B_OK; 934 } 935 936 937 static status_t 938 read_package_data(const PackageData& data, DataReader* dataReader, off_t offset, 939 void* buffer, size_t* bufferSize) 940 { 941 // create a PackageDataReader 942 PackageDataReader* reader; 943 status_t error = GlobalFactory::Default()->CreatePackageDataReader( 944 dataReader, data, reader); 945 if (error != B_OK) 946 RETURN_ERROR(error); 947 ObjectDeleter<PackageDataReader> readerDeleter(reader); 948 949 // check the offset 950 if (offset < 0 || (uint64)offset > data.UncompressedSize()) 951 return B_BAD_VALUE; 952 953 // clamp the size 954 size_t toRead = std::min((uint64)*bufferSize, 955 data.UncompressedSize() - offset); 956 957 // read 958 if (toRead > 0) { 959 status_t error = reader->ReadData(offset, buffer, toRead); 960 if (error != B_OK) 961 RETURN_ERROR(error); 962 } 963 964 *bufferSize = toRead; 965 return B_OK; 966 } 967 968 969 status_t 970 packagefs_read_attr(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie, 971 off_t offset, void* buffer, size_t* bufferSize) 972 { 973 Volume* volume = (Volume*)fsVolume->private_volume; 974 Node* node = (Node*)fsNode->private_node; 975 AttributeCookie* cookie = (AttributeCookie*)_cookie; 976 977 FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume, node, 978 node->ID(), cookie); 979 TOUCH(volume); 980 TOUCH(node); 981 982 const PackageData& data = cookie->attribute->Data(); 983 if (data.IsEncodedInline()) { 984 // inline data 985 BufferDataReader dataReader(data.InlineData(), data.CompressedSize()); 986 return read_package_data(data, &dataReader, offset, buffer, bufferSize); 987 } 988 989 // data not inline -- open the package 990 int fd = cookie->package->Open(); 991 if (fd < 0) 992 RETURN_ERROR(fd); 993 PackageCloser packageCloser(cookie->package); 994 995 FDDataReader dataReader(fd); 996 return read_package_data(data, &dataReader, offset, buffer, bufferSize); 997 } 998 999 1000 status_t 1001 packagefs_read_attr_stat(fs_volume* fsVolume, fs_vnode* fsNode, 1002 void* _cookie, struct stat* st) 1003 { 1004 Volume* volume = (Volume*)fsVolume->private_volume; 1005 Node* node = (Node*)fsNode->private_node; 1006 AttributeCookie* cookie = (AttributeCookie*)_cookie; 1007 1008 FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume, node, 1009 node->ID(), cookie); 1010 TOUCH(volume); 1011 TOUCH(node); 1012 1013 st->st_size = cookie->attribute->Data().UncompressedSize(); 1014 st->st_type = cookie->attribute->Type(); 1015 1016 return B_OK; 1017 } 1018 1019 1020 // #pragma mark - Module Interface 1021 1022 1023 static status_t 1024 packagefs_std_ops(int32 op, ...) 1025 { 1026 switch (op) { 1027 case B_MODULE_INIT: 1028 { 1029 init_debugging(); 1030 PRINT("package_std_ops(): B_MODULE_INIT\n"); 1031 1032 status_t error = GlobalFactory::CreateDefault(); 1033 if (error != B_OK) { 1034 ERROR("Failed to init GlobalFactory\n"); 1035 exit_debugging(); 1036 return error; 1037 } 1038 1039 return B_OK; 1040 } 1041 1042 case B_MODULE_UNINIT: 1043 { 1044 PRINT("package_std_ops(): B_MODULE_UNINIT\n"); 1045 GlobalFactory::DeleteDefault(); 1046 exit_debugging(); 1047 return B_OK; 1048 } 1049 1050 default: 1051 return B_ERROR; 1052 } 1053 } 1054 1055 1056 static file_system_module_info sPackageFSModuleInfo = { 1057 { 1058 "file_systems/packagefs" B_CURRENT_FS_API_VERSION, 1059 0, 1060 packagefs_std_ops, 1061 }, 1062 1063 "packagefs", // short_name 1064 "Package File System", // pretty_name 1065 0, // DDM flags 1066 1067 1068 // scanning 1069 NULL, // identify_partition, 1070 NULL, // scan_partition, 1071 NULL, // free_identify_partition_cookie, 1072 NULL, // free_partition_content_cookie() 1073 1074 &packagefs_mount 1075 }; 1076 1077 1078 fs_volume_ops gPackageFSVolumeOps = { 1079 &packagefs_unmount, 1080 &packagefs_read_fs_info, 1081 NULL, // write_fs_info, 1082 NULL, // sync, 1083 1084 &packagefs_get_vnode 1085 1086 // TODO: index operations 1087 // TODO: query operations 1088 // TODO: FS layer operations 1089 }; 1090 1091 1092 fs_vnode_ops gPackageFSVnodeOps = { 1093 // vnode operations 1094 &packagefs_lookup, 1095 NULL, // get_vnode_name, 1096 &packagefs_put_vnode, 1097 &packagefs_put_vnode, // remove_vnode -- same as put_vnode 1098 1099 // VM file access 1100 NULL, // can_page, 1101 NULL, // read_pages, 1102 NULL, // write_pages, 1103 1104 &packagefs_io, 1105 NULL, // cancel_io() 1106 1107 NULL, // get_file_map, 1108 1109 NULL, // ioctl, 1110 NULL, // set_flags, 1111 NULL, // select, 1112 NULL, // deselect, 1113 NULL, // fsync, 1114 1115 &packagefs_read_symlink, 1116 NULL, // create_symlink, 1117 1118 NULL, // link, 1119 NULL, // unlink, 1120 NULL, // rename, 1121 1122 &packagefs_access, 1123 &packagefs_read_stat, 1124 NULL, // write_stat, 1125 1126 // file operations 1127 NULL, // create, 1128 &packagefs_open, 1129 &packagefs_close, 1130 &packagefs_free_cookie, 1131 &packagefs_read, 1132 NULL, // write, 1133 1134 // directory operations 1135 NULL, // create_dir, 1136 NULL, // remove_dir, 1137 &packagefs_open_dir, 1138 &packagefs_close_dir, 1139 &packagefs_free_dir_cookie, 1140 &packagefs_read_dir, 1141 &packagefs_rewind_dir, 1142 1143 // attribute directory operations 1144 &packagefs_open_attr_dir, 1145 &packagefs_close_attr_dir, 1146 &packagefs_free_attr_dir_cookie, 1147 &packagefs_read_attr_dir, 1148 &packagefs_rewind_attr_dir, 1149 1150 // attribute operations 1151 NULL, // create_attr, 1152 &packagefs_open_attr, 1153 &packagefs_close_attr, 1154 &packagefs_free_attr_cookie, 1155 &packagefs_read_attr, 1156 NULL, // write_attr, 1157 1158 &packagefs_read_attr_stat, 1159 NULL, // write_attr_stat, 1160 NULL, // rename_attr, 1161 NULL // remove_attr, 1162 1163 // TODO: FS layer operations 1164 }; 1165 1166 1167 module_info *modules[] = { 1168 (module_info *)&sPackageFSModuleInfo, 1169 NULL, 1170 }; 1171