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