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