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