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