2 * Copyright 2011, Oliver Tappe <zooey@hirschkaefer.de>
3 * Distributed under the terms of the MIT License.
10 #include <fs_interface.h>
11 #include <KernelExport.h>
15 #include <AutoDeleter.h>
17 #include "DebugSupport.h"
18 #include "kernel_interface.h"
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.
28 TODO: node monitoring!
30 TODO: path filter, such that /dev can be bind-mounted with only a subset
33 TODO: Since the source node IDs are used for our nodes, this doesn't work
34 for source trees with submounts.
36 TODO: There's no file cache support (required for mmap()). We implement the
37 hooks, but they aren't used.
41 // #pragma mark - helper macros
44 #define FETCH_SOURCE_VOLUME_AND_NODE(volume, nodeID) \
45 fs_volume* sourceVolume = volume->SourceFSVolume(); \
46 if (sourceVolume == NULL) \
47 RETURN_ERROR(B_ERROR); \
49 status_t error = vfs_get_vnode(volume->SourceFSVolume()->id, \
50 nodeID, true, &sourceVnode); \
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);
59 // #pragma mark - Volume
63 bindfs_mount(fs_volume
* fsVolume
, const char* device
, uint32 flags
,
64 const char* parameters
, ino_t
* _rootID
)
66 FUNCTION("fsVolume: %p, device: \"%s\", flags: %#lx, parameters: \"%s\"\n",
67 fsVolume
, device
, flags
, parameters
);
69 // create a Volume object
70 Volume
* volume
= new(std::nothrow
) Volume(fsVolume
);
72 RETURN_ERROR(B_NO_MEMORY
);
73 ObjectDeleter
<Volume
> volumeDeleter(volume
);
75 status_t error
= volume
->Mount(parameters
);
80 *_rootID
= volume
->RootNode()->ID();
81 fsVolume
->private_volume
= volumeDeleter
.Detach();
82 fsVolume
->ops
= &gBindFSVolumeOps
;
89 bindfs_unmount(fs_volume
* fsVolume
)
91 Volume
* volume
= (Volume
*)fsVolume
->private_volume
;
93 FUNCTION("volume: %p\n", volume
);
103 bindfs_read_fs_info(fs_volume
* fsVolume
, struct fs_info
* info
)
105 Volume
* volume
= (Volume
*)fsVolume
->private_volume
;
107 FUNCTION("volume: %p, info: %p\n", volume
, info
);
109 fs_volume
* sourceVolume
= volume
->SourceFSVolume();
111 if (sourceVolume
->ops
->read_fs_info
!= NULL
) {
112 status_t error
= sourceVolume
->ops
->read_fs_info(sourceVolume
, info
);
116 info
->block_size
= 512;
117 info
->io_size
= 64 * 1024;
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;
125 strlcpy(info
->volume_name
, volume
->Name(), sizeof(info
->volume_name
));
131 // #pragma mark - VNodes
135 bindfs_lookup(fs_volume
* fsVolume
, fs_vnode
* fsDir
, const char* entryName
,
138 Volume
* volume
= (Volume
*)fsVolume
->private_volume
;
139 Node
* node
= (Node
*)fsDir
->private_node
;
141 FUNCTION("volume: %p, dir: %p (%lld), entry: \"%s\"\n", volume
, node
,
142 node
->ID(), entryName
);
144 FETCH_SOURCE_VOLUME_AND_NODE(volume
, node
->ID());
146 error
= sourceNode
->ops
->lookup(sourceVolume
, sourceNode
, entryName
, _vnid
);
150 error
= get_vnode(fsVolume
, *_vnid
, NULL
);
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
);
162 bindfs_get_vnode(fs_volume
* fsVolume
, ino_t vnid
, fs_vnode
* fsNode
,
163 int* _type
, uint32
* _flags
, bool reenter
)
165 Volume
* volume
= (Volume
*)fsVolume
->private_volume
;
167 FUNCTION("volume: %p, vnid: %lld\n", volume
, vnid
);
169 FETCH_SOURCE_VOLUME_AND_NODE(volume
, vnid
);
172 error
= sourceNode
->ops
->read_stat(sourceVolume
, sourceNode
, &st
);
174 Node
* node
= new(std::nothrow
) Node(vnid
, st
.st_mode
);
176 RETURN_ERROR(B_NO_MEMORY
);
178 fsNode
->private_node
= node
;
179 fsNode
->ops
= const_cast<fs_vnode_ops
*>(volume
->VnodeOps());
180 *_type
= node
->Mode() & S_IFMT
;
188 bindfs_get_vnode_name(fs_volume
* fsVolume
, fs_vnode
* fsNode
, char* buffer
,
191 Volume
* volume
= (Volume
*)fsVolume
->private_volume
;
192 Node
* node
= (Node
*)fsNode
->private_node
;
194 FUNCTION("volume: %p, node: %p\n", volume
, node
);
196 FETCH_SOURCE_VOLUME_AND_NODE(volume
, node
->ID());
198 return sourceNode
->ops
->get_vnode_name(sourceVolume
, sourceNode
, buffer
,
203 bindfs_put_vnode(fs_volume
* fsVolume
, fs_vnode
* fsNode
, bool reenter
)
205 Volume
* volume
= (Volume
*)fsVolume
->private_volume
;
206 Node
* node
= (Node
*)fsNode
->private_node
;
208 FUNCTION("volume: %p, node: %p\n", volume
, node
);
210 FETCH_SOURCE_VOLUME_AND_NODE(volume
, node
->ID());
219 bindfs_remove_vnode(fs_volume
* fsVolume
, fs_vnode
* fsNode
, bool reenter
)
221 Volume
* volume
= (Volume
*)fsVolume
->private_volume
;
222 Node
* node
= (Node
*)fsNode
->private_node
;
224 FUNCTION("volume: %p, node: %p\n", volume
, node
);
226 FETCH_SOURCE_VOLUME_AND_NODE(volume
, node
->ID());
230 return sourceNode
->ops
->remove_vnode(sourceVolume
, sourceNode
, reenter
);
234 // #pragma mark - VM access
237 // TODO: These hooks are obsolete. Since we don't create a file cache, they
238 // aren't needed anyway.
242 bindfs_can_page(fs_volume
* fsVolume
, fs_vnode
* fsNode
, void* cookie
)
244 Volume
* volume
= (Volume
*)fsVolume
->private_volume
;
245 Node
* node
= (Node
*)fsNode
->private_node
;
247 FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume
,
248 node
, node
->ID(), cookie
);
250 FETCH_SOURCE_VOLUME_AND_NODE(volume
, node
->ID());
252 return sourceNode
->ops
->can_page(sourceVolume
, sourceNode
, cookie
);
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
)
260 Volume
* volume
= (Volume
*)fsVolume
->private_volume
;
261 Node
* node
= (Node
*)fsNode
->private_node
;
263 FUNCTION("volume: %p, node: %p (%lld), cookie: %p, pos: %lld, vecs: %p, "
265 volume
, node
, node
->ID(), cookie
, pos
, vecs
, count
);
267 FETCH_SOURCE_VOLUME_AND_NODE(volume
, node
->ID());
269 return sourceNode
->ops
->read_pages(sourceVolume
, sourceNode
, cookie
, pos
,
270 vecs
, count
, _numBytes
);
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
)
278 Volume
* volume
= (Volume
*)fsVolume
->private_volume
;
279 Node
* node
= (Node
*)fsNode
->private_node
;
281 FUNCTION("volume: %p, node: %p (%lld), cookie: %p, pos: %lld, vecs: %p, "
283 volume
, node
, node
->ID(), cookie
, pos
, vecs
, count
);
285 FETCH_SOURCE_VOLUME_AND_NODE(volume
, node
->ID());
287 return sourceNode
->ops
->write_pages(sourceVolume
, sourceNode
, cookie
, pos
,
288 vecs
, count
, _numBytes
);
292 // #pragma mark - Request I/O
295 // TODO: Since we don't create a file cache, these hooks aren't needed.
299 bindfs_io(fs_volume
* fsVolume
, fs_vnode
* fsNode
, void* cookie
,
302 Volume
* volume
= (Volume
*)fsVolume
->private_volume
;
303 Node
* node
= (Node
*)fsNode
->private_node
;
305 FUNCTION("volume: %p, node: %p (%lld), cookie: %p, request: %p\n", volume
,
306 node
, node
->ID(), cookie
, request
);
308 FETCH_SOURCE_VOLUME_AND_NODE(volume
, node
->ID());
310 return sourceNode
->ops
->io(sourceVolume
, sourceNode
, cookie
, request
);
315 bindfs_cancel_io(fs_volume
* fsVolume
, fs_vnode
* fsNode
, void* cookie
,
318 Volume
* volume
= (Volume
*)fsVolume
->private_volume
;
319 Node
* node
= (Node
*)fsNode
->private_node
;
321 FUNCTION("volume: %p, node: %p (%lld), cookie: %p, request: %p\n", volume
,
322 node
, node
->ID(), cookie
, request
);
324 FETCH_SOURCE_VOLUME_AND_NODE(volume
, node
->ID());
326 return sourceNode
->ops
->cancel_io(sourceVolume
, sourceNode
, cookie
,
331 // #pragma mark - File Map
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
)
338 Volume
* volume
= (Volume
*)fsVolume
->private_volume
;
339 Node
* node
= (Node
*)fsNode
->private_node
;
341 FUNCTION("volume: %p, node: %p (%lld), offset: %lld, size: %ld, vecs: %p\n",
342 volume
, node
, node
->ID(), offset
, size
, vecs
);
344 FETCH_SOURCE_VOLUME_AND_NODE(volume
, node
->ID());
346 return sourceNode
->ops
->get_file_map(sourceVolume
, sourceNode
, offset
, size
,
351 // #pragma mark - Special
355 bindfs_ioctl(fs_volume
* fsVolume
, fs_vnode
* fsNode
, void* cookie
, uint32 op
,
356 void* buffer
, size_t length
)
358 Volume
* volume
= (Volume
*)fsVolume
->private_volume
;
359 Node
* node
= (Node
*)fsNode
->private_node
;
361 FUNCTION("volume: %p, node: %p (%lld), cookie: %p, op: %lx, buffer: %p, "
363 volume
, node
, node
->ID(), cookie
, op
, buffer
, length
);
365 FETCH_SOURCE_VOLUME_AND_NODE(volume
, node
->ID());
367 return sourceNode
->ops
->ioctl(sourceVolume
, sourceNode
, cookie
, op
, buffer
,
373 bindfs_set_flags(fs_volume
* fsVolume
, fs_vnode
* fsNode
, void* cookie
, int flags
)
375 Volume
* volume
= (Volume
*)fsVolume
->private_volume
;
376 Node
* node
= (Node
*)fsNode
->private_node
;
378 FUNCTION("volume: %p, node: %p (%lld), cookie: %p, flags: %x\n",
379 volume
, node
, node
->ID(), cookie
, flags
);
381 FETCH_SOURCE_VOLUME_AND_NODE(volume
, node
->ID());
383 return sourceNode
->ops
->set_flags(sourceVolume
, sourceNode
, cookie
, flags
);
388 bindfs_select(fs_volume
* fsVolume
, fs_vnode
* fsNode
, void* cookie
, uint8 event
,
391 Volume
* volume
= (Volume
*)fsVolume
->private_volume
;
392 Node
* node
= (Node
*)fsNode
->private_node
;
394 FUNCTION("volume: %p, node: %p (%lld), cookie: %p, event: %x, sync: %p\n",
395 volume
, node
, node
->ID(), cookie
, event
, sync
);
397 FETCH_SOURCE_VOLUME_AND_NODE(volume
, node
->ID());
399 return sourceNode
->ops
->select(sourceVolume
, sourceNode
, cookie
, event
,
405 bindfs_deselect(fs_volume
* fsVolume
, fs_vnode
* fsNode
, void* cookie
,
406 uint8 event
, selectsync
* sync
)
408 Volume
* volume
= (Volume
*)fsVolume
->private_volume
;
409 Node
* node
= (Node
*)fsNode
->private_node
;
411 FUNCTION("volume: %p, node: %p (%lld), cookie: %p, event: %x, sync: %p\n",
412 volume
, node
, node
->ID(), cookie
, event
, sync
);
414 FETCH_SOURCE_VOLUME_AND_NODE(volume
, node
->ID());
416 return sourceNode
->ops
->deselect(sourceVolume
, sourceNode
, cookie
, event
,
422 bindfs_fsync(fs_volume
* fsVolume
, fs_vnode
* fsNode
)
424 Volume
* volume
= (Volume
*)fsVolume
->private_volume
;
425 Node
* node
= (Node
*)fsNode
->private_node
;
427 FUNCTION("volume: %p, node: %p (%lld)\n", volume
, node
, node
->ID());
429 FETCH_SOURCE_VOLUME_AND_NODE(volume
, node
->ID());
431 return sourceNode
->ops
->fsync(sourceVolume
, sourceNode
);
435 // #pragma mark - Nodes
439 bindfs_read_symlink(fs_volume
* fsVolume
, fs_vnode
* fsNode
, char* buffer
,
442 Volume
* volume
= (Volume
*)fsVolume
->private_volume
;
443 Node
* node
= (Node
*)fsNode
->private_node
;
445 FUNCTION("volume: %p, node: %p (%lld)\n", volume
, node
, node
->ID());
447 FETCH_SOURCE_VOLUME_AND_NODE(volume
, node
->ID());
449 return sourceNode
->ops
->read_symlink(sourceVolume
, sourceNode
, buffer
,
455 bindfs_create_symlink(fs_volume
* fsVolume
, fs_vnode
* fsNode
, const char* name
,
456 const char* path
, int mode
)
458 Volume
* volume
= (Volume
*)fsVolume
->private_volume
;
459 Node
* node
= (Node
*)fsNode
->private_node
;
461 FUNCTION("volume: %p, node: %p (%lld), name: %s, path: %s, mode: %x\n",
462 volume
, node
, node
->ID(), name
, path
, mode
);
464 FETCH_SOURCE_VOLUME_AND_NODE(volume
, node
->ID());
466 return sourceNode
->ops
->create_symlink(sourceVolume
, sourceNode
, name
, path
,
472 bindfs_link(fs_volume
* fsVolume
, fs_vnode
* fsNode
, const char* name
,
475 Volume
* volume
= (Volume
*)fsVolume
->private_volume
;
476 Node
* node
= (Node
*)fsNode
->private_node
;
478 FUNCTION("volume: %p, node: %p (%lld), name: %s, tonode: %p\n",
479 volume
, node
, node
->ID(), name
, toNode
);
481 FETCH_SOURCE_VOLUME_AND_NODE(volume
, node
->ID());
483 return sourceNode
->ops
->link(sourceVolume
, sourceNode
, name
, toNode
);
488 bindfs_unlink(fs_volume
* fsVolume
, fs_vnode
* fsNode
, const char* name
)
490 Volume
* volume
= (Volume
*)fsVolume
->private_volume
;
491 Node
* node
= (Node
*)fsNode
->private_node
;
493 FUNCTION("volume: %p, node: %p (%lld), name: %s\n",
494 volume
, node
, node
->ID(), name
);
496 FETCH_SOURCE_VOLUME_AND_NODE(volume
, node
->ID());
498 return sourceNode
->ops
->unlink(sourceVolume
, sourceNode
, name
);
503 bindfs_rename(fs_volume
* fsVolume
, fs_vnode
* fsNode
, const char* fromName
,
504 fs_vnode
* toDir
, const char* toName
)
506 Volume
* volume
= (Volume
*)fsVolume
->private_volume
;
507 Node
* node
= (Node
*)fsNode
->private_node
;
509 FUNCTION("volume: %p, node: %p (%lld), from: %s, toDir: %p, to: %s\n",
510 volume
, node
, node
->ID(), fromName
, toDir
, toName
);
512 FETCH_SOURCE_VOLUME_AND_NODE(volume
, node
->ID());
514 return sourceNode
->ops
->rename(sourceVolume
, sourceNode
, fromName
, toDir
,
520 bindfs_access(fs_volume
* fsVolume
, fs_vnode
* fsNode
, int mode
)
522 Volume
* volume
= (Volume
*)fsVolume
->private_volume
;
523 Node
* node
= (Node
*)fsNode
->private_node
;
525 FUNCTION("volume: %p, node: %p (%lld)\n", volume
, node
, node
->ID());
527 FETCH_SOURCE_VOLUME_AND_NODE(volume
, node
->ID());
529 return sourceNode
->ops
->access(sourceVolume
, sourceNode
, mode
);
534 bindfs_read_stat(fs_volume
* fsVolume
, fs_vnode
* fsNode
, struct stat
* st
)
536 Volume
* volume
= (Volume
*)fsVolume
->private_volume
;
537 Node
* node
= (Node
*)fsNode
->private_node
;
539 FUNCTION("volume: %p, node: %p (%lld)\n", volume
, node
, node
->ID());
541 FETCH_SOURCE_VOLUME_AND_NODE(volume
, node
->ID());
543 error
= sourceNode
->ops
->read_stat(sourceVolume
, sourceNode
, st
);
547 st
->st_dev
= volume
->ID();
554 bindfs_write_stat(fs_volume
* fsVolume
, fs_vnode
* fsNode
,
555 const struct stat
* _st
, uint32 statMask
)
557 Volume
* volume
= (Volume
*)fsVolume
->private_volume
;
558 Node
* node
= (Node
*)fsNode
->private_node
;
560 FUNCTION("volume: %p, node: %p (%lld)\n", volume
, node
, node
->ID());
562 FETCH_SOURCE_VOLUME_AND_NODE(volume
, node
->ID());
565 memcpy(&st
, _st
, sizeof(st
));
566 st
.st_dev
= sourceVolume
->id
;
568 return sourceNode
->ops
->write_stat(sourceVolume
, sourceNode
, &st
, statMask
);
573 bindfs_preallocate(fs_volume
* fsVolume
, fs_vnode
* fsNode
, off_t pos
,
576 Volume
* volume
= (Volume
*)fsVolume
->private_volume
;
577 Node
* node
= (Node
*)fsNode
->private_node
;
579 FUNCTION("volume: %p, node: %p (%lld), pos: %lld, length: %lld\n",
580 volume
, node
, node
->ID(), pos
, length
);
582 FETCH_SOURCE_VOLUME_AND_NODE(volume
, node
->ID());
584 return sourceNode
->ops
->preallocate(sourceVolume
, sourceNode
, pos
, length
);
588 // #pragma mark - Files
592 bindfs_create(fs_volume
* fsVolume
, fs_vnode
* fsNode
, const char* name
,
593 int openMode
, int perms
, void** _cookie
, ino_t
* _newVnodeID
)
595 Volume
* volume
= (Volume
*)fsVolume
->private_volume
;
596 Node
* node
= (Node
*)fsNode
->private_node
;
598 FUNCTION("volume: %p, node: %p (%lld), name: %s, openMode %#x, perms: %x\n",
599 volume
, node
, node
->ID(), name
, openMode
, perms
);
601 FETCH_SOURCE_VOLUME_AND_NODE(volume
, node
->ID());
603 error
= sourceNode
->ops
->create(sourceVolume
, sourceNode
, name
, openMode
,
604 perms
, _cookie
, _newVnodeID
);
608 error
= get_vnode(fsVolume
, *_newVnodeID
, NULL
);
610 // on error remove the newly created source entry
612 sourceNode
->ops
->unlink(sourceVolume
, sourceNode
, name
);
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
)
618 vfs_put_vnode(newSourceVnode
);
627 bindfs_open(fs_volume
* fsVolume
, fs_vnode
* fsNode
, int openMode
,
630 Volume
* volume
= (Volume
*)fsVolume
->private_volume
;
631 Node
* node
= (Node
*)fsNode
->private_node
;
633 FUNCTION("volume: %p, node: %p (%lld), openMode %#x\n", volume
, node
,
634 node
->ID(), openMode
);
636 FETCH_SOURCE_VOLUME_AND_NODE(volume
, node
->ID());
638 return sourceNode
->ops
->open(sourceVolume
, sourceNode
, openMode
, _cookie
);
643 bindfs_close(fs_volume
* fsVolume
, fs_vnode
* fsNode
, void* cookie
)
645 Volume
* volume
= (Volume
*)fsVolume
->private_volume
;
646 Node
* node
= (Node
*)fsNode
->private_node
;
648 FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume
, node
,
651 FETCH_SOURCE_VOLUME_AND_NODE(volume
, node
->ID());
653 return sourceNode
->ops
->close(sourceVolume
, sourceNode
, cookie
);
658 bindfs_free_cookie(fs_volume
* fsVolume
, fs_vnode
* fsNode
, void* cookie
)
660 Volume
* volume
= (Volume
*)fsVolume
->private_volume
;
661 Node
* node
= (Node
*)fsNode
->private_node
;
663 FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume
, node
,
666 FETCH_SOURCE_VOLUME_AND_NODE(volume
, node
->ID());
668 return sourceNode
->ops
->free_cookie(sourceVolume
, sourceNode
, cookie
);
673 bindfs_read(fs_volume
* fsVolume
, fs_vnode
* fsNode
, void* cookie
,
674 off_t offset
, void* buffer
, size_t* bufferSize
)
676 Volume
* volume
= (Volume
*)fsVolume
->private_volume
;
677 Node
* node
= (Node
*)fsNode
->private_node
;
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
);
683 FETCH_SOURCE_VOLUME_AND_NODE(volume
, node
->ID());
685 return sourceNode
->ops
->read(sourceVolume
, sourceNode
, cookie
, offset
,
691 bindfs_write(fs_volume
* fsVolume
, fs_vnode
* fsNode
, void* cookie
,
692 off_t offset
, const void* buffer
, size_t* bufferSize
)
694 Volume
* volume
= (Volume
*)fsVolume
->private_volume
;
695 Node
* node
= (Node
*)fsNode
->private_node
;
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
);
701 FETCH_SOURCE_VOLUME_AND_NODE(volume
, node
->ID());
703 return sourceNode
->ops
->write(sourceVolume
, sourceNode
, cookie
, offset
,
708 // #pragma mark - Directories
712 bindfs_create_dir(fs_volume
* fsVolume
, fs_vnode
* fsNode
, const char* name
,
715 Volume
* volume
= (Volume
*)fsVolume
->private_volume
;
716 Node
* node
= (Node
*)fsNode
->private_node
;
718 FUNCTION("volume: %p, node: %p (%lld), name: %s, perms: %x\n", volume
, node
,
719 node
->ID(), name
, perms
);
721 FETCH_SOURCE_VOLUME_AND_NODE(volume
, node
->ID());
723 return sourceNode
->ops
->create_dir(sourceVolume
, sourceNode
, name
, perms
);
728 bindfs_remove_dir(fs_volume
* fsVolume
, fs_vnode
* fsNode
, const char* name
)
730 Volume
* volume
= (Volume
*)fsVolume
->private_volume
;
731 Node
* node
= (Node
*)fsNode
->private_node
;
733 FUNCTION("volume: %p, node: %p (%lld), name: %s\n", volume
, node
,
736 FETCH_SOURCE_VOLUME_AND_NODE(volume
, node
->ID());
738 return sourceNode
->ops
->remove_dir(sourceVolume
, sourceNode
, name
);
743 bindfs_open_dir(fs_volume
* fsVolume
, fs_vnode
* fsNode
, void** _cookie
)
745 Volume
* volume
= (Volume
*)fsVolume
->private_volume
;
746 Node
* node
= (Node
*)fsNode
->private_node
;
748 FUNCTION("volume: %p, node: %p (%lld)\n", volume
, node
, node
->ID());
750 FETCH_SOURCE_VOLUME_AND_NODE(volume
, node
->ID());
752 return sourceNode
->ops
->open_dir(sourceVolume
, sourceNode
, _cookie
);
757 bindfs_close_dir(fs_volume
* fsVolume
, fs_vnode
* fsNode
, void* cookie
)
759 Volume
* volume
= (Volume
*)fsVolume
->private_volume
;
760 Node
* node
= (Node
*)fsNode
->private_node
;
762 FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume
, node
,
765 FETCH_SOURCE_VOLUME_AND_NODE(volume
, node
->ID());
767 return sourceNode
->ops
->close_dir(sourceVolume
, sourceNode
, cookie
);
772 bindfs_free_dir_cookie(fs_volume
* fsVolume
, fs_vnode
* fsNode
, void* cookie
)
774 Volume
* volume
= (Volume
*)fsVolume
->private_volume
;
775 Node
* node
= (Node
*)fsNode
->private_node
;
777 FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume
, node
,
780 FETCH_SOURCE_VOLUME_AND_NODE(volume
, node
->ID());
782 return sourceNode
->ops
->free_dir_cookie(sourceVolume
, sourceNode
, cookie
);
787 bindfs_read_dir(fs_volume
* fsVolume
, fs_vnode
* fsNode
, void* cookie
,
788 struct dirent
* buffer
, size_t bufferSize
, uint32
* _count
)
790 Volume
* volume
= (Volume
*)fsVolume
->private_volume
;
791 Node
* node
= (Node
*)fsNode
->private_node
;
793 FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume
, node
,
796 FETCH_SOURCE_VOLUME_AND_NODE(volume
, node
->ID());
798 return sourceNode
->ops
->read_dir(sourceVolume
, sourceNode
, cookie
, buffer
,
804 bindfs_rewind_dir(fs_volume
* fsVolume
, fs_vnode
* fsNode
, void* cookie
)
806 Volume
* volume
= (Volume
*)fsVolume
->private_volume
;
807 Node
* node
= (Node
*)fsNode
->private_node
;
809 FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume
, node
,
812 FETCH_SOURCE_VOLUME_AND_NODE(volume
, node
->ID());
814 return sourceNode
->ops
->rewind_dir(sourceVolume
, sourceNode
, cookie
);
818 // #pragma mark - Attribute Directories
822 bindfs_open_attr_dir(fs_volume
* fsVolume
, fs_vnode
* fsNode
, void** _cookie
)
824 Volume
* volume
= (Volume
*)fsVolume
->private_volume
;
825 Node
* node
= (Node
*)fsNode
->private_node
;
827 FUNCTION("volume: %p, node: %p (%lld)\n", volume
, node
, node
->ID());
829 FETCH_SOURCE_VOLUME_AND_NODE(volume
, node
->ID());
831 return sourceNode
->ops
->open_attr_dir(sourceVolume
, sourceNode
, _cookie
);
836 bindfs_close_attr_dir(fs_volume
* fsVolume
, fs_vnode
* fsNode
, void* cookie
)
838 Volume
* volume
= (Volume
*)fsVolume
->private_volume
;
839 Node
* node
= (Node
*)fsNode
->private_node
;
841 FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume
, node
,
844 FETCH_SOURCE_VOLUME_AND_NODE(volume
, node
->ID());
846 return sourceNode
->ops
->close_attr_dir(sourceVolume
, sourceNode
, cookie
);
851 bindfs_free_attr_dir_cookie(fs_volume
* fsVolume
, fs_vnode
* fsNode
,
854 Volume
* volume
= (Volume
*)fsVolume
->private_volume
;
855 Node
* node
= (Node
*)fsNode
->private_node
;
857 FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume
, node
,
860 FETCH_SOURCE_VOLUME_AND_NODE(volume
, node
->ID());
862 return sourceNode
->ops
->free_attr_dir_cookie(sourceVolume
, sourceNode
,
868 bindfs_read_attr_dir(fs_volume
* fsVolume
, fs_vnode
* fsNode
, void* cookie
,
869 struct dirent
* buffer
, size_t bufferSize
, uint32
* _count
)
871 Volume
* volume
= (Volume
*)fsVolume
->private_volume
;
872 Node
* node
= (Node
*)fsNode
->private_node
;
874 FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume
, node
,
877 FETCH_SOURCE_VOLUME_AND_NODE(volume
, node
->ID());
879 return sourceNode
->ops
->read_attr_dir(sourceVolume
, sourceNode
, cookie
,
880 buffer
, bufferSize
, _count
);
885 bindfs_rewind_attr_dir(fs_volume
* fsVolume
, fs_vnode
* fsNode
, void* cookie
)
887 Volume
* volume
= (Volume
*)fsVolume
->private_volume
;
888 Node
* node
= (Node
*)fsNode
->private_node
;
890 FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume
, node
,
893 FETCH_SOURCE_VOLUME_AND_NODE(volume
, node
->ID());
895 return sourceNode
->ops
->rewind_attr_dir(sourceVolume
, sourceNode
, cookie
);
899 // #pragma mark - Attribute Operations
903 bindfs_create_attr(fs_volume
* fsVolume
, fs_vnode
* fsNode
, const char* name
,
904 uint32 type
, int openMode
, void** _cookie
)
906 Volume
* volume
= (Volume
*)fsVolume
->private_volume
;
907 Node
* node
= (Node
*)fsNode
->private_node
;
909 FUNCTION("volume: %p, node: %p (%lld), name: \"%s\", type: %lx, "
911 volume
, node
, node
->ID(), name
, type
, openMode
);
913 FETCH_SOURCE_VOLUME_AND_NODE(volume
, node
->ID());
915 return sourceNode
->ops
->create_attr(sourceVolume
, sourceNode
, name
, type
,
921 bindfs_open_attr(fs_volume
* fsVolume
, fs_vnode
* fsNode
, const char* name
,
922 int openMode
, void** _cookie
)
924 Volume
* volume
= (Volume
*)fsVolume
->private_volume
;
925 Node
* node
= (Node
*)fsNode
->private_node
;
927 FUNCTION("volume: %p, node: %p (%lld), name: \"%s\", openMode %#x\n",
928 volume
, node
, node
->ID(), name
, openMode
);
930 FETCH_SOURCE_VOLUME_AND_NODE(volume
, node
->ID());
932 return sourceNode
->ops
->open_attr(sourceVolume
, sourceNode
, name
, openMode
,
938 bindfs_close_attr(fs_volume
* fsVolume
, fs_vnode
* fsNode
, void* cookie
)
940 Volume
* volume
= (Volume
*)fsVolume
->private_volume
;
941 Node
* node
= (Node
*)fsNode
->private_node
;
943 FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume
, node
,
946 FETCH_SOURCE_VOLUME_AND_NODE(volume
, node
->ID());
948 return sourceNode
->ops
->close_attr(sourceVolume
, sourceNode
, cookie
);
953 bindfs_free_attr_cookie(fs_volume
* fsVolume
, fs_vnode
* fsNode
, void* cookie
)
955 Volume
* volume
= (Volume
*)fsVolume
->private_volume
;
956 Node
* node
= (Node
*)fsNode
->private_node
;
958 FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume
, node
,
961 FETCH_SOURCE_VOLUME_AND_NODE(volume
, node
->ID());
963 return sourceNode
->ops
->free_attr_cookie(sourceVolume
, sourceNode
, cookie
);
968 bindfs_read_attr(fs_volume
* fsVolume
, fs_vnode
* fsNode
, void* cookie
,
969 off_t offset
, void* buffer
, size_t* bufferSize
)
971 Volume
* volume
= (Volume
*)fsVolume
->private_volume
;
972 Node
* node
= (Node
*)fsNode
->private_node
;
974 FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume
, node
,
977 FETCH_SOURCE_VOLUME_AND_NODE(volume
, node
->ID());
979 return sourceNode
->ops
->read_attr(sourceVolume
, sourceNode
, cookie
, offset
,
985 bindfs_write_attr(fs_volume
* fsVolume
, fs_vnode
* fsNode
, void* cookie
,
986 off_t offset
, const void* buffer
, size_t* bufferSize
)
988 Volume
* volume
= (Volume
*)fsVolume
->private_volume
;
989 Node
* node
= (Node
*)fsNode
->private_node
;
991 FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume
, node
,
994 FETCH_SOURCE_VOLUME_AND_NODE(volume
, node
->ID());
996 return sourceNode
->ops
->write_attr(sourceVolume
, sourceNode
, cookie
, offset
,
1002 bindfs_read_attr_stat(fs_volume
* fsVolume
, fs_vnode
* fsNode
, void* cookie
,
1005 Volume
* volume
= (Volume
*)fsVolume
->private_volume
;
1006 Node
* node
= (Node
*)fsNode
->private_node
;
1008 FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume
, node
,
1009 node
->ID(), cookie
);
1011 FETCH_SOURCE_VOLUME_AND_NODE(volume
, node
->ID());
1014 = sourceNode
->ops
->read_attr_stat(sourceVolume
, sourceNode
, cookie
, st
);
1016 RETURN_ERROR(error
);
1018 st
->st_dev
= volume
->ID();
1025 bindfs_write_attr_stat(fs_volume
* fsVolume
, fs_vnode
* fsNode
, void* cookie
,
1026 const struct stat
* _st
, int statMask
)
1028 Volume
* volume
= (Volume
*)fsVolume
->private_volume
;
1029 Node
* node
= (Node
*)fsNode
->private_node
;
1031 FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume
, node
,
1032 node
->ID(), cookie
);
1034 FETCH_SOURCE_VOLUME_AND_NODE(volume
, node
->ID());
1037 memcpy(&st
, _st
, sizeof(st
));
1038 st
.st_dev
= sourceVolume
->id
;
1040 return sourceNode
->ops
->write_attr_stat(sourceVolume
, sourceNode
, cookie
,
1046 bindfs_rename_attr(fs_volume
* fsVolume
, fs_vnode
* fsNode
, const char* fromName
,
1047 fs_vnode
* toDir
, const char* toName
)
1049 Volume
* volume
= (Volume
*)fsVolume
->private_volume
;
1050 Node
* node
= (Node
*)fsNode
->private_node
;
1052 FUNCTION("volume: %p, node: %p (%lld), from: %s, toDir: %p, to: %s\n",
1053 volume
, node
, node
->ID(), fromName
, toDir
, toName
);
1055 FETCH_SOURCE_VOLUME_AND_NODE(volume
, node
->ID());
1057 return sourceNode
->ops
->rename_attr(sourceVolume
, sourceNode
, fromName
,
1063 bindfs_remove_attr(fs_volume
* fsVolume
, fs_vnode
* fsNode
, const char* name
)
1065 Volume
* volume
= (Volume
*)fsVolume
->private_volume
;
1066 Node
* node
= (Node
*)fsNode
->private_node
;
1068 FUNCTION("volume: %p, node: %p (%lld), name: %s\n", volume
, node
,
1071 FETCH_SOURCE_VOLUME_AND_NODE(volume
, node
->ID());
1073 return sourceNode
->ops
->remove_attr(sourceVolume
, sourceNode
, name
);
1077 // #pragma mark - Module Interface
1081 bindfs_std_ops(int32 op
, ...)
1087 PRINT("bindfs_std_ops(): B_MODULE_INIT\n");
1092 case B_MODULE_UNINIT
:
1094 PRINT("bind_std_ops(): B_MODULE_UNINIT\n");
1105 static file_system_module_info sBindFSModuleInfo
= {
1107 "file_systems/bindfs" B_CURRENT_FS_API_VERSION
,
1112 "bindfs", // short_name
1113 "Bind File System", // pretty_name
1118 NULL
, // identify_partition,
1119 NULL
, // scan_partition,
1120 NULL
, // free_identify_partition_cookie,
1121 NULL
, // free_partition_content_cookie()
1127 fs_volume_ops gBindFSVolumeOps
= {
1129 &bindfs_read_fs_info
,
1130 NULL
, // write_fs_info,
1135 // TODO: index operations
1136 // TODO: query operations
1137 // TODO: FS layer operations
1141 fs_vnode_ops gBindFSVnodeOps
= {
1144 &bindfs_get_vnode_name
,
1146 &bindfs_remove_vnode
,
1151 &bindfs_write_pages
,
1156 &bindfs_get_file_map
,
1164 &bindfs_read_symlink
,
1165 &bindfs_create_symlink
,
1174 &bindfs_preallocate
,
1180 &bindfs_free_cookie
,
1184 // directory operations
1189 &bindfs_free_dir_cookie
,
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
,
1200 // attribute operations
1201 &bindfs_create_attr
,
1204 &bindfs_free_attr_cookie
,
1208 &bindfs_read_attr_stat
,
1209 &bindfs_write_attr_stat
,
1210 &bindfs_rename_attr
,
1211 &bindfs_remove_attr
,
1213 // TODO: FS layer operations
1217 module_info
*modules
[] = {
1218 (module_info
*)&sBindFSModuleInfo
,