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