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