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 <AutoDeleterDrivers.h> 16 17 #include "DebugSupport.h" 18 #include "kernel_interface.h" 19 #include "Node.h" 20 #include "Volume.h" 21 22 23 /*! \brief Binds an arbitrary folder to a given path (which must be that of a 24 folder, too). All requests to the mounted path will be passed to the 25 corresponding node of the bound (source) filesystem. 26 27 TODO: node monitoring! 28 29 TODO: path filter, such that /dev can be bind-mounted with only a subset 30 of entries 31 32 TODO: Since the source node IDs are used for our nodes, this doesn't work 33 for source trees with submounts. 34 35 TODO: There's no file cache support (required for mmap()). We implement the 36 hooks, but they aren't used. 37 */ 38 39 40 // #pragma mark - helper macros 41 42 43 #define FETCH_SOURCE_VOLUME_AND_NODE(volume, nodeID) \ 44 fs_volume* sourceVolume = volume->SourceFSVolume(); \ 45 if (sourceVolume == NULL) \ 46 RETURN_ERROR(B_ERROR); \ 47 vnode* sourceVnode; \ 48 status_t error = vfs_get_vnode(volume->SourceFSVolume()->id, \ 49 nodeID, true, &sourceVnode); \ 50 if (error != B_OK) \ 51 RETURN_ERROR(error); \ 52 VnodePutter putter(sourceVnode); \ 53 fs_vnode* sourceNode = vfs_fsnode_for_vnode(sourceVnode); \ 54 if (sourceNode == NULL) \ 55 RETURN_ERROR(B_ERROR); 56 57 58 // #pragma mark - Volume 59 60 61 static status_t 62 bindfs_mount(fs_volume* fsVolume, const char* device, uint32 flags, 63 const char* parameters, ino_t* _rootID) 64 { 65 FUNCTION("fsVolume: %p, device: \"%s\", flags: %#" B_PRIx32 ", " 66 "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 (%" B_PRIdINO "), entry: \"%s\"\n", 142 volume, node, 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: %" B_PRIdINO "\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 (%" B_PRIdINO "), cookie: %p\n", 248 volume, 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 (%" B_PRIdINO "), cookie: %p, " 264 "pos: %" B_PRIdOFF ", vecs: %p, 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 (%" B_PRIdINO "), cookie: %p, " 282 "pos: %" B_PRIdOFF ", vecs: %p, 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 (%" B_PRIdINO "), cookie: %p, request: %p\n", 306 volume, 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 (%" B_PRIdINO "), cookie: %p, request: %p\n", 322 volume, 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 (%" B_PRIdINO "), offset: %" B_PRIdOFF ", " 342 "size: %ld, vecs: %p\n", 343 volume, node, node->ID(), offset, size, vecs); 344 345 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 346 347 return sourceNode->ops->get_file_map(sourceVolume, sourceNode, offset, size, 348 vecs, _count); 349 } 350 351 352 // #pragma mark - Special 353 354 355 static status_t 356 bindfs_ioctl(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie, uint32 op, 357 void* buffer, size_t length) 358 { 359 Volume* volume = (Volume*)fsVolume->private_volume; 360 Node* node = (Node*)fsNode->private_node; 361 362 FUNCTION("volume: %p, node: %p (%" B_PRIdINO "), cookie: %p, " 363 "op: %" B_PRIx32 ", buffer: %p, length: %ld\n", 364 volume, node, node->ID(), cookie, op, buffer, length); 365 366 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 367 368 return sourceNode->ops->ioctl(sourceVolume, sourceNode, cookie, op, buffer, 369 length); 370 } 371 372 373 static status_t 374 bindfs_set_flags(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie, int flags) 375 { 376 Volume* volume = (Volume*)fsVolume->private_volume; 377 Node* node = (Node*)fsNode->private_node; 378 379 FUNCTION("volume: %p, node: %p (%" B_PRIdINO "), cookie: %p, flags: %x\n", 380 volume, node, node->ID(), cookie, flags); 381 382 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 383 384 return sourceNode->ops->set_flags(sourceVolume, sourceNode, cookie, flags); 385 } 386 387 388 static status_t 389 bindfs_select(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie, uint8 event, 390 selectsync* sync) 391 { 392 Volume* volume = (Volume*)fsVolume->private_volume; 393 Node* node = (Node*)fsNode->private_node; 394 395 FUNCTION("volume: %p, node: %p (%" B_PRIdINO "), cookie: %p, event: %x, " 396 "sync: %p\n", 397 volume, node, node->ID(), cookie, event, sync); 398 399 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 400 401 return sourceNode->ops->select(sourceVolume, sourceNode, cookie, event, 402 sync); 403 } 404 405 406 static status_t 407 bindfs_deselect(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie, 408 uint8 event, selectsync* sync) 409 { 410 Volume* volume = (Volume*)fsVolume->private_volume; 411 Node* node = (Node*)fsNode->private_node; 412 413 FUNCTION("volume: %p, node: %p (%" B_PRIdINO "), cookie: %p, event: %x, " 414 "sync: %p\n", 415 volume, node, node->ID(), cookie, event, sync); 416 417 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 418 419 return sourceNode->ops->deselect(sourceVolume, sourceNode, cookie, event, 420 sync); 421 } 422 423 424 static status_t 425 bindfs_fsync(fs_volume* fsVolume, fs_vnode* fsNode) 426 { 427 Volume* volume = (Volume*)fsVolume->private_volume; 428 Node* node = (Node*)fsNode->private_node; 429 430 FUNCTION("volume: %p, node: %p (%" B_PRIdINO ")\n", 431 volume, node, node->ID()); 432 433 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 434 435 return sourceNode->ops->fsync(sourceVolume, sourceNode); 436 } 437 438 439 // #pragma mark - Nodes 440 441 442 static status_t 443 bindfs_read_symlink(fs_volume* fsVolume, fs_vnode* fsNode, char* buffer, 444 size_t* _bufferSize) 445 { 446 Volume* volume = (Volume*)fsVolume->private_volume; 447 Node* node = (Node*)fsNode->private_node; 448 449 FUNCTION("volume: %p, node: %p (%" B_PRIdINO ")\n", 450 volume, node, node->ID()); 451 452 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 453 454 return sourceNode->ops->read_symlink(sourceVolume, sourceNode, buffer, 455 _bufferSize); 456 } 457 458 459 static status_t 460 bindfs_create_symlink(fs_volume* fsVolume, fs_vnode* fsNode, const char* name, 461 const char* path, int mode) 462 { 463 Volume* volume = (Volume*)fsVolume->private_volume; 464 Node* node = (Node*)fsNode->private_node; 465 466 FUNCTION("volume: %p, node: %p (%" B_PRIdINO "), " 467 "name: %s, path: %s, mode: %x\n", 468 volume, node, node->ID(), name, path, mode); 469 470 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 471 472 return sourceNode->ops->create_symlink(sourceVolume, sourceNode, name, path, 473 mode); 474 } 475 476 477 static status_t 478 bindfs_link(fs_volume* fsVolume, fs_vnode* fsNode, const char* name, 479 fs_vnode* toNode) 480 { 481 Volume* volume = (Volume*)fsVolume->private_volume; 482 Node* node = (Node*)fsNode->private_node; 483 484 FUNCTION("volume: %p, node: %p (%" B_PRIdINO "), " 485 "name: %s, tonode: %p\n", 486 volume, node, node->ID(), name, toNode); 487 488 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 489 490 return sourceNode->ops->link(sourceVolume, sourceNode, name, toNode); 491 } 492 493 494 static status_t 495 bindfs_unlink(fs_volume* fsVolume, fs_vnode* fsNode, const char* name) 496 { 497 Volume* volume = (Volume*)fsVolume->private_volume; 498 Node* node = (Node*)fsNode->private_node; 499 500 FUNCTION("volume: %p, node: %p (%" B_PRIdINO "), name: %s\n", 501 volume, node, node->ID(), name); 502 503 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 504 505 return sourceNode->ops->unlink(sourceVolume, sourceNode, name); 506 } 507 508 509 static status_t 510 bindfs_rename(fs_volume* fsVolume, fs_vnode* fsNode, const char* fromName, 511 fs_vnode* toDir, const char* toName) 512 { 513 Volume* volume = (Volume*)fsVolume->private_volume; 514 Node* node = (Node*)fsNode->private_node; 515 516 FUNCTION("volume: %p, node: %p (%" B_PRIdINO "), " 517 "from: %s, toDir: %p, to: %s\n", 518 volume, node, node->ID(), fromName, toDir, toName); 519 520 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 521 522 return sourceNode->ops->rename(sourceVolume, sourceNode, fromName, toDir, 523 toName); 524 } 525 526 527 static status_t 528 bindfs_access(fs_volume* fsVolume, fs_vnode* fsNode, int mode) 529 { 530 Volume* volume = (Volume*)fsVolume->private_volume; 531 Node* node = (Node*)fsNode->private_node; 532 533 FUNCTION("volume: %p, node: %p (%" B_PRIdINO" )\n", 534 volume, node, node->ID()); 535 536 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 537 538 return sourceNode->ops->access(sourceVolume, sourceNode, mode); 539 } 540 541 542 static status_t 543 bindfs_read_stat(fs_volume* fsVolume, fs_vnode* fsNode, struct stat* st) 544 { 545 Volume* volume = (Volume*)fsVolume->private_volume; 546 Node* node = (Node*)fsNode->private_node; 547 548 FUNCTION("volume: %p, node: %p (%" B_PRIdINO ")\n", 549 volume, node, node->ID()); 550 551 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 552 553 error = sourceNode->ops->read_stat(sourceVolume, sourceNode, st); 554 if (error != B_OK) 555 RETURN_ERROR(error); 556 557 st->st_dev = volume->ID(); 558 559 return B_OK; 560 } 561 562 563 static status_t 564 bindfs_write_stat(fs_volume* fsVolume, fs_vnode* fsNode, 565 const struct stat* _st, uint32 statMask) 566 { 567 Volume* volume = (Volume*)fsVolume->private_volume; 568 Node* node = (Node*)fsNode->private_node; 569 570 FUNCTION("volume: %p, node: %p (%" B_PRIdINO ")\n", 571 volume, node, node->ID()); 572 573 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 574 575 struct stat st; 576 memcpy(&st, _st, sizeof(st)); 577 st.st_dev = sourceVolume->id; 578 579 return sourceNode->ops->write_stat(sourceVolume, sourceNode, &st, statMask); 580 } 581 582 583 static status_t 584 bindfs_preallocate(fs_volume* fsVolume, fs_vnode* fsNode, off_t pos, 585 off_t length) 586 { 587 Volume* volume = (Volume*)fsVolume->private_volume; 588 Node* node = (Node*)fsNode->private_node; 589 590 FUNCTION("volume: %p, node: %p (%" B_PRIdINO "), pos: %" B_PRIdOFF ", " 591 "length: %" B_PRIdOFF "\n", 592 volume, node, node->ID(), pos, length); 593 594 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 595 596 return sourceNode->ops->preallocate(sourceVolume, sourceNode, pos, length); 597 } 598 599 600 // #pragma mark - Files 601 602 603 static status_t 604 bindfs_create(fs_volume* fsVolume, fs_vnode* fsNode, const char* name, 605 int openMode, int perms, void** _cookie, ino_t* _newVnodeID) 606 { 607 Volume* volume = (Volume*)fsVolume->private_volume; 608 Node* node = (Node*)fsNode->private_node; 609 610 FUNCTION("volume: %p, node: %p (%" B_PRIdINO "), " 611 "name: %s, openMode %#x, perms: %x\n", 612 volume, node, node->ID(), name, openMode, perms); 613 614 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 615 616 error = sourceNode->ops->create(sourceVolume, sourceNode, name, openMode, 617 perms, _cookie, _newVnodeID); 618 if (error != B_OK) 619 return error; 620 621 error = get_vnode(fsVolume, *_newVnodeID, NULL); 622 623 // on error remove the newly created source entry 624 if (error != B_OK) 625 sourceNode->ops->unlink(sourceVolume, sourceNode, name); 626 627 // create() on the source gave us a reference we don't need any longer 628 vnode* newSourceVnode; 629 if (vfs_lookup_vnode(sourceVolume->id, *_newVnodeID, &newSourceVnode) 630 == B_OK) { 631 vfs_put_vnode(newSourceVnode); 632 } 633 634 return error; 635 636 } 637 638 639 static status_t 640 bindfs_open(fs_volume* fsVolume, fs_vnode* fsNode, int openMode, 641 void** _cookie) 642 { 643 Volume* volume = (Volume*)fsVolume->private_volume; 644 Node* node = (Node*)fsNode->private_node; 645 646 FUNCTION("volume: %p, node: %p (%" B_PRIdINO "), openMode %#x\n", 647 volume, node, node->ID(), openMode); 648 649 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 650 651 return sourceNode->ops->open(sourceVolume, sourceNode, openMode, _cookie); 652 } 653 654 655 static status_t 656 bindfs_close(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie) 657 { 658 Volume* volume = (Volume*)fsVolume->private_volume; 659 Node* node = (Node*)fsNode->private_node; 660 661 FUNCTION("volume: %p, node: %p (%" B_PRIdINO "), cookie: %p\n", 662 volume, node, node->ID(), cookie); 663 664 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 665 666 return sourceNode->ops->close(sourceVolume, sourceNode, cookie); 667 } 668 669 670 static status_t 671 bindfs_free_cookie(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie) 672 { 673 Volume* volume = (Volume*)fsVolume->private_volume; 674 Node* node = (Node*)fsNode->private_node; 675 676 FUNCTION("volume: %p, node: %p (%" B_PRIdINO "), cookie: %p\n", 677 volume, node, node->ID(), cookie); 678 679 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 680 681 return sourceNode->ops->free_cookie(sourceVolume, sourceNode, cookie); 682 } 683 684 685 static status_t 686 bindfs_read(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie, 687 off_t offset, void* buffer, size_t* bufferSize) 688 { 689 Volume* volume = (Volume*)fsVolume->private_volume; 690 Node* node = (Node*)fsNode->private_node; 691 692 FUNCTION("volume: %p, node: %p (%" B_PRIdINO "), cookie: %p, " 693 "offset: %" B_PRIdOFF ", buffer: %p, size: %lu\n", 694 volume, node, node->ID(), cookie, offset, buffer, *bufferSize); 695 696 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 697 698 return sourceNode->ops->read(sourceVolume, sourceNode, cookie, offset, 699 buffer, bufferSize); 700 } 701 702 703 static status_t 704 bindfs_write(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie, 705 off_t offset, const void* buffer, size_t* bufferSize) 706 { 707 Volume* volume = (Volume*)fsVolume->private_volume; 708 Node* node = (Node*)fsNode->private_node; 709 710 FUNCTION("volume: %p, node: %p (%" B_PRIdINO "), cookie: %p, " 711 "offset: %" B_PRIdOFF ", buffer: %p, size: %lu\n", 712 volume, node, node->ID(), cookie, offset, buffer, *bufferSize); 713 714 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 715 716 return sourceNode->ops->write(sourceVolume, sourceNode, cookie, offset, 717 buffer, bufferSize); 718 } 719 720 721 // #pragma mark - Directories 722 723 724 static status_t 725 bindfs_create_dir(fs_volume* fsVolume, fs_vnode* fsNode, const char* name, 726 int perms) 727 { 728 Volume* volume = (Volume*)fsVolume->private_volume; 729 Node* node = (Node*)fsNode->private_node; 730 731 FUNCTION("volume: %p, node: %p (%" B_PRIdINO "), name: %s, perms: %x\n", 732 volume, node, node->ID(), name, perms); 733 734 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 735 736 return sourceNode->ops->create_dir(sourceVolume, sourceNode, name, perms); 737 } 738 739 740 static status_t 741 bindfs_remove_dir(fs_volume* fsVolume, fs_vnode* fsNode, const char* name) 742 { 743 Volume* volume = (Volume*)fsVolume->private_volume; 744 Node* node = (Node*)fsNode->private_node; 745 746 FUNCTION("volume: %p, node: %p (%" B_PRIdINO "), name: %s\n", volume, node, 747 node->ID(), name); 748 749 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 750 751 return sourceNode->ops->remove_dir(sourceVolume, sourceNode, name); 752 } 753 754 755 static status_t 756 bindfs_open_dir(fs_volume* fsVolume, fs_vnode* fsNode, void** _cookie) 757 { 758 Volume* volume = (Volume*)fsVolume->private_volume; 759 Node* node = (Node*)fsNode->private_node; 760 761 FUNCTION("volume: %p, node: %p (%" B_PRIdINO ")\n", 762 volume, node, node->ID()); 763 764 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 765 766 return sourceNode->ops->open_dir(sourceVolume, sourceNode, _cookie); 767 } 768 769 770 static status_t 771 bindfs_close_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie) 772 { 773 Volume* volume = (Volume*)fsVolume->private_volume; 774 Node* node = (Node*)fsNode->private_node; 775 776 FUNCTION("volume: %p, node: %p (%" B_PRIdINO "), cookie: %p\n", 777 volume, node, node->ID(), cookie); 778 779 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 780 781 return sourceNode->ops->close_dir(sourceVolume, sourceNode, cookie); 782 } 783 784 785 static status_t 786 bindfs_free_dir_cookie(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie) 787 { 788 Volume* volume = (Volume*)fsVolume->private_volume; 789 Node* node = (Node*)fsNode->private_node; 790 791 FUNCTION("volume: %p, node: %p (%" B_PRIdINO "), cookie: %p\n", 792 volume, node, node->ID(), cookie); 793 794 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 795 796 return sourceNode->ops->free_dir_cookie(sourceVolume, sourceNode, cookie); 797 } 798 799 800 static status_t 801 bindfs_read_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie, 802 struct dirent* buffer, size_t bufferSize, uint32* _count) 803 { 804 Volume* volume = (Volume*)fsVolume->private_volume; 805 Node* node = (Node*)fsNode->private_node; 806 807 FUNCTION("volume: %p, node: %p (%" B_PRIdINO "), cookie: %p\n", 808 volume, node, node->ID(), cookie); 809 810 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 811 812 return sourceNode->ops->read_dir(sourceVolume, sourceNode, cookie, buffer, 813 bufferSize, _count); 814 } 815 816 817 static status_t 818 bindfs_rewind_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie) 819 { 820 Volume* volume = (Volume*)fsVolume->private_volume; 821 Node* node = (Node*)fsNode->private_node; 822 823 FUNCTION("volume: %p, node: %p (%" B_PRIdINO "), cookie: %p\n", 824 volume, node, node->ID(), cookie); 825 826 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 827 828 return sourceNode->ops->rewind_dir(sourceVolume, sourceNode, cookie); 829 } 830 831 832 // #pragma mark - Attribute Directories 833 834 835 status_t 836 bindfs_open_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 (%" B_PRIdINO ")\n", 842 volume, node, node->ID()); 843 844 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 845 846 return sourceNode->ops->open_attr_dir(sourceVolume, sourceNode, _cookie); 847 } 848 849 850 status_t 851 bindfs_close_attr_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie) 852 { 853 Volume* volume = (Volume*)fsVolume->private_volume; 854 Node* node = (Node*)fsNode->private_node; 855 856 FUNCTION("volume: %p, node: %p (%" B_PRIdINO "), cookie: %p\n", 857 volume, node, node->ID(), cookie); 858 859 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 860 861 return sourceNode->ops->close_attr_dir(sourceVolume, sourceNode, cookie); 862 } 863 864 865 status_t 866 bindfs_free_attr_dir_cookie(fs_volume* fsVolume, fs_vnode* fsNode, 867 void* cookie) 868 { 869 Volume* volume = (Volume*)fsVolume->private_volume; 870 Node* node = (Node*)fsNode->private_node; 871 872 FUNCTION("volume: %p, node: %p (%" B_PRIdINO "), cookie: %p\n", 873 volume, node, node->ID(), cookie); 874 875 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 876 877 return sourceNode->ops->free_attr_dir_cookie(sourceVolume, sourceNode, 878 cookie); 879 } 880 881 882 status_t 883 bindfs_read_attr_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie, 884 struct dirent* buffer, size_t bufferSize, uint32* _count) 885 { 886 Volume* volume = (Volume*)fsVolume->private_volume; 887 Node* node = (Node*)fsNode->private_node; 888 889 FUNCTION("volume: %p, node: %p (%" B_PRIdINO "), cookie: %p\n", 890 volume, node, node->ID(), cookie); 891 892 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 893 894 return sourceNode->ops->read_attr_dir(sourceVolume, sourceNode, cookie, 895 buffer, bufferSize, _count); 896 } 897 898 899 status_t 900 bindfs_rewind_attr_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie) 901 { 902 Volume* volume = (Volume*)fsVolume->private_volume; 903 Node* node = (Node*)fsNode->private_node; 904 905 FUNCTION("volume: %p, node: %p (%" B_PRIdINO "), cookie: %p\n", 906 volume, node, node->ID(), cookie); 907 908 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 909 910 return sourceNode->ops->rewind_attr_dir(sourceVolume, sourceNode, cookie); 911 } 912 913 914 // #pragma mark - Attribute Operations 915 916 917 status_t 918 bindfs_create_attr(fs_volume* fsVolume, fs_vnode* fsNode, const char* name, 919 uint32 type, int openMode, void** _cookie) 920 { 921 Volume* volume = (Volume*)fsVolume->private_volume; 922 Node* node = (Node*)fsNode->private_node; 923 924 FUNCTION("volume: %p, node: %p (%" B_PRIdINO "), name: \"%s\", " 925 "type: %" B_PRIx32 ", openMode %#x\n", 926 volume, node, node->ID(), name, type, openMode); 927 928 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 929 930 return sourceNode->ops->create_attr(sourceVolume, sourceNode, name, type, 931 openMode, _cookie); 932 } 933 934 935 status_t 936 bindfs_open_attr(fs_volume* fsVolume, fs_vnode* fsNode, const char* name, 937 int openMode, void** _cookie) 938 { 939 Volume* volume = (Volume*)fsVolume->private_volume; 940 Node* node = (Node*)fsNode->private_node; 941 942 FUNCTION("volume: %p, node: %p (%" B_PRIdINO "), name: \"%s\", " 943 "openMode %#x\n", 944 volume, node, node->ID(), name, openMode); 945 946 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 947 948 return sourceNode->ops->open_attr(sourceVolume, sourceNode, name, openMode, 949 _cookie); 950 } 951 952 953 status_t 954 bindfs_close_attr(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie) 955 { 956 Volume* volume = (Volume*)fsVolume->private_volume; 957 Node* node = (Node*)fsNode->private_node; 958 959 FUNCTION("volume: %p, node: %p (%" B_PRIdINO "), cookie: %p\n", 960 volume, node, node->ID(), cookie); 961 962 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 963 964 return sourceNode->ops->close_attr(sourceVolume, sourceNode, cookie); 965 } 966 967 968 status_t 969 bindfs_free_attr_cookie(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie) 970 { 971 Volume* volume = (Volume*)fsVolume->private_volume; 972 Node* node = (Node*)fsNode->private_node; 973 974 FUNCTION("volume: %p, node: %p (%" B_PRIdINO "), cookie: %p\n", 975 volume, node, node->ID(), cookie); 976 977 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 978 979 return sourceNode->ops->free_attr_cookie(sourceVolume, sourceNode, cookie); 980 } 981 982 983 status_t 984 bindfs_read_attr(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie, 985 off_t offset, void* buffer, size_t* bufferSize) 986 { 987 Volume* volume = (Volume*)fsVolume->private_volume; 988 Node* node = (Node*)fsNode->private_node; 989 990 FUNCTION("volume: %p, node: %p (%" B_PRIdINO "), cookie: %p\n", 991 volume, node, node->ID(), cookie); 992 993 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 994 995 return sourceNode->ops->read_attr(sourceVolume, sourceNode, cookie, offset, 996 buffer, bufferSize); 997 } 998 999 1000 status_t 1001 bindfs_write_attr(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie, 1002 off_t offset, const void* buffer, size_t* bufferSize) 1003 { 1004 Volume* volume = (Volume*)fsVolume->private_volume; 1005 Node* node = (Node*)fsNode->private_node; 1006 1007 FUNCTION("volume: %p, node: %p (%" B_PRIdINO "), cookie: %p\n", 1008 volume, node, node->ID(), cookie); 1009 1010 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 1011 1012 return sourceNode->ops->write_attr(sourceVolume, sourceNode, cookie, offset, 1013 buffer, bufferSize); 1014 } 1015 1016 1017 status_t 1018 bindfs_read_attr_stat(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie, 1019 struct stat* st) 1020 { 1021 Volume* volume = (Volume*)fsVolume->private_volume; 1022 Node* node = (Node*)fsNode->private_node; 1023 1024 FUNCTION("volume: %p, node: %p (%" B_PRIdINO "), cookie: %p\n", 1025 volume, node, node->ID(), cookie); 1026 1027 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 1028 1029 error 1030 = sourceNode->ops->read_attr_stat(sourceVolume, sourceNode, cookie, st); 1031 if (error != B_OK) 1032 RETURN_ERROR(error); 1033 1034 st->st_dev = volume->ID(); 1035 1036 return B_OK; 1037 } 1038 1039 1040 status_t 1041 bindfs_write_attr_stat(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie, 1042 const struct stat* _st, int statMask) 1043 { 1044 Volume* volume = (Volume*)fsVolume->private_volume; 1045 Node* node = (Node*)fsNode->private_node; 1046 1047 FUNCTION("volume: %p, node: %p (%" B_PRIdINO"), cookie: %p\n", 1048 volume, node, node->ID(), cookie); 1049 1050 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 1051 1052 struct stat st; 1053 memcpy(&st, _st, sizeof(st)); 1054 st.st_dev = sourceVolume->id; 1055 1056 return sourceNode->ops->write_attr_stat(sourceVolume, sourceNode, cookie, 1057 &st, statMask); 1058 } 1059 1060 1061 static status_t 1062 bindfs_rename_attr(fs_volume* fsVolume, fs_vnode* fsNode, const char* fromName, 1063 fs_vnode* toDir, const char* toName) 1064 { 1065 Volume* volume = (Volume*)fsVolume->private_volume; 1066 Node* node = (Node*)fsNode->private_node; 1067 1068 FUNCTION("volume: %p, node: %p (%" B_PRIdINO "), from: %s, toDir: %p, " 1069 "to: %s\n", 1070 volume, node, node->ID(), fromName, toDir, toName); 1071 1072 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 1073 1074 return sourceNode->ops->rename_attr(sourceVolume, sourceNode, fromName, 1075 toDir, toName); 1076 } 1077 1078 1079 static status_t 1080 bindfs_remove_attr(fs_volume* fsVolume, fs_vnode* fsNode, const char* name) 1081 { 1082 Volume* volume = (Volume*)fsVolume->private_volume; 1083 Node* node = (Node*)fsNode->private_node; 1084 1085 FUNCTION("volume: %p, node: %p (%" B_PRIdINO "), name: %s\n", 1086 volume, node, node->ID(), name); 1087 1088 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID()); 1089 1090 return sourceNode->ops->remove_attr(sourceVolume, sourceNode, name); 1091 } 1092 1093 1094 // #pragma mark - Module Interface 1095 1096 1097 static status_t 1098 bindfs_std_ops(int32 op, ...) 1099 { 1100 switch (op) { 1101 case B_MODULE_INIT: 1102 { 1103 init_debugging(); 1104 PRINT("bindfs_std_ops(): B_MODULE_INIT\n"); 1105 1106 return B_OK; 1107 } 1108 1109 case B_MODULE_UNINIT: 1110 { 1111 PRINT("bind_std_ops(): B_MODULE_UNINIT\n"); 1112 exit_debugging(); 1113 return B_OK; 1114 } 1115 1116 default: 1117 return B_ERROR; 1118 } 1119 } 1120 1121 1122 static file_system_module_info sBindFSModuleInfo = { 1123 { 1124 "file_systems/bindfs" B_CURRENT_FS_API_VERSION, 1125 0, 1126 bindfs_std_ops, 1127 }, 1128 1129 "bindfs", // short_name 1130 "Bind File System", // pretty_name 1131 0, // DDM flags 1132 1133 1134 // scanning 1135 NULL, // identify_partition, 1136 NULL, // scan_partition, 1137 NULL, // free_identify_partition_cookie, 1138 NULL, // free_partition_content_cookie() 1139 1140 &bindfs_mount 1141 }; 1142 1143 1144 fs_volume_ops gBindFSVolumeOps = { 1145 &bindfs_unmount, 1146 &bindfs_read_fs_info, 1147 NULL, // write_fs_info, 1148 NULL, // sync, 1149 1150 &bindfs_get_vnode 1151 1152 // TODO: index operations 1153 // TODO: query operations 1154 // TODO: FS layer operations 1155 }; 1156 1157 1158 fs_vnode_ops gBindFSVnodeOps = { 1159 // vnode operations 1160 &bindfs_lookup, 1161 &bindfs_get_vnode_name, 1162 &bindfs_put_vnode, 1163 &bindfs_remove_vnode, 1164 1165 // VM file access 1166 &bindfs_can_page, 1167 &bindfs_read_pages, 1168 &bindfs_write_pages, 1169 1170 &bindfs_io, 1171 &bindfs_cancel_io, 1172 1173 &bindfs_get_file_map, 1174 1175 &bindfs_ioctl, 1176 &bindfs_set_flags, 1177 &bindfs_select, 1178 &bindfs_deselect, 1179 &bindfs_fsync, 1180 1181 &bindfs_read_symlink, 1182 &bindfs_create_symlink, 1183 1184 &bindfs_link, 1185 &bindfs_unlink, 1186 &bindfs_rename, 1187 1188 &bindfs_access, 1189 &bindfs_read_stat, 1190 &bindfs_write_stat, 1191 &bindfs_preallocate, 1192 1193 // file operations 1194 &bindfs_create, 1195 &bindfs_open, 1196 &bindfs_close, 1197 &bindfs_free_cookie, 1198 &bindfs_read, 1199 &bindfs_write, 1200 1201 // directory operations 1202 &bindfs_create_dir, 1203 &bindfs_remove_dir, 1204 &bindfs_open_dir, 1205 &bindfs_close_dir, 1206 &bindfs_free_dir_cookie, 1207 &bindfs_read_dir, 1208 &bindfs_rewind_dir, 1209 1210 // attribute directory operations 1211 &bindfs_open_attr_dir, 1212 &bindfs_close_attr_dir, 1213 &bindfs_free_attr_dir_cookie, 1214 &bindfs_read_attr_dir, 1215 &bindfs_rewind_attr_dir, 1216 1217 // attribute operations 1218 &bindfs_create_attr, 1219 &bindfs_open_attr, 1220 &bindfs_close_attr, 1221 &bindfs_free_attr_cookie, 1222 &bindfs_read_attr, 1223 &bindfs_write_attr, 1224 1225 &bindfs_read_attr_stat, 1226 &bindfs_write_attr_stat, 1227 &bindfs_rename_attr, 1228 &bindfs_remove_attr, 1229 1230 // TODO: FS layer operations 1231 }; 1232 1233 1234 module_info *modules[] = { 1235 (module_info *)&sBindFSModuleInfo, 1236 NULL, 1237 }; 1238