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