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