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