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
62static status_t
63bindfs_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
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 (%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
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: %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
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 (%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
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 (%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
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 (%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
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 (%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
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 (%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
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 (%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
354static status_t
355bindfs_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
372static status_t
373bindfs_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
387static status_t
388bindfs_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
404static status_t
405bindfs_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
421static status_t
422bindfs_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
438static status_t
439bindfs_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
454static status_t
455bindfs_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
471static status_t
472bindfs_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
487static status_t
488bindfs_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
502static status_t
503bindfs_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
519static status_t
520bindfs_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
533static status_t
534bindfs_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
553static status_t
554bindfs_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
572static status_t
573bindfs_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
591static status_t
592bindfs_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
626static status_t
627bindfs_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
642static status_t
643bindfs_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
657static status_t
658bindfs_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
672static status_t
673bindfs_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
690static status_t
691bindfs_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
711static status_t
712bindfs_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
727static status_t
728bindfs_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
742static status_t
743bindfs_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
756static status_t
757bindfs_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
771static status_t
772bindfs_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
786static status_t
787bindfs_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
803static status_t
804bindfs_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
821status_t
822bindfs_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
835status_t
836bindfs_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
850status_t
851bindfs_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
867status_t
868bindfs_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
884status_t
885bindfs_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
902status_t
903bindfs_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
920status_t
921bindfs_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
937status_t
938bindfs_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
952status_t
953bindfs_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
967status_t
968bindfs_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
984status_t
985bindfs_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
1001status_t
1002bindfs_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
1024status_t
1025bindfs_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
1045static status_t
1046bindfs_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
1062static status_t
1063bindfs_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
1080static status_t
1081bindfs_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
1105static 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
1127fs_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
1141fs_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
1217module_info *modules[] = {
1218	(module_info *)&sBindFSModuleInfo,
1219	NULL,
1220};
1221