1 /* 2 * Copyright 2011, Oliver Tappe <zooey@hirschkaefer.de> 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include <new> 8 9 #include <fs_info.h> 10 #include <fs_interface.h> 11 #include <KernelExport.h> 12 13 #include <vfs.h> 14 15 #include <AutoDeleter.h> 16 17 #include "DebugSupport.h" 18 #include "kernel_interface.h" 19 #include "Node.h" 20 #include "Utils.h" 21 #include "Volume.h" 22 23 24 /*! \brief Binds an arbitrary folder to a given path (which must be that of a 25 folder, too). All requests to the mounted path will be passed to the 26 corresponding node of the bound (source) filesystem. 27 28 TODO: node monitoring! 29 30 TODO: path filter, such that /dev can be bind-mounted with only a subset 31 of entries 32 33 TODO: Since the source node IDs are used for our nodes, this doesn't work 34 for source trees with submounts. 35 36 TODO: There's no file cache support (required for mmap()). We implement the 37 hooks, but they aren't used. 38 */ 39 40 41 // #pragma mark - helper macros 42 43 44 #define FETCH_SOURCE_VOLUME_AND_NODE(volume, nodeID) \ 45 fs_volume* sourceVolume = volume->SourceFSVolume(); \ 46 if (sourceVolume == NULL) \ 47 RETURN_ERROR(B_ERROR); \ 48 vnode* sourceVnode; \ 49 status_t error = vfs_get_vnode(volume->SourceFSVolume()->id, \ 50 nodeID, true, &sourceVnode); \ 51 if (error != B_OK) \ 52 RETURN_ERROR(error); \ 53 VnodePutter putter(sourceVnode); \ 54 fs_vnode* sourceNode = vfs_fsnode_for_vnode(sourceVnode); \ 55 if (sourceNode == NULL) \ 56 RETURN_ERROR(B_ERROR); 57 58 59 // #pragma mark - Volume 60 61 62 static status_t 63 bindfs_mount(fs_volume* fsVolume, const char* device, uint32 flags, 64 const char* parameters, ino_t* _rootID) 65 { 66 FUNCTION("fsVolume: %p, device: \"%s\", flags: %#lx, parameters: \"%s\"\n", 67 fsVolume, device, flags, parameters); 68 69 // create a Volume object 70 Volume* volume = new(std::nothrow) Volume(fsVolume); 71 if (volume == NULL) 72 RETURN_ERROR(B_NO_MEMORY); 73 ObjectDeleter<Volume> volumeDeleter(volume); 74 75 status_t error = volume->Mount(parameters); 76 if (error != B_OK) 77 return error; 78 79 // set return values 80 *_rootID = volume->RootNode()->ID(); 81 fsVolume->private_volume = volumeDeleter.Detach(); 82 fsVolume->ops = &gBindFSVolumeOps; 83 84 return B_OK; 85 } 86 87 88 static status_t 89 bindfs_unmount(fs_volume* fsVolume) 90 { 91 Volume* volume = (Volume*)fsVolume->private_volume; 92 93 FUNCTION("volume: %p\n", volume); 94 95 volume->Unmount(); 96 delete volume; 97 98 return B_OK; 99 } 100 101 102 static status_t 103 bindfs_read_fs_info(fs_volume* fsVolume, struct fs_info* info) 104 { 105 Volume* volume = (Volume*)fsVolume->private_volume; 106 107 FUNCTION("volume: %p, info: %p\n", volume, info); 108 109 fs_volume* sourceVolume = volume->SourceFSVolume(); 110 111 if (sourceVolume->ops->read_fs_info != NULL) { 112 status_t error = sourceVolume->ops->read_fs_info(sourceVolume, info); 113 if (error != B_OK) 114 RETURN_ERROR(error); 115 } else { 116 info->block_size = 512; 117 info->io_size = 64 * 1024; 118 } 119 120 info->dev = volume->ID(); 121 info->root = volume->RootNode()->ID(); 122 info->total_blocks = info->free_blocks = 0; 123 info->total_nodes = info->free_nodes = 0; 124 125 strlcpy(info->volume_name, volume->Name(), sizeof(info->volume_name)); 126 127 return B_OK; 128 } 129 130 131 // #pragma mark - VNodes 132 133 134 static status_t 135 bindfs_lookup(fs_volume* fsVolume, fs_vnode* fsDir, const char* entryName, 136 ino_t* _vnid) 137 { 138 Volume* volume = (Volume*)fsVolume->private_volume; 139 Node* node = (Node*)fsDir->private_node; 140 141 FUNCTION("volume: %p, dir: %p (%lld), entry: \"%s\"\n", volume, node, 142 node->ID(), entryName); 143 144 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 145 146 error = sourceNode->ops->lookup(sourceVolume, sourceNode, entryName, _vnid); 147 if (error != B_OK) 148 RETURN_ERROR(error); 149 150 error = get_vnode(fsVolume, *_vnid, NULL); 151 152 // lookup() on the source gave us a reference we don't need any longer 153 vnode* sourceChildVnode; 154 if (vfs_lookup_vnode(sourceVolume->id, *_vnid, &sourceChildVnode) == B_OK) 155 vfs_put_vnode(sourceChildVnode); 156 157 return error; 158 } 159 160 161 static status_t 162 bindfs_get_vnode(fs_volume* fsVolume, ino_t vnid, fs_vnode* fsNode, 163 int* _type, uint32* _flags, bool reenter) 164 { 165 Volume* volume = (Volume*)fsVolume->private_volume; 166 167 FUNCTION("volume: %p, vnid: %lld\n", volume, vnid); 168 169 FETCH_SOURCE_VOLUME_AND_NODE(volume, vnid); 170 171 struct stat st; 172 error = sourceNode->ops->read_stat(sourceVolume, sourceNode, &st); 173 174 Node* node = new(std::nothrow) Node(vnid, st.st_mode); 175 if (node == NULL) 176 RETURN_ERROR(B_NO_MEMORY); 177 178 fsNode->private_node = node; 179 fsNode->ops = const_cast<fs_vnode_ops*>(volume->VnodeOps()); 180 *_type = node->Mode() & S_IFMT; 181 *_flags = 0; 182 183 return B_OK; 184 } 185 186 187 static status_t 188 bindfs_get_vnode_name(fs_volume* fsVolume, fs_vnode* fsNode, char* buffer, 189 size_t bufferSize) 190 { 191 Volume* volume = (Volume*)fsVolume->private_volume; 192 Node* node = (Node*)fsNode->private_node; 193 194 FUNCTION("volume: %p, node: %p\n", volume, node); 195 196 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 197 198 return sourceNode->ops->get_vnode_name(sourceVolume, sourceNode, buffer, 199 bufferSize); 200 } 201 202 static status_t 203 bindfs_put_vnode(fs_volume* fsVolume, fs_vnode* fsNode, bool reenter) 204 { 205 Volume* volume = (Volume*)fsVolume->private_volume; 206 Node* node = (Node*)fsNode->private_node; 207 208 FUNCTION("volume: %p, node: %p\n", volume, node); 209 210 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 211 212 delete node; 213 214 return B_OK; 215 } 216 217 218 static status_t 219 bindfs_remove_vnode(fs_volume* fsVolume, fs_vnode* fsNode, bool reenter) 220 { 221 Volume* volume = (Volume*)fsVolume->private_volume; 222 Node* node = (Node*)fsNode->private_node; 223 224 FUNCTION("volume: %p, node: %p\n", volume, node); 225 226 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 227 228 delete node; 229 230 return sourceNode->ops->remove_vnode(sourceVolume, sourceNode, reenter); 231 } 232 233 234 // #pragma mark - VM access 235 236 237 // TODO: These hooks are obsolete. Since we don't create a file cache, they 238 // aren't needed anyway. 239 240 241 static bool 242 bindfs_can_page(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie) 243 { 244 Volume* volume = (Volume*)fsVolume->private_volume; 245 Node* node = (Node*)fsNode->private_node; 246 247 FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume, 248 node, node->ID(), cookie); 249 250 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 251 252 return sourceNode->ops->can_page(sourceVolume, sourceNode, cookie); 253 } 254 255 256 static status_t 257 bindfs_read_pages(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie, 258 off_t pos, const iovec* vecs, size_t count, size_t* _numBytes) 259 { 260 Volume* volume = (Volume*)fsVolume->private_volume; 261 Node* node = (Node*)fsNode->private_node; 262 263 FUNCTION("volume: %p, node: %p (%lld), cookie: %p, pos: %lld, vecs: %p, " 264 "count: %ld\n", 265 volume, node, node->ID(), cookie, pos, vecs, count); 266 267 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 268 269 return sourceNode->ops->read_pages(sourceVolume, sourceNode, cookie, pos, 270 vecs, count, _numBytes); 271 } 272 273 274 static status_t 275 bindfs_write_pages(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie, 276 off_t pos, const iovec* vecs, size_t count, size_t* _numBytes) 277 { 278 Volume* volume = (Volume*)fsVolume->private_volume; 279 Node* node = (Node*)fsNode->private_node; 280 281 FUNCTION("volume: %p, node: %p (%lld), cookie: %p, pos: %lld, vecs: %p, " 282 "count: %ld\n", 283 volume, node, node->ID(), cookie, pos, vecs, count); 284 285 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 286 287 return sourceNode->ops->write_pages(sourceVolume, sourceNode, cookie, pos, 288 vecs, count, _numBytes); 289 } 290 291 292 // #pragma mark - Request I/O 293 294 295 // TODO: Since we don't create a file cache, these hooks aren't needed. 296 297 298 static status_t 299 bindfs_io(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie, 300 io_request* request) 301 { 302 Volume* volume = (Volume*)fsVolume->private_volume; 303 Node* node = (Node*)fsNode->private_node; 304 305 FUNCTION("volume: %p, node: %p (%lld), cookie: %p, request: %p\n", volume, 306 node, node->ID(), cookie, request); 307 308 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 309 310 return sourceNode->ops->io(sourceVolume, sourceNode, cookie, request); 311 } 312 313 314 static status_t 315 bindfs_cancel_io(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie, 316 io_request* request) 317 { 318 Volume* volume = (Volume*)fsVolume->private_volume; 319 Node* node = (Node*)fsNode->private_node; 320 321 FUNCTION("volume: %p, node: %p (%lld), cookie: %p, request: %p\n", volume, 322 node, node->ID(), cookie, request); 323 324 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 325 326 return sourceNode->ops->cancel_io(sourceVolume, sourceNode, cookie, 327 request); 328 } 329 330 331 // #pragma mark - File Map 332 333 334 static status_t 335 bindfs_get_file_map(fs_volume* fsVolume, fs_vnode* fsNode, off_t offset, 336 size_t size, struct file_io_vec* vecs, size_t* _count) 337 { 338 Volume* volume = (Volume*)fsVolume->private_volume; 339 Node* node = (Node*)fsNode->private_node; 340 341 FUNCTION("volume: %p, node: %p (%lld), offset: %lld, size: %ld, vecs: %p\n", 342 volume, node, node->ID(), offset, size, vecs); 343 344 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 345 346 return sourceNode->ops->get_file_map(sourceVolume, sourceNode, offset, size, 347 vecs, _count); 348 } 349 350 351 // #pragma mark - Special 352 353 354 static status_t 355 bindfs_ioctl(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie, uint32 op, 356 void* buffer, size_t length) 357 { 358 Volume* volume = (Volume*)fsVolume->private_volume; 359 Node* node = (Node*)fsNode->private_node; 360 361 FUNCTION("volume: %p, node: %p (%lld), cookie: %p, op: %lx, buffer: %p, " 362 "length: %ld\n", 363 volume, node, node->ID(), cookie, op, buffer, length); 364 365 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 366 367 return sourceNode->ops->ioctl(sourceVolume, sourceNode, cookie, op, buffer, 368 length); 369 } 370 371 372 static status_t 373 bindfs_set_flags(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie, int flags) 374 { 375 Volume* volume = (Volume*)fsVolume->private_volume; 376 Node* node = (Node*)fsNode->private_node; 377 378 FUNCTION("volume: %p, node: %p (%lld), cookie: %p, flags: %x\n", 379 volume, node, node->ID(), cookie, flags); 380 381 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 382 383 return sourceNode->ops->set_flags(sourceVolume, sourceNode, cookie, flags); 384 } 385 386 387 static status_t 388 bindfs_select(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie, uint8 event, 389 selectsync* sync) 390 { 391 Volume* volume = (Volume*)fsVolume->private_volume; 392 Node* node = (Node*)fsNode->private_node; 393 394 FUNCTION("volume: %p, node: %p (%lld), cookie: %p, event: %x, sync: %p\n", 395 volume, node, node->ID(), cookie, event, sync); 396 397 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 398 399 return sourceNode->ops->select(sourceVolume, sourceNode, cookie, event, 400 sync); 401 } 402 403 404 static status_t 405 bindfs_deselect(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie, 406 uint8 event, selectsync* sync) 407 { 408 Volume* volume = (Volume*)fsVolume->private_volume; 409 Node* node = (Node*)fsNode->private_node; 410 411 FUNCTION("volume: %p, node: %p (%lld), cookie: %p, event: %x, sync: %p\n", 412 volume, node, node->ID(), cookie, event, sync); 413 414 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 415 416 return sourceNode->ops->deselect(sourceVolume, sourceNode, cookie, event, 417 sync); 418 } 419 420 421 static status_t 422 bindfs_fsync(fs_volume* fsVolume, fs_vnode* fsNode) 423 { 424 Volume* volume = (Volume*)fsVolume->private_volume; 425 Node* node = (Node*)fsNode->private_node; 426 427 FUNCTION("volume: %p, node: %p (%lld)\n", volume, node, node->ID()); 428 429 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 430 431 return sourceNode->ops->fsync(sourceVolume, sourceNode); 432 } 433 434 435 // #pragma mark - Nodes 436 437 438 static status_t 439 bindfs_read_symlink(fs_volume* fsVolume, fs_vnode* fsNode, char* buffer, 440 size_t* _bufferSize) 441 { 442 Volume* volume = (Volume*)fsVolume->private_volume; 443 Node* node = (Node*)fsNode->private_node; 444 445 FUNCTION("volume: %p, node: %p (%lld)\n", volume, node, node->ID()); 446 447 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 448 449 return sourceNode->ops->read_symlink(sourceVolume, sourceNode, buffer, 450 _bufferSize); 451 } 452 453 454 static status_t 455 bindfs_create_symlink(fs_volume* fsVolume, fs_vnode* fsNode, const char* name, 456 const char* path, int mode) 457 { 458 Volume* volume = (Volume*)fsVolume->private_volume; 459 Node* node = (Node*)fsNode->private_node; 460 461 FUNCTION("volume: %p, node: %p (%lld), name: %s, path: %s, mode: %x\n", 462 volume, node, node->ID(), name, path, mode); 463 464 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 465 466 return sourceNode->ops->create_symlink(sourceVolume, sourceNode, name, path, 467 mode); 468 } 469 470 471 static status_t 472 bindfs_link(fs_volume* fsVolume, fs_vnode* fsNode, const char* name, 473 fs_vnode* toNode) 474 { 475 Volume* volume = (Volume*)fsVolume->private_volume; 476 Node* node = (Node*)fsNode->private_node; 477 478 FUNCTION("volume: %p, node: %p (%lld), name: %s, tonode: %p\n", 479 volume, node, node->ID(), name, toNode); 480 481 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 482 483 return sourceNode->ops->link(sourceVolume, sourceNode, name, toNode); 484 } 485 486 487 static status_t 488 bindfs_unlink(fs_volume* fsVolume, fs_vnode* fsNode, const char* name) 489 { 490 Volume* volume = (Volume*)fsVolume->private_volume; 491 Node* node = (Node*)fsNode->private_node; 492 493 FUNCTION("volume: %p, node: %p (%lld), name: %s\n", 494 volume, node, node->ID(), name); 495 496 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 497 498 return sourceNode->ops->unlink(sourceVolume, sourceNode, name); 499 } 500 501 502 static status_t 503 bindfs_rename(fs_volume* fsVolume, fs_vnode* fsNode, const char* fromName, 504 fs_vnode* toDir, const char* toName) 505 { 506 Volume* volume = (Volume*)fsVolume->private_volume; 507 Node* node = (Node*)fsNode->private_node; 508 509 FUNCTION("volume: %p, node: %p (%lld), from: %s, toDir: %p, to: %s\n", 510 volume, node, node->ID(), fromName, toDir, toName); 511 512 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 513 514 return sourceNode->ops->rename(sourceVolume, sourceNode, fromName, toDir, 515 toName); 516 } 517 518 519 static status_t 520 bindfs_access(fs_volume* fsVolume, fs_vnode* fsNode, int mode) 521 { 522 Volume* volume = (Volume*)fsVolume->private_volume; 523 Node* node = (Node*)fsNode->private_node; 524 525 FUNCTION("volume: %p, node: %p (%lld)\n", volume, node, node->ID()); 526 527 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 528 529 return sourceNode->ops->access(sourceVolume, sourceNode, mode); 530 } 531 532 533 static status_t 534 bindfs_read_stat(fs_volume* fsVolume, fs_vnode* fsNode, struct stat* st) 535 { 536 Volume* volume = (Volume*)fsVolume->private_volume; 537 Node* node = (Node*)fsNode->private_node; 538 539 FUNCTION("volume: %p, node: %p (%lld)\n", volume, node, node->ID()); 540 541 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 542 543 error = sourceNode->ops->read_stat(sourceVolume, sourceNode, st); 544 if (error != B_OK) 545 RETURN_ERROR(error); 546 547 st->st_dev = volume->ID(); 548 549 return B_OK; 550 } 551 552 553 static status_t 554 bindfs_write_stat(fs_volume* fsVolume, fs_vnode* fsNode, 555 const struct stat* _st, uint32 statMask) 556 { 557 Volume* volume = (Volume*)fsVolume->private_volume; 558 Node* node = (Node*)fsNode->private_node; 559 560 FUNCTION("volume: %p, node: %p (%lld)\n", volume, node, node->ID()); 561 562 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 563 564 struct stat st; 565 memcpy(&st, _st, sizeof(st)); 566 st.st_dev = sourceVolume->id; 567 568 return sourceNode->ops->write_stat(sourceVolume, sourceNode, &st, statMask); 569 } 570 571 572 static status_t 573 bindfs_preallocate(fs_volume* fsVolume, fs_vnode* fsNode, off_t pos, 574 off_t length) 575 { 576 Volume* volume = (Volume*)fsVolume->private_volume; 577 Node* node = (Node*)fsNode->private_node; 578 579 FUNCTION("volume: %p, node: %p (%lld), pos: %lld, length: %lld\n", 580 volume, node, node->ID(), pos, length); 581 582 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 583 584 return sourceNode->ops->preallocate(sourceVolume, sourceNode, pos, length); 585 } 586 587 588 // #pragma mark - Files 589 590 591 static status_t 592 bindfs_create(fs_volume* fsVolume, fs_vnode* fsNode, const char* name, 593 int openMode, int perms, void** _cookie, ino_t* _newVnodeID) 594 { 595 Volume* volume = (Volume*)fsVolume->private_volume; 596 Node* node = (Node*)fsNode->private_node; 597 598 FUNCTION("volume: %p, node: %p (%lld), name: %s, openMode %#x, perms: %x\n", 599 volume, node, node->ID(), name, openMode, perms); 600 601 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 602 603 error = sourceNode->ops->create(sourceVolume, sourceNode, name, openMode, 604 perms, _cookie, _newVnodeID); 605 if (error != B_OK) 606 return error; 607 608 error = get_vnode(fsVolume, *_newVnodeID, NULL); 609 610 // on error remove the newly created source entry 611 if (error != B_OK) 612 sourceNode->ops->unlink(sourceVolume, sourceNode, name); 613 614 // create() on the source gave us a reference we don't need any longer 615 vnode* newSourceVnode; 616 if (vfs_lookup_vnode(sourceVolume->id, *_newVnodeID, &newSourceVnode) 617 == B_OK) { 618 vfs_put_vnode(newSourceVnode); 619 } 620 621 return error; 622 623 } 624 625 626 static status_t 627 bindfs_open(fs_volume* fsVolume, fs_vnode* fsNode, int openMode, 628 void** _cookie) 629 { 630 Volume* volume = (Volume*)fsVolume->private_volume; 631 Node* node = (Node*)fsNode->private_node; 632 633 FUNCTION("volume: %p, node: %p (%lld), openMode %#x\n", volume, node, 634 node->ID(), openMode); 635 636 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 637 638 return sourceNode->ops->open(sourceVolume, sourceNode, openMode, _cookie); 639 } 640 641 642 static status_t 643 bindfs_close(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie) 644 { 645 Volume* volume = (Volume*)fsVolume->private_volume; 646 Node* node = (Node*)fsNode->private_node; 647 648 FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume, node, 649 node->ID(), cookie); 650 651 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 652 653 return sourceNode->ops->close(sourceVolume, sourceNode, cookie); 654 } 655 656 657 static status_t 658 bindfs_free_cookie(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie) 659 { 660 Volume* volume = (Volume*)fsVolume->private_volume; 661 Node* node = (Node*)fsNode->private_node; 662 663 FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume, node, 664 node->ID(), cookie); 665 666 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 667 668 return sourceNode->ops->free_cookie(sourceVolume, sourceNode, cookie); 669 } 670 671 672 static status_t 673 bindfs_read(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie, 674 off_t offset, void* buffer, size_t* bufferSize) 675 { 676 Volume* volume = (Volume*)fsVolume->private_volume; 677 Node* node = (Node*)fsNode->private_node; 678 679 FUNCTION("volume: %p, node: %p (%lld), cookie: %p, offset: %lld, " 680 "buffer: %p, size: %lu\n", volume, node, node->ID(), cookie, offset, 681 buffer, *bufferSize); 682 683 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 684 685 return sourceNode->ops->read(sourceVolume, sourceNode, cookie, offset, 686 buffer, bufferSize); 687 } 688 689 690 static status_t 691 bindfs_write(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie, 692 off_t offset, const void* buffer, size_t* bufferSize) 693 { 694 Volume* volume = (Volume*)fsVolume->private_volume; 695 Node* node = (Node*)fsNode->private_node; 696 697 FUNCTION("volume: %p, node: %p (%lld), cookie: %p, offset: %lld, " 698 "buffer: %p, size: %lu\n", volume, node, node->ID(), cookie, offset, 699 buffer, *bufferSize); 700 701 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 702 703 return sourceNode->ops->write(sourceVolume, sourceNode, cookie, offset, 704 buffer, bufferSize); 705 } 706 707 708 // #pragma mark - Directories 709 710 711 static status_t 712 bindfs_create_dir(fs_volume* fsVolume, fs_vnode* fsNode, const char* name, 713 int perms) 714 { 715 Volume* volume = (Volume*)fsVolume->private_volume; 716 Node* node = (Node*)fsNode->private_node; 717 718 FUNCTION("volume: %p, node: %p (%lld), name: %s, perms: %x\n", volume, node, 719 node->ID(), name, perms); 720 721 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 722 723 return sourceNode->ops->create_dir(sourceVolume, sourceNode, name, perms); 724 } 725 726 727 static status_t 728 bindfs_remove_dir(fs_volume* fsVolume, fs_vnode* fsNode, const char* name) 729 { 730 Volume* volume = (Volume*)fsVolume->private_volume; 731 Node* node = (Node*)fsNode->private_node; 732 733 FUNCTION("volume: %p, node: %p (%lld), name: %s\n", volume, node, 734 node->ID(), name); 735 736 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 737 738 return sourceNode->ops->remove_dir(sourceVolume, sourceNode, name); 739 } 740 741 742 static status_t 743 bindfs_open_dir(fs_volume* fsVolume, fs_vnode* fsNode, void** _cookie) 744 { 745 Volume* volume = (Volume*)fsVolume->private_volume; 746 Node* node = (Node*)fsNode->private_node; 747 748 FUNCTION("volume: %p, node: %p (%lld)\n", volume, node, node->ID()); 749 750 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 751 752 return sourceNode->ops->open_dir(sourceVolume, sourceNode, _cookie); 753 } 754 755 756 static status_t 757 bindfs_close_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie) 758 { 759 Volume* volume = (Volume*)fsVolume->private_volume; 760 Node* node = (Node*)fsNode->private_node; 761 762 FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume, node, 763 node->ID(), cookie); 764 765 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 766 767 return sourceNode->ops->close_dir(sourceVolume, sourceNode, cookie); 768 } 769 770 771 static status_t 772 bindfs_free_dir_cookie(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie) 773 { 774 Volume* volume = (Volume*)fsVolume->private_volume; 775 Node* node = (Node*)fsNode->private_node; 776 777 FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume, node, 778 node->ID(), cookie); 779 780 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 781 782 return sourceNode->ops->free_dir_cookie(sourceVolume, sourceNode, cookie); 783 } 784 785 786 static status_t 787 bindfs_read_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie, 788 struct dirent* buffer, size_t bufferSize, uint32* _count) 789 { 790 Volume* volume = (Volume*)fsVolume->private_volume; 791 Node* node = (Node*)fsNode->private_node; 792 793 FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume, node, 794 node->ID(), cookie); 795 796 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 797 798 return sourceNode->ops->read_dir(sourceVolume, sourceNode, cookie, buffer, 799 bufferSize, _count); 800 } 801 802 803 static status_t 804 bindfs_rewind_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie) 805 { 806 Volume* volume = (Volume*)fsVolume->private_volume; 807 Node* node = (Node*)fsNode->private_node; 808 809 FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume, node, 810 node->ID(), cookie); 811 812 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 813 814 return sourceNode->ops->rewind_dir(sourceVolume, sourceNode, cookie); 815 } 816 817 818 // #pragma mark - Attribute Directories 819 820 821 status_t 822 bindfs_open_attr_dir(fs_volume* fsVolume, fs_vnode* fsNode, void** _cookie) 823 { 824 Volume* volume = (Volume*)fsVolume->private_volume; 825 Node* node = (Node*)fsNode->private_node; 826 827 FUNCTION("volume: %p, node: %p (%lld)\n", volume, node, node->ID()); 828 829 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 830 831 return sourceNode->ops->open_attr_dir(sourceVolume, sourceNode, _cookie); 832 } 833 834 835 status_t 836 bindfs_close_attr_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie) 837 { 838 Volume* volume = (Volume*)fsVolume->private_volume; 839 Node* node = (Node*)fsNode->private_node; 840 841 FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume, node, 842 node->ID(), cookie); 843 844 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 845 846 return sourceNode->ops->close_attr_dir(sourceVolume, sourceNode, cookie); 847 } 848 849 850 status_t 851 bindfs_free_attr_dir_cookie(fs_volume* fsVolume, fs_vnode* fsNode, 852 void* cookie) 853 { 854 Volume* volume = (Volume*)fsVolume->private_volume; 855 Node* node = (Node*)fsNode->private_node; 856 857 FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume, node, 858 node->ID(), cookie); 859 860 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 861 862 return sourceNode->ops->free_attr_dir_cookie(sourceVolume, sourceNode, 863 cookie); 864 } 865 866 867 status_t 868 bindfs_read_attr_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie, 869 struct dirent* buffer, size_t bufferSize, uint32* _count) 870 { 871 Volume* volume = (Volume*)fsVolume->private_volume; 872 Node* node = (Node*)fsNode->private_node; 873 874 FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume, node, 875 node->ID(), cookie); 876 877 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 878 879 return sourceNode->ops->read_attr_dir(sourceVolume, sourceNode, cookie, 880 buffer, bufferSize, _count); 881 } 882 883 884 status_t 885 bindfs_rewind_attr_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie) 886 { 887 Volume* volume = (Volume*)fsVolume->private_volume; 888 Node* node = (Node*)fsNode->private_node; 889 890 FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume, node, 891 node->ID(), cookie); 892 893 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 894 895 return sourceNode->ops->rewind_attr_dir(sourceVolume, sourceNode, cookie); 896 } 897 898 899 // #pragma mark - Attribute Operations 900 901 902 status_t 903 bindfs_create_attr(fs_volume* fsVolume, fs_vnode* fsNode, const char* name, 904 uint32 type, int openMode, void** _cookie) 905 { 906 Volume* volume = (Volume*)fsVolume->private_volume; 907 Node* node = (Node*)fsNode->private_node; 908 909 FUNCTION("volume: %p, node: %p (%lld), name: \"%s\", type: %lx, " 910 "openMode %#x\n", 911 volume, node, node->ID(), name, type, openMode); 912 913 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 914 915 return sourceNode->ops->create_attr(sourceVolume, sourceNode, name, type, 916 openMode, _cookie); 917 } 918 919 920 status_t 921 bindfs_open_attr(fs_volume* fsVolume, fs_vnode* fsNode, const char* name, 922 int openMode, void** _cookie) 923 { 924 Volume* volume = (Volume*)fsVolume->private_volume; 925 Node* node = (Node*)fsNode->private_node; 926 927 FUNCTION("volume: %p, node: %p (%lld), name: \"%s\", openMode %#x\n", 928 volume, node, node->ID(), name, openMode); 929 930 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 931 932 return sourceNode->ops->open_attr(sourceVolume, sourceNode, name, openMode, 933 _cookie); 934 } 935 936 937 status_t 938 bindfs_close_attr(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie) 939 { 940 Volume* volume = (Volume*)fsVolume->private_volume; 941 Node* node = (Node*)fsNode->private_node; 942 943 FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume, node, 944 node->ID(), cookie); 945 946 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 947 948 return sourceNode->ops->close_attr(sourceVolume, sourceNode, cookie); 949 } 950 951 952 status_t 953 bindfs_free_attr_cookie(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie) 954 { 955 Volume* volume = (Volume*)fsVolume->private_volume; 956 Node* node = (Node*)fsNode->private_node; 957 958 FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume, node, 959 node->ID(), cookie); 960 961 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 962 963 return sourceNode->ops->free_attr_cookie(sourceVolume, sourceNode, cookie); 964 } 965 966 967 status_t 968 bindfs_read_attr(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie, 969 off_t offset, void* buffer, size_t* bufferSize) 970 { 971 Volume* volume = (Volume*)fsVolume->private_volume; 972 Node* node = (Node*)fsNode->private_node; 973 974 FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume, node, 975 node->ID(), cookie); 976 977 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 978 979 return sourceNode->ops->read_attr(sourceVolume, sourceNode, cookie, offset, 980 buffer, bufferSize); 981 } 982 983 984 status_t 985 bindfs_write_attr(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie, 986 off_t offset, const void* buffer, size_t* bufferSize) 987 { 988 Volume* volume = (Volume*)fsVolume->private_volume; 989 Node* node = (Node*)fsNode->private_node; 990 991 FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume, node, 992 node->ID(), cookie); 993 994 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 995 996 return sourceNode->ops->write_attr(sourceVolume, sourceNode, cookie, offset, 997 buffer, bufferSize); 998 } 999 1000 1001 status_t 1002 bindfs_read_attr_stat(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie, 1003 struct stat* st) 1004 { 1005 Volume* volume = (Volume*)fsVolume->private_volume; 1006 Node* node = (Node*)fsNode->private_node; 1007 1008 FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume, node, 1009 node->ID(), cookie); 1010 1011 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 1012 1013 error 1014 = sourceNode->ops->read_attr_stat(sourceVolume, sourceNode, cookie, st); 1015 if (error != B_OK) 1016 RETURN_ERROR(error); 1017 1018 st->st_dev = volume->ID(); 1019 1020 return B_OK; 1021 } 1022 1023 1024 status_t 1025 bindfs_write_attr_stat(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie, 1026 const struct stat* _st, int statMask) 1027 { 1028 Volume* volume = (Volume*)fsVolume->private_volume; 1029 Node* node = (Node*)fsNode->private_node; 1030 1031 FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume, node, 1032 node->ID(), cookie); 1033 1034 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 1035 1036 struct stat st; 1037 memcpy(&st, _st, sizeof(st)); 1038 st.st_dev = sourceVolume->id; 1039 1040 return sourceNode->ops->write_attr_stat(sourceVolume, sourceNode, cookie, 1041 &st, statMask); 1042 } 1043 1044 1045 static status_t 1046 bindfs_rename_attr(fs_volume* fsVolume, fs_vnode* fsNode, const char* fromName, 1047 fs_vnode* toDir, const char* toName) 1048 { 1049 Volume* volume = (Volume*)fsVolume->private_volume; 1050 Node* node = (Node*)fsNode->private_node; 1051 1052 FUNCTION("volume: %p, node: %p (%lld), from: %s, toDir: %p, to: %s\n", 1053 volume, node, node->ID(), fromName, toDir, toName); 1054 1055 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 1056 1057 return sourceNode->ops->rename_attr(sourceVolume, sourceNode, fromName, 1058 toDir, toName); 1059 } 1060 1061 1062 static status_t 1063 bindfs_remove_attr(fs_volume* fsVolume, fs_vnode* fsNode, const char* name) 1064 { 1065 Volume* volume = (Volume*)fsVolume->private_volume; 1066 Node* node = (Node*)fsNode->private_node; 1067 1068 FUNCTION("volume: %p, node: %p (%lld), name: %s\n", volume, node, 1069 node->ID(), name); 1070 1071 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 1072 1073 return sourceNode->ops->remove_attr(sourceVolume, sourceNode, name); 1074 } 1075 1076 1077 // #pragma mark - Module Interface 1078 1079 1080 static status_t 1081 bindfs_std_ops(int32 op, ...) 1082 { 1083 switch (op) { 1084 case B_MODULE_INIT: 1085 { 1086 init_debugging(); 1087 PRINT("bindfs_std_ops(): B_MODULE_INIT\n"); 1088 1089 return B_OK; 1090 } 1091 1092 case B_MODULE_UNINIT: 1093 { 1094 PRINT("bind_std_ops(): B_MODULE_UNINIT\n"); 1095 exit_debugging(); 1096 return B_OK; 1097 } 1098 1099 default: 1100 return B_ERROR; 1101 } 1102 } 1103 1104 1105 static file_system_module_info sBindFSModuleInfo = { 1106 { 1107 "file_systems/bindfs" B_CURRENT_FS_API_VERSION, 1108 0, 1109 bindfs_std_ops, 1110 }, 1111 1112 "bindfs", // short_name 1113 "Bind File System", // pretty_name 1114 0, // DDM flags 1115 1116 1117 // scanning 1118 NULL, // identify_partition, 1119 NULL, // scan_partition, 1120 NULL, // free_identify_partition_cookie, 1121 NULL, // free_partition_content_cookie() 1122 1123 &bindfs_mount 1124 }; 1125 1126 1127 fs_volume_ops gBindFSVolumeOps = { 1128 &bindfs_unmount, 1129 &bindfs_read_fs_info, 1130 NULL, // write_fs_info, 1131 NULL, // sync, 1132 1133 &bindfs_get_vnode 1134 1135 // TODO: index operations 1136 // TODO: query operations 1137 // TODO: FS layer operations 1138 }; 1139 1140 1141 fs_vnode_ops gBindFSVnodeOps = { 1142 // vnode operations 1143 &bindfs_lookup, 1144 &bindfs_get_vnode_name, 1145 &bindfs_put_vnode, 1146 &bindfs_remove_vnode, 1147 1148 // VM file access 1149 &bindfs_can_page, 1150 &bindfs_read_pages, 1151 &bindfs_write_pages, 1152 1153 &bindfs_io, 1154 &bindfs_cancel_io, 1155 1156 &bindfs_get_file_map, 1157 1158 &bindfs_ioctl, 1159 &bindfs_set_flags, 1160 &bindfs_select, 1161 &bindfs_deselect, 1162 &bindfs_fsync, 1163 1164 &bindfs_read_symlink, 1165 &bindfs_create_symlink, 1166 1167 &bindfs_link, 1168 &bindfs_unlink, 1169 &bindfs_rename, 1170 1171 &bindfs_access, 1172 &bindfs_read_stat, 1173 &bindfs_write_stat, 1174 &bindfs_preallocate, 1175 1176 // file operations 1177 &bindfs_create, 1178 &bindfs_open, 1179 &bindfs_close, 1180 &bindfs_free_cookie, 1181 &bindfs_read, 1182 &bindfs_write, 1183 1184 // directory operations 1185 &bindfs_create_dir, 1186 &bindfs_remove_dir, 1187 &bindfs_open_dir, 1188 &bindfs_close_dir, 1189 &bindfs_free_dir_cookie, 1190 &bindfs_read_dir, 1191 &bindfs_rewind_dir, 1192 1193 // attribute directory operations 1194 &bindfs_open_attr_dir, 1195 &bindfs_close_attr_dir, 1196 &bindfs_free_attr_dir_cookie, 1197 &bindfs_read_attr_dir, 1198 &bindfs_rewind_attr_dir, 1199 1200 // attribute operations 1201 &bindfs_create_attr, 1202 &bindfs_open_attr, 1203 &bindfs_close_attr, 1204 &bindfs_free_attr_cookie, 1205 &bindfs_read_attr, 1206 &bindfs_write_attr, 1207 1208 &bindfs_read_attr_stat, 1209 &bindfs_write_attr_stat, 1210 &bindfs_rename_attr, 1211 &bindfs_remove_attr, 1212 1213 // TODO: FS layer operations 1214 }; 1215 1216 1217 module_info *modules[] = { 1218 (module_info *)&sBindFSModuleInfo, 1219 NULL, 1220 }; 1221