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