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