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