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