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