xref: /haiku/src/add-ons/kernel/file_systems/bindfs/kernel_interface.cpp (revision cdccd323b5056042f24338ea9471b57ccf4b075f)
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 
61 static status_t
bindfs_mount(fs_volume * fsVolume,const char * device,uint32 flags,const char * parameters,ino_t * _rootID)62 bindfs_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 
88 static status_t
bindfs_unmount(fs_volume * fsVolume)89 bindfs_unmount(fs_volume* fsVolume)
90 {
91 	Volume* volume = (Volume*)fsVolume->private_volume;
92 
93 	FUNCTION("volume: %p\n", volume);
94 
95 	volume->Unmount();
96 	delete volume;
97 
98 	return B_OK;
99 }
100 
101 
102 static status_t
bindfs_read_fs_info(fs_volume * fsVolume,struct fs_info * info)103 bindfs_read_fs_info(fs_volume* fsVolume, struct fs_info* info)
104 {
105 	Volume* volume = (Volume*)fsVolume->private_volume;
106 
107 	FUNCTION("volume: %p, info: %p\n", volume, info);
108 
109 	fs_volume* sourceVolume = volume->SourceFSVolume();
110 
111 	if (sourceVolume->ops->read_fs_info != NULL) {
112 		status_t error = sourceVolume->ops->read_fs_info(sourceVolume, info);
113 		if (error != B_OK)
114 			RETURN_ERROR(error);
115 	} else {
116 		info->block_size = 512;
117 		info->io_size = 64 * 1024;
118 	}
119 
120 	info->dev = volume->ID();
121 	info->root = volume->RootNode()->ID();
122 	info->total_blocks = info->free_blocks = 0;
123 	info->total_nodes = info->free_nodes = 0;
124 
125 	strlcpy(info->volume_name, volume->Name(), sizeof(info->volume_name));
126 
127 	return B_OK;
128 }
129 
130 
131 // #pragma mark - VNodes
132 
133 
134 static status_t
bindfs_lookup(fs_volume * fsVolume,fs_vnode * fsDir,const char * entryName,ino_t * _vnid)135 bindfs_lookup(fs_volume* fsVolume, fs_vnode* fsDir, const char* entryName,
136 	ino_t* _vnid)
137 {
138 	Volume* volume = (Volume*)fsVolume->private_volume;
139 	Node* node = (Node*)fsDir->private_node;
140 
141 	FUNCTION("volume: %p, dir: %p (%" 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 
161 static status_t
bindfs_get_vnode(fs_volume * fsVolume,ino_t vnid,fs_vnode * fsNode,int * _type,uint32 * _flags,bool reenter)162 bindfs_get_vnode(fs_volume* fsVolume, ino_t vnid, fs_vnode* fsNode,
163 	int* _type, uint32* _flags, bool reenter)
164 {
165 	Volume* volume = (Volume*)fsVolume->private_volume;
166 
167 	FUNCTION("volume: %p, vnid: %" 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 
187 static status_t
bindfs_get_vnode_name(fs_volume * fsVolume,fs_vnode * fsNode,char * buffer,size_t bufferSize)188 bindfs_get_vnode_name(fs_volume* fsVolume, fs_vnode* fsNode, char* buffer,
189 	size_t bufferSize)
190 {
191 	Volume* volume = (Volume*)fsVolume->private_volume;
192 	Node* node = (Node*)fsNode->private_node;
193 
194 	FUNCTION("volume: %p, node: %p\n", volume, node);
195 
196 	FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID());
197 
198 	return sourceNode->ops->get_vnode_name(sourceVolume, sourceNode, buffer,
199 		bufferSize);
200 }
201 
202 static status_t
bindfs_put_vnode(fs_volume * fsVolume,fs_vnode * fsNode,bool reenter)203 bindfs_put_vnode(fs_volume* fsVolume, fs_vnode* fsNode, bool reenter)
204 {
205 	Volume* volume = (Volume*)fsVolume->private_volume;
206 	Node* node = (Node*)fsNode->private_node;
207 
208 	FUNCTION("volume: %p, node: %p\n", volume, node);
209 
210 	FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID());
211 
212 	delete node;
213 
214 	return B_OK;
215 }
216 
217 
218 static status_t
bindfs_remove_vnode(fs_volume * fsVolume,fs_vnode * fsNode,bool reenter)219 bindfs_remove_vnode(fs_volume* fsVolume, fs_vnode* fsNode, bool reenter)
220 {
221 	Volume* volume = (Volume*)fsVolume->private_volume;
222 	Node* node = (Node*)fsNode->private_node;
223 
224 	FUNCTION("volume: %p, node: %p\n", volume, node);
225 
226 	FETCH_SOURCE_VOLUME_AND_NODE(volume, node->ID());
227 
228 	delete node;
229 
230 	return sourceNode->ops->remove_vnode(sourceVolume, sourceNode, reenter);
231 }
232 
233 
234 // #pragma mark - VM access
235 
236 
237 // TODO: These hooks are obsolete. Since we don't create a file cache, they
238 // aren't needed anyway.
239 
240 
241 static bool
bindfs_can_page(fs_volume * fsVolume,fs_vnode * fsNode,void * cookie)242 bindfs_can_page(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie)
243 {
244 	Volume* volume = (Volume*)fsVolume->private_volume;
245 	Node* node = (Node*)fsNode->private_node;
246 
247 	FUNCTION("volume: %p, node: %p (%" 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 
256 static status_t
bindfs_read_pages(fs_volume * fsVolume,fs_vnode * fsNode,void * cookie,off_t pos,const iovec * vecs,size_t count,size_t * _numBytes)257 bindfs_read_pages(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie,
258 	off_t pos, const iovec* vecs, size_t count, size_t* _numBytes)
259 {
260 	Volume* volume = (Volume*)fsVolume->private_volume;
261 	Node* node = (Node*)fsNode->private_node;
262 
263 	FUNCTION("volume: %p, node: %p (%" 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 
274 static status_t
bindfs_write_pages(fs_volume * fsVolume,fs_vnode * fsNode,void * cookie,off_t pos,const iovec * vecs,size_t count,size_t * _numBytes)275 bindfs_write_pages(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie,
276 	off_t pos, const iovec* vecs, size_t count, size_t* _numBytes)
277 {
278 	Volume* volume = (Volume*)fsVolume->private_volume;
279 	Node* node = (Node*)fsNode->private_node;
280 
281 	FUNCTION("volume: %p, node: %p (%" 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 
298 static status_t
bindfs_io(fs_volume * fsVolume,fs_vnode * fsNode,void * cookie,io_request * request)299 bindfs_io(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie,
300 	io_request* request)
301 {
302 	Volume* volume = (Volume*)fsVolume->private_volume;
303 	Node* node = (Node*)fsNode->private_node;
304 
305 	FUNCTION("volume: %p, node: %p (%" 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 
314 static status_t
bindfs_cancel_io(fs_volume * fsVolume,fs_vnode * fsNode,void * cookie,io_request * request)315 bindfs_cancel_io(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie,
316 	io_request* request)
317 {
318 	Volume* volume = (Volume*)fsVolume->private_volume;
319 	Node* node = (Node*)fsNode->private_node;
320 
321 	FUNCTION("volume: %p, node: %p (%" 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 
334 static status_t
bindfs_get_file_map(fs_volume * fsVolume,fs_vnode * fsNode,off_t offset,size_t size,struct file_io_vec * vecs,size_t * _count)335 bindfs_get_file_map(fs_volume* fsVolume, fs_vnode* fsNode, off_t offset,
336 	size_t size, struct file_io_vec* vecs, size_t* _count)
337 {
338 	Volume* volume = (Volume*)fsVolume->private_volume;
339 	Node* node = (Node*)fsNode->private_node;
340 
341 	FUNCTION("volume: %p, node: %p (%" 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 
355 static status_t
bindfs_ioctl(fs_volume * fsVolume,fs_vnode * fsNode,void * cookie,uint32 op,void * buffer,size_t length)356 bindfs_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 
373 static status_t
bindfs_set_flags(fs_volume * fsVolume,fs_vnode * fsNode,void * cookie,int flags)374 bindfs_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 
388 static status_t
bindfs_select(fs_volume * fsVolume,fs_vnode * fsNode,void * cookie,uint8 event,selectsync * sync)389 bindfs_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 
406 static status_t
bindfs_deselect(fs_volume * fsVolume,fs_vnode * fsNode,void * cookie,uint8 event,selectsync * sync)407 bindfs_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 
424 static status_t
bindfs_fsync(fs_volume * fsVolume,fs_vnode * fsNode)425 bindfs_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 
442 static status_t
bindfs_read_symlink(fs_volume * fsVolume,fs_vnode * fsNode,char * buffer,size_t * _bufferSize)443 bindfs_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 
459 static status_t
bindfs_create_symlink(fs_volume * fsVolume,fs_vnode * fsNode,const char * name,const char * path,int mode)460 bindfs_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 
477 static status_t
bindfs_link(fs_volume * fsVolume,fs_vnode * fsNode,const char * name,fs_vnode * toNode)478 bindfs_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 
494 static status_t
bindfs_unlink(fs_volume * fsVolume,fs_vnode * fsNode,const char * name)495 bindfs_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 
509 static status_t
bindfs_rename(fs_volume * fsVolume,fs_vnode * fsNode,const char * fromName,fs_vnode * toDir,const char * toName)510 bindfs_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 
527 static status_t
bindfs_access(fs_volume * fsVolume,fs_vnode * fsNode,int mode)528 bindfs_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 
542 static status_t
bindfs_read_stat(fs_volume * fsVolume,fs_vnode * fsNode,struct stat * st)543 bindfs_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 
563 static status_t
bindfs_write_stat(fs_volume * fsVolume,fs_vnode * fsNode,const struct stat * _st,uint32 statMask)564 bindfs_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 
583 static status_t
bindfs_preallocate(fs_volume * fsVolume,fs_vnode * fsNode,off_t pos,off_t length)584 bindfs_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 
603 static status_t
bindfs_create(fs_volume * fsVolume,fs_vnode * fsNode,const char * name,int openMode,int perms,void ** _cookie,ino_t * _newVnodeID)604 bindfs_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 
639 static status_t
bindfs_open(fs_volume * fsVolume,fs_vnode * fsNode,int openMode,void ** _cookie)640 bindfs_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 
655 static status_t
bindfs_close(fs_volume * fsVolume,fs_vnode * fsNode,void * cookie)656 bindfs_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 
670 static status_t
bindfs_free_cookie(fs_volume * fsVolume,fs_vnode * fsNode,void * cookie)671 bindfs_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 
685 static status_t
bindfs_read(fs_volume * fsVolume,fs_vnode * fsNode,void * cookie,off_t offset,void * buffer,size_t * bufferSize)686 bindfs_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 
703 static status_t
bindfs_write(fs_volume * fsVolume,fs_vnode * fsNode,void * cookie,off_t offset,const void * buffer,size_t * bufferSize)704 bindfs_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 
724 static status_t
bindfs_create_dir(fs_volume * fsVolume,fs_vnode * fsNode,const char * name,int perms)725 bindfs_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 
740 static status_t
bindfs_remove_dir(fs_volume * fsVolume,fs_vnode * fsNode,const char * name)741 bindfs_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 
755 static status_t
bindfs_open_dir(fs_volume * fsVolume,fs_vnode * fsNode,void ** _cookie)756 bindfs_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 
770 static status_t
bindfs_close_dir(fs_volume * fsVolume,fs_vnode * fsNode,void * cookie)771 bindfs_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 
785 static status_t
bindfs_free_dir_cookie(fs_volume * fsVolume,fs_vnode * fsNode,void * cookie)786 bindfs_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 
800 static status_t
bindfs_read_dir(fs_volume * fsVolume,fs_vnode * fsNode,void * cookie,struct dirent * buffer,size_t bufferSize,uint32 * _count)801 bindfs_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 
817 static status_t
bindfs_rewind_dir(fs_volume * fsVolume,fs_vnode * fsNode,void * cookie)818 bindfs_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 
835 status_t
bindfs_open_attr_dir(fs_volume * fsVolume,fs_vnode * fsNode,void ** _cookie)836 bindfs_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 
850 status_t
bindfs_close_attr_dir(fs_volume * fsVolume,fs_vnode * fsNode,void * cookie)851 bindfs_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 
865 status_t
bindfs_free_attr_dir_cookie(fs_volume * fsVolume,fs_vnode * fsNode,void * cookie)866 bindfs_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 
882 status_t
bindfs_read_attr_dir(fs_volume * fsVolume,fs_vnode * fsNode,void * cookie,struct dirent * buffer,size_t bufferSize,uint32 * _count)883 bindfs_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 
899 status_t
bindfs_rewind_attr_dir(fs_volume * fsVolume,fs_vnode * fsNode,void * cookie)900 bindfs_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 
917 status_t
bindfs_create_attr(fs_volume * fsVolume,fs_vnode * fsNode,const char * name,uint32 type,int openMode,void ** _cookie)918 bindfs_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 
935 status_t
bindfs_open_attr(fs_volume * fsVolume,fs_vnode * fsNode,const char * name,int openMode,void ** _cookie)936 bindfs_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 
953 status_t
bindfs_close_attr(fs_volume * fsVolume,fs_vnode * fsNode,void * cookie)954 bindfs_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 
968 status_t
bindfs_free_attr_cookie(fs_volume * fsVolume,fs_vnode * fsNode,void * cookie)969 bindfs_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 
983 status_t
bindfs_read_attr(fs_volume * fsVolume,fs_vnode * fsNode,void * cookie,off_t offset,void * buffer,size_t * bufferSize)984 bindfs_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 
1000 status_t
bindfs_write_attr(fs_volume * fsVolume,fs_vnode * fsNode,void * cookie,off_t offset,const void * buffer,size_t * bufferSize)1001 bindfs_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 
1017 status_t
bindfs_read_attr_stat(fs_volume * fsVolume,fs_vnode * fsNode,void * cookie,struct stat * st)1018 bindfs_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 
1040 status_t
bindfs_write_attr_stat(fs_volume * fsVolume,fs_vnode * fsNode,void * cookie,const struct stat * _st,int statMask)1041 bindfs_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 
1061 static status_t
bindfs_rename_attr(fs_volume * fsVolume,fs_vnode * fsNode,const char * fromName,fs_vnode * toDir,const char * toName)1062 bindfs_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 
1079 static status_t
bindfs_remove_attr(fs_volume * fsVolume,fs_vnode * fsNode,const char * name)1080 bindfs_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 
1097 static status_t
bindfs_std_ops(int32 op,...)1098 bindfs_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 
1122 static 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 
1144 fs_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 
1158 fs_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 
1234 module_info *modules[] = {
1235 	(module_info *)&sBindFSModuleInfo,
1236 	NULL,
1237 };
1238