BPicture: Fix archive constructor.
[haiku.git] / src / add-ons / kernel / file_systems / bindfs / kernel_interface.cpp
blob86080c4e5f4b2d524c83e5b7b1ef3f9ce1b0db2b
1 /*
2 * Copyright 2011, Oliver Tappe <zooey@hirschkaefer.de>
3 * Distributed under the terms of the MIT License.
4 */
7 #include <new>
9 #include <fs_info.h>
10 #include <fs_interface.h>
11 #include <KernelExport.h>
13 #include <vfs.h>
15 #include <AutoDeleter.h>
17 #include "DebugSupport.h"
18 #include "kernel_interface.h"
19 #include "Node.h"
20 #include "Utils.h"
21 #include "Volume.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
31 of entries
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); \
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);
59 // #pragma mark - Volume
62 static status_t
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);
71 if (volume == NULL)
72 RETURN_ERROR(B_NO_MEMORY);
73 ObjectDeleter<Volume> volumeDeleter(volume);
75 status_t error = volume->Mount(parameters);
76 if (error != B_OK)
77 return error;
79 // set return values
80 *_rootID = volume->RootNode()->ID();
81 fsVolume->private_volume = volumeDeleter.Detach();
82 fsVolume->ops = &gBindFSVolumeOps;
84 return B_OK;
88 static status_t
89 bindfs_unmount(fs_volume* fsVolume)
91 Volume* volume = (Volume*)fsVolume->private_volume;
93 FUNCTION("volume: %p\n", volume);
95 volume->Unmount();
96 delete volume;
98 return B_OK;
102 static status_t
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);
113 if (error != B_OK)
114 RETURN_ERROR(error);
115 } else {
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));
127 return B_OK;
131 // #pragma mark - VNodes
134 static status_t
135 bindfs_lookup(fs_volume* fsVolume, fs_vnode* fsDir, const char* entryName,
136 ino_t* _vnid)
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);
147 if (error != B_OK)
148 RETURN_ERROR(error);
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);
157 return error;
161 static status_t
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);
171 struct stat st;
172 error = sourceNode->ops->read_stat(sourceVolume, sourceNode, &st);
174 Node* node = new(std::nothrow) Node(vnid, st.st_mode);
175 if (node == NULL)
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;
181 *_flags = 0;
183 return B_OK;
187 static status_t
188 bindfs_get_vnode_name(fs_volume* fsVolume, fs_vnode* fsNode, char* buffer,
189 size_t bufferSize)
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,
199 bufferSize);
202 static status_t
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());
212 delete node;
214 return B_OK;
218 static status_t
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());
228 delete node;
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.
241 static bool
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);
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)
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, "
264 "count: %ld\n",
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);
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)
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, "
282 "count: %ld\n",
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.
298 static status_t
299 bindfs_io(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie,
300 io_request* request)
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);
314 static status_t
315 bindfs_cancel_io(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie,
316 io_request* request)
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,
327 request);
331 // #pragma mark - File Map
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)
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,
347 vecs, _count);
351 // #pragma mark - Special
354 static status_t
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, "
362 "length: %ld\n",
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,
368 length);
372 static status_t
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);
387 static status_t
388 bindfs_select(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie, uint8 event,
389 selectsync* sync)
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,
400 sync);
404 static status_t
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,
417 sync);
421 static status_t
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
438 static status_t
439 bindfs_read_symlink(fs_volume* fsVolume, fs_vnode* fsNode, char* buffer,
440 size_t* _bufferSize)
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,
450 _bufferSize);
454 static status_t
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,
467 mode);
471 static status_t
472 bindfs_link(fs_volume* fsVolume, fs_vnode* fsNode, const char* name,
473 fs_vnode* toNode)
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);
487 static status_t
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);
502 static status_t
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,
515 toName);
519 static status_t
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);
533 static status_t
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);
544 if (error != B_OK)
545 RETURN_ERROR(error);
547 st->st_dev = volume->ID();
549 return B_OK;
553 static status_t
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());
564 struct stat st;
565 memcpy(&st, _st, sizeof(st));
566 st.st_dev = sourceVolume->id;
568 return sourceNode->ops->write_stat(sourceVolume, sourceNode, &st, statMask);
572 static status_t
573 bindfs_preallocate(fs_volume* fsVolume, fs_vnode* fsNode, off_t pos,
574 off_t length)
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
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)
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);
605 if (error != B_OK)
606 return error;
608 error = get_vnode(fsVolume, *_newVnodeID, NULL);
610 // on error remove the newly created source entry
611 if (error != B_OK)
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)
617 == B_OK) {
618 vfs_put_vnode(newSourceVnode);
621 return error;
626 static status_t
627 bindfs_open(fs_volume* fsVolume, fs_vnode* fsNode, int openMode,
628 void** _cookie)
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);
642 static status_t
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,
649 node->ID(), cookie);
651 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID());
653 return sourceNode->ops->close(sourceVolume, sourceNode, cookie);
657 static status_t
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,
664 node->ID(), cookie);
666 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID());
668 return sourceNode->ops->free_cookie(sourceVolume, sourceNode, cookie);
672 static status_t
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,
686 buffer, bufferSize);
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)
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,
704 buffer, bufferSize);
708 // #pragma mark - Directories
711 static status_t
712 bindfs_create_dir(fs_volume* fsVolume, fs_vnode* fsNode, const char* name,
713 int perms)
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);
727 static status_t
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,
734 node->ID(), name);
736 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID());
738 return sourceNode->ops->remove_dir(sourceVolume, sourceNode, name);
742 static status_t
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);
756 static status_t
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,
763 node->ID(), cookie);
765 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID());
767 return sourceNode->ops->close_dir(sourceVolume, sourceNode, cookie);
771 static status_t
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,
778 node->ID(), cookie);
780 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID());
782 return sourceNode->ops->free_dir_cookie(sourceVolume, sourceNode, cookie);
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)
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,
794 node->ID(), cookie);
796 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID());
798 return sourceNode->ops->read_dir(sourceVolume, sourceNode, cookie, buffer,
799 bufferSize, _count);
803 static status_t
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,
810 node->ID(), cookie);
812 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID());
814 return sourceNode->ops->rewind_dir(sourceVolume, sourceNode, cookie);
818 // #pragma mark - Attribute Directories
821 status_t
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);
835 status_t
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,
842 node->ID(), cookie);
844 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID());
846 return sourceNode->ops->close_attr_dir(sourceVolume, sourceNode, cookie);
850 status_t
851 bindfs_free_attr_dir_cookie(fs_volume* fsVolume, fs_vnode* fsNode,
852 void* cookie)
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,
858 node->ID(), cookie);
860 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID());
862 return sourceNode->ops->free_attr_dir_cookie(sourceVolume, sourceNode,
863 cookie);
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)
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,
875 node->ID(), cookie);
877 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID());
879 return sourceNode->ops->read_attr_dir(sourceVolume, sourceNode, cookie,
880 buffer, bufferSize, _count);
884 status_t
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,
891 node->ID(), cookie);
893 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID());
895 return sourceNode->ops->rewind_attr_dir(sourceVolume, sourceNode, cookie);
899 // #pragma mark - Attribute Operations
902 status_t
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, "
910 "openMode %#x\n",
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,
916 openMode, _cookie);
920 status_t
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,
933 _cookie);
937 status_t
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,
944 node->ID(), cookie);
946 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID());
948 return sourceNode->ops->close_attr(sourceVolume, sourceNode, cookie);
952 status_t
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,
959 node->ID(), cookie);
961 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID());
963 return sourceNode->ops->free_attr_cookie(sourceVolume, sourceNode, cookie);
967 status_t
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,
975 node->ID(), cookie);
977 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID());
979 return sourceNode->ops->read_attr(sourceVolume, sourceNode, cookie, offset,
980 buffer, bufferSize);
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)
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,
992 node->ID(), cookie);
994 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID());
996 return sourceNode->ops->write_attr(sourceVolume, sourceNode, cookie, offset,
997 buffer, bufferSize);
1001 status_t
1002 bindfs_read_attr_stat(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie,
1003 struct stat* st)
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());
1013 error
1014 = sourceNode->ops->read_attr_stat(sourceVolume, sourceNode, cookie, st);
1015 if (error != B_OK)
1016 RETURN_ERROR(error);
1018 st->st_dev = volume->ID();
1020 return B_OK;
1024 status_t
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());
1036 struct stat st;
1037 memcpy(&st, _st, sizeof(st));
1038 st.st_dev = sourceVolume->id;
1040 return sourceNode->ops->write_attr_stat(sourceVolume, sourceNode, cookie,
1041 &st, statMask);
1045 static status_t
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,
1058 toDir, toName);
1062 static status_t
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,
1069 node->ID(), name);
1071 FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID());
1073 return sourceNode->ops->remove_attr(sourceVolume, sourceNode, name);
1077 // #pragma mark - Module Interface
1080 static status_t
1081 bindfs_std_ops(int32 op, ...)
1083 switch (op) {
1084 case B_MODULE_INIT:
1086 init_debugging();
1087 PRINT("bindfs_std_ops(): B_MODULE_INIT\n");
1089 return B_OK;
1092 case B_MODULE_UNINIT:
1094 PRINT("bind_std_ops(): B_MODULE_UNINIT\n");
1095 exit_debugging();
1096 return B_OK;
1099 default:
1100 return B_ERROR;
1105 static file_system_module_info sBindFSModuleInfo = {
1107 "file_systems/bindfs" B_CURRENT_FS_API_VERSION,
1109 bindfs_std_ops,
1112 "bindfs", // short_name
1113 "Bind File System", // pretty_name
1114 0, // DDM flags
1117 // scanning
1118 NULL, // identify_partition,
1119 NULL, // scan_partition,
1120 NULL, // free_identify_partition_cookie,
1121 NULL, // free_partition_content_cookie()
1123 &bindfs_mount
1127 fs_volume_ops gBindFSVolumeOps = {
1128 &bindfs_unmount,
1129 &bindfs_read_fs_info,
1130 NULL, // write_fs_info,
1131 NULL, // sync,
1133 &bindfs_get_vnode
1135 // TODO: index operations
1136 // TODO: query operations
1137 // TODO: FS layer operations
1141 fs_vnode_ops gBindFSVnodeOps = {
1142 // vnode operations
1143 &bindfs_lookup,
1144 &bindfs_get_vnode_name,
1145 &bindfs_put_vnode,
1146 &bindfs_remove_vnode,
1148 // VM file access
1149 &bindfs_can_page,
1150 &bindfs_read_pages,
1151 &bindfs_write_pages,
1153 &bindfs_io,
1154 &bindfs_cancel_io,
1156 &bindfs_get_file_map,
1158 &bindfs_ioctl,
1159 &bindfs_set_flags,
1160 &bindfs_select,
1161 &bindfs_deselect,
1162 &bindfs_fsync,
1164 &bindfs_read_symlink,
1165 &bindfs_create_symlink,
1167 &bindfs_link,
1168 &bindfs_unlink,
1169 &bindfs_rename,
1171 &bindfs_access,
1172 &bindfs_read_stat,
1173 &bindfs_write_stat,
1174 &bindfs_preallocate,
1176 // file operations
1177 &bindfs_create,
1178 &bindfs_open,
1179 &bindfs_close,
1180 &bindfs_free_cookie,
1181 &bindfs_read,
1182 &bindfs_write,
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,
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,
1202 &bindfs_open_attr,
1203 &bindfs_close_attr,
1204 &bindfs_free_attr_cookie,
1205 &bindfs_read_attr,
1206 &bindfs_write_attr,
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,
1219 NULL,