xref: /haiku/src/add-ons/kernel/file_systems/netfs/client/netfs.cpp (revision 4bd0c1066b227cec4b79883bdef697c7a27f2e90)
1 // netfs.cpp
2 
3 #include <new>
4 
5 #include <KernelExport.h>
6 #include <fsproto.h>
7 
8 #include "DebugSupport.h"
9 #include "Node.h"
10 #include "ObjectTracker.h"
11 #include "QueryManager.h"
12 #include "RootVolume.h"
13 #include "VolumeManager.h"
14 
15 // #pragma mark -
16 // #pragma mark ----- prototypes -----
17 
18 extern "C" {
19 
20 // fs
21 static int netfs_mount(nspace_id nsid, const char *device, ulong flags,
22 				void *parameters, size_t len, void **data, vnode_id *rootID);
23 static int netfs_unmount(void *ns);
24 //static int netfs_sync(void *ns);
25 static int netfs_read_fs_stat(void *ns, struct fs_info *info);
26 //static int netfs_write_fs_stat(void *ns, struct fs_info *info, long mask);
27 
28 // vnodes
29 static int netfs_read_vnode(void *ns, vnode_id vnid, char reenter,
30 				void **node);
31 static int netfs_write_vnode(void *ns, void *node, char reenter);
32 static int netfs_remove_vnode(void *ns, void *node, char reenter);
33 
34 // nodes
35 //static int netfs_fsync(void *ns, void *node);
36 static int netfs_read_stat(void *ns, void *node, struct stat *st);
37 static int netfs_write_stat(void *ns, void *node, struct stat *st,
38 				long mask);
39 static int netfs_access(void *ns, void *node, int mode);
40 
41 // files
42 static int netfs_create(void *ns, void *dir, const char *name,
43 				int openMode, int mode, vnode_id *vnid, void **cookie);
44 static int netfs_open(void *ns, void *node, int openMode, void **cookie);
45 static int netfs_close(void *ns, void *node, void *cookie);
46 static int netfs_free_cookie(void *ns, void *node, void *cookie);
47 static int netfs_read(void *ns, void *node, void *cookie, off_t pos,
48 				void *buffer, size_t *bufferSize);
49 static int netfs_write(void *ns, void *node, void *cookie, off_t pos,
50 				const void *buffer, size_t *bufferSize);
51 static int netfs_ioctl(void *ns, void *node, void *cookie, int cmd,
52 				void *buffer, size_t bufferSize);
53 //static int netfs_setflags(void *ns, void *node, void *cookie, int flags);
54 
55 // hard links / symlinks
56 static int netfs_link(void *ns, void *dir, const char *name, void *node);
57 static int netfs_unlink(void *ns, void *dir, const char *name);
58 static int netfs_symlink(void *ns, void *dir, const char *name,
59 				const char *path);
60 static int netfs_read_link(void *ns, void *node, char *buffer,
61 				size_t *bufferSize);
62 static int netfs_rename(void *ns, void *oldDir, const char *oldName,
63 				void *newDir, const char *newName);
64 
65 // directories
66 static int netfs_mkdir(void *ns, void *dir, const char *name, int mode);
67 static int netfs_rmdir(void *ns, void *dir, const char *name);
68 static int netfs_open_dir(void *ns, void *node, void **cookie);
69 static int netfs_close_dir(void *ns, void *node, void *cookie);
70 static int netfs_free_dir_cookie(void *ns, void *node, void *cookie);
71 static int netfs_read_dir(void *ns, void *node, void *cookie,
72 				long *count, struct dirent *buffer, size_t bufferSize);
73 static int netfs_rewind_dir(void *ns, void *node, void *cookie);
74 static int netfs_walk(void *ns, void *dir, const char *entryName,
75 				char **resolvedPath, vnode_id *vnid);
76 
77 // attributes
78 static int netfs_open_attrdir(void *ns, void *node, void **cookie);
79 static int netfs_close_attrdir(void *ns, void *node, void *cookie);
80 static int netfs_free_attrdir_cookie(void *ns, void *node, void *cookie);
81 static int netfs_read_attrdir(void *ns, void *node, void *cookie,
82 				long *count, struct dirent *buffer, size_t bufferSize);
83 static int netfs_read_attr(void *ns, void *node, const char *name,
84 				int type, void *buffer, size_t *bufferSize, off_t pos);
85 static int netfs_rewind_attrdir(void *ns, void *node, void *cookie);
86 static int netfs_write_attr(void *ns, void *node, const char *name,
87 				int type, const void *buffer, size_t *bufferSize, off_t pos);
88 static int netfs_remove_attr(void *ns, void *node, const char *name);
89 static int netfs_rename_attr(void *ns, void *node, const char *oldName,
90 				const char *newName);
91 static int netfs_stat_attr(void *ns, void *node, const char *name,
92 				struct attr_info *attrInfo);
93 
94 // queries
95 static int netfs_open_query(void *ns, const char *queryString, ulong flags,
96 				port_id port, long token, void **cookie);
97 static int netfs_close_query(void *ns, void *cookie);
98 static int netfs_free_query_cookie(void *ns, void *node, void *cookie);
99 static int netfs_read_query(void *ns, void *cookie, long *count,
100 				struct dirent *buffer, size_t bufferSize);
101 
102 } // extern "C"
103 
104 /* vnode_ops struct. Fill this in to tell the kernel how to call
105 	functions in your driver.
106 */
107 vnode_ops fs_entry = {
108 	&netfs_read_vnode,				// read_vnode
109 	&netfs_write_vnode,				// write_vnode
110 	&netfs_remove_vnode,			// remove_vnode
111 	NULL,							// secure_vnode (not needed)
112 	&netfs_walk,					// walk
113 	&netfs_access,					// access
114 	&netfs_create,					// create
115 	&netfs_mkdir,					// mkdir
116 	&netfs_symlink,					// symlink
117 	&netfs_link,					// link
118 	&netfs_rename,					// rename
119 	&netfs_unlink,					// unlink
120 	&netfs_rmdir,					// rmdir
121 	&netfs_read_link,				// readlink
122 	&netfs_open_dir,				// opendir
123 	&netfs_close_dir,				// closedir
124 	&netfs_free_dir_cookie,			// free_dircookie
125 	&netfs_rewind_dir,				// rewinddir
126 	&netfs_read_dir,				// readdir
127 	&netfs_open,					// open file
128 	&netfs_close,					// close file
129 	&netfs_free_cookie,				// free cookie
130 	&netfs_read,					// read file
131 	&netfs_write,					// write file
132 	NULL,							// readv
133 	NULL,							// writev
134 	&netfs_ioctl,					// ioctl
135 	NULL,							// setflags file
136 	&netfs_read_stat,				// read stat
137 	&netfs_write_stat,				// write stat
138 	NULL,							// fsync
139 	NULL,							// initialize
140 	&netfs_mount,					// mount
141 	&netfs_unmount,					// unmount
142 	NULL,							// sync
143 	&netfs_read_fs_stat,			// read fs stat
144 	NULL,							// write fs stat
145 	NULL,							// select
146 	NULL,							// deselect
147 
148 	NULL,							// open index dir
149 	NULL,							// close index dir
150 	NULL,							// free index dir cookie
151 	NULL,							// rewind index dir
152 	NULL,							// read index dir
153 	NULL,							// create index
154 	NULL,							// remove index
155 	NULL,							// rename index
156 	NULL,							// stat index
157 
158 	&netfs_open_attrdir,			// open attr dir
159 	&netfs_close_attrdir,			// close attr dir
160 	&netfs_free_attrdir_cookie,		// free attr dir cookie
161 	&netfs_rewind_attrdir,			// rewind attr dir
162 	&netfs_read_attrdir,			// read attr dir
163 	&netfs_write_attr,				// write attr
164 	&netfs_read_attr,				// read attr
165 	&netfs_remove_attr,				// remove attr
166 	&netfs_rename_attr,				// rename attr
167 	&netfs_stat_attr,				// stat attr
168 
169 	&netfs_open_query,				// open query
170 	&netfs_close_query,				// close query
171 	&netfs_free_query_cookie,		// free query cookie
172 	&netfs_read_query,				// read query
173 };
174 
175 int32 api_version = B_CUR_FS_API_VERSION;
176 
177 // #pragma mark -
178 // #pragma mark ----- fs -----
179 
180 // netfs_mount
181 static
182 int
183 netfs_mount(nspace_id nsid, const char *device, ulong flags,
184 	void *parameters, size_t len, void **data, vnode_id *rootID)
185 {
186 	status_t error = B_OK;
187 	init_debugging();
188 
189 	#ifdef DEBUG_OBJECT_TRACKING
190 		ObjectTracker::InitDefault();
191 	#endif
192 
193 	// create and init the volume manager
194 	VolumeManager* volumeManager = new(std::nothrow) VolumeManager(nsid, flags);
195 	Volume* rootVolume = NULL;
196 	if (volumeManager) {
197 		error = volumeManager->MountRootVolume(device,
198 			(const char*)parameters, len, &rootVolume);
199 		if (error != B_OK) {
200 			delete volumeManager;
201 			volumeManager = NULL;
202 		}
203 	} else
204 		error = B_NO_MEMORY;
205 	VolumePutter _(rootVolume);
206 
207 	// set results
208 	if (error == B_OK) {
209 		*data = volumeManager;
210 		*rootID = rootVolume->GetRootID();
211 	} else {
212 		#ifdef DEBUG_OBJECT_TRACKING
213 			ObjectTracker::ExitDefault();
214 		#endif
215 		exit_debugging();
216 	}
217 	return error;
218 }
219 
220 // netfs_unmount
221 static
222 int
223 netfs_unmount(void *ns)
224 {
225 	VolumeManager* volumeManager = (VolumeManager*)ns;
226 
227 	PRINT("netfs_unmount()\n");
228 
229 	volumeManager->UnmountRootVolume();
230 	delete volumeManager;
231 
232 	#ifdef DEBUG_OBJECT_TRACKING
233 		ObjectTracker::ExitDefault();
234 	#endif
235 
236 	PRINT("netfs_unmount() done\n");
237 
238 	exit_debugging();
239 	return B_OK;
240 }
241 
242 #if 0 // not used
243 
244 // netfs_sync
245 static
246 int
247 netfs_sync(void *ns)
248 {
249 	VolumeManager* volumeManager = (VolumeManager*)ns;
250 	Volume* volume = volumeManager->GetRootVolume();
251 	VolumePutter _(volume);
252 
253 	PRINT("netfs_sync(%p)\n", ns);
254 
255 	status_t error = B_BAD_VALUE;
256 	if (volume)
257 		error = volume->Sync();
258 
259 	PRINT("netfs_sync() done: %" B_PRIx32 " \n", error);
260 
261 	return error;
262 }
263 
264 #endif
265 
266 // netfs_read_fs_stat
267 static
268 int
269 netfs_read_fs_stat(void *ns, struct fs_info *info)
270 {
271 	VolumeManager* volumeManager = (VolumeManager*)ns;
272 	Volume* volume = volumeManager->GetRootVolume();
273 	VolumePutter _(volume);
274 
275 	PRINT("netfs_read_fs_stat(%p, %p)\n", ns, info);
276 
277 	status_t error = B_BAD_VALUE;
278 	if (volume)
279 		error = volume->ReadFSStat(info);
280 
281 	PRINT("netfs_read_fs_stat() done: %" B_PRIx32 " \n", error);
282 
283 	return error;
284 }
285 
286 #if 0 // not used
287 
288 // netfs_write_fs_stat
289 static
290 int
291 netfs_write_fs_stat(void *ns, struct fs_info *info, long mask)
292 {
293 	VolumeManager* volumeManager = (VolumeManager*)ns;
294 	Volume* volume = volumeManager->GetRootVolume();
295 	VolumePutter _(volume);
296 
297 	PRINT("netfs_write_fs_stat(%p, %p, %ld)\n", ns, info, mask);
298 
299 	status_t error = B_BAD_VALUE;
300 	if (volume)
301 		error = volume->WriteFSStat(info, mask);
302 
303 	PRINT("netfs_write_fs_stat() done: %" B_PRIx32 " \n", error);
304 
305 	return error;
306 }
307 
308 #endif
309 
310 // #pragma mark -
311 // #pragma mark ----- vnodes -----
312 
313 // netfs_read_vnode
314 static
315 int
316 netfs_read_vnode(void *ns, vnode_id vnid, char reenter, void **node)
317 {
318 	VolumeManager* volumeManager = (VolumeManager*)ns;
319 	Volume* volume = volumeManager->GetVolume(vnid);
320 	VolumePutter _(volume);
321 
322 	PRINT("netfs_read_vnode(%p, %" B_PRIdINO ", %d, %p)\n", ns, vnid, reenter,
323 		node);
324 
325 	status_t error = B_BAD_VALUE;
326 	if (volume)
327 		error = volume->ReadVNode(vnid, reenter, (Node**)node);
328 
329 	PRINT("netfs_read_vnode() done: (%" B_PRIx32 ", %p)\n", error, *node);
330 
331 	return error;
332 }
333 
334 // netfs_write_vnode
335 static
336 int
337 netfs_write_vnode(void *ns, void *_node, char reenter)
338 {
339 	Node* node = (Node*)_node;
340 // DANGER: If dbg_printf() is used, this thread will enter another FS and
341 // even perform a write operation. The is dangerous here, since this hook
342 // may be called out of the other FSs, since, for instance a put_vnode()
343 // called from another FS may cause the VFS layer to free vnodes and thus
344 // invoke this hook.
345 //	PRINT(("netfs_write_vnode(%p, %p, %d)\n", ns, node, reenter));
346 	status_t error = node->GetVolume()->WriteVNode(node, reenter);
347 //	PRINT(("netfs_write_vnode() done: %" B_PRIx32 "\n", error));
348 	return error;
349 }
350 
351 // netfs_remove_vnode
352 static
353 int
354 netfs_remove_vnode(void *ns, void *_node, char reenter)
355 {
356 	Node* node = (Node*)_node;
357 // DANGER: See netfs_write_vnode().
358 //	PRINT(("netfs_remove_vnode(%p, %p, %d)\n", ns, node, reenter));
359 	status_t error = node->GetVolume()->RemoveVNode(node, reenter);
360 //	PRINT(("netfs_remove_vnode() done: %" B_PRIx32 "\n", error));
361 	return error;
362 }
363 
364 // #pragma mark -
365 // #pragma mark ----- nodes -----
366 
367 #if 0 // not used
368 
369 // netfs_fsync
370 static
371 int
372 netfs_fsync(void *ns, void *_node)
373 {
374 	Node* node = (Node*)_node;
375 	PRINT("netfs_fsync(%p, %p)\n", ns, node);
376 	status_t error = node->GetVolume()->FSync(node);
377 	PRINT("netfs_fsync() done: %" B_PRIx32 "\n", error);
378 	return error;
379 }
380 
381 #endif
382 
383 // netfs_read_stat
384 static
385 int
386 netfs_read_stat(void *ns, void *_node, struct stat *st)
387 {
388 	Node* node = (Node*)_node;
389 	PRINT("netfs_read_stat(%p, %p, %p)\n", ns, node, st);
390 	status_t error = node->GetVolume()->ReadStat(node, st);
391 	PRINT("netfs_read_stat() done: %" B_PRIx32 "\n", error);
392 	return error;
393 }
394 
395 // netfs_write_stat
396 static
397 int
398 netfs_write_stat(void *ns, void *_node, struct stat *st, long mask)
399 {
400 	Node* node = (Node*)_node;
401 	PRINT("netfs_write_stat(%p, %p, %p, %ld)\n", ns, node, st, mask);
402 	status_t error = node->GetVolume()->WriteStat(node, st, mask);
403 	PRINT("netfs_write_stat() done: %" B_PRIx32 "\n", error);
404 	return error;
405 }
406 
407 // netfs_access
408 static
409 int
410 netfs_access(void *ns, void *_node, int mode)
411 {
412 	Node* node = (Node*)_node;
413 	PRINT("netfs_access(%p, %p, %d)\n", ns, node, mode);
414 	status_t error = node->GetVolume()->Access(node, mode);
415 	PRINT("netfs_access() done: %" B_PRIx32 "\n", error);
416 	return error;
417 }
418 
419 // #pragma mark -
420 // #pragma mark ----- files -----
421 
422 // netfs_create
423 static
424 int
425 netfs_create(void *ns, void *_dir, const char *name, int openMode, int mode,
426 	vnode_id *vnid, void **cookie)
427 {
428 	Node* dir = (Node*)_dir;
429 	PRINT("netfs_create(%p, %p, `%s', %d, %d, %p, %p)\n", ns, dir,
430 		name, openMode, mode, vnid, cookie);
431 	status_t error = dir->GetVolume()->Create(dir, name, openMode, mode, vnid,
432 		cookie);
433 	PRINT("netfs_create() done: (%" B_PRIx32 ", %" B_PRIdINO ", %p)\n", error, *vnid,
434 		*cookie);
435 	return error;
436 }
437 
438 // netfs_open
439 static
440 int
441 netfs_open(void *ns, void *_node, int openMode, void **cookie)
442 {
443 	Node* node = (Node*)_node;
444 	PRINT("netfs_open(%p, %p, %d)\n", ns, node, openMode);
445 	status_t error = node->GetVolume()->Open(node, openMode, cookie);
446 	PRINT("netfs_open() done: (%" B_PRIx32 ", %p)\n", error, *cookie);
447 	return error;
448 }
449 
450 // netfs_close
451 static
452 int
453 netfs_close(void *ns, void *_node, void *cookie)
454 {
455 	Node* node = (Node*)_node;
456 	PRINT("netfs_close(%p, %p, %p)\n", ns, node, cookie);
457 	status_t error = node->GetVolume()->Close(node, cookie);
458 	PRINT("netfs_close() done: %" B_PRIx32 "\n", error);
459 	return error;
460 }
461 
462 // netfs_free_cookie
463 static
464 int
465 netfs_free_cookie(void *ns, void *_node, void *cookie)
466 {
467 	Node* node = (Node*)_node;
468 	PRINT("netfs_free_cookie(%p, %p, %p)\n", ns, node, cookie);
469 	status_t error = node->GetVolume()->FreeCookie(node, cookie);
470 	PRINT("netfs_free_cookie() done: %" B_PRIx32 "\n", error);
471 	return error;
472 }
473 
474 // netfs_read
475 static
476 int
477 netfs_read(void *ns, void *_node, void *cookie, off_t pos, void *buffer,
478 	size_t *bufferSize)
479 {
480 	Node* node = (Node*)_node;
481 	PRINT("netfs_read(%p, %p, %p, %" B_PRIdOFF ", %p, %lu)\n", ns, node,
482 		cookie, pos, buffer, *bufferSize);
483 	status_t error = node->GetVolume()->Read(node, cookie, pos, buffer,
484 		*bufferSize, bufferSize);
485 	PRINT("netfs_read() done: (%" B_PRIx32 ", %lu)\n", error, *bufferSize);
486 	return error;
487 }
488 
489 // netfs_write
490 static
491 int
492 netfs_write(void *ns, void *_node, void *cookie, off_t pos,
493 	const void *buffer, size_t *bufferSize)
494 {
495 	Node* node = (Node*)_node;
496 	PRINT("netfs_write(%p, %p, %p, %" B_PRIdOFF ", %p, %lu)\n", ns, node,
497 		cookie, pos, buffer, *bufferSize);
498 	status_t error = node->GetVolume()->Write(node, cookie, pos, buffer,
499 		*bufferSize, bufferSize);
500 	PRINT("netfs_write() done: (%" B_PRIx32 ", %lu)\n", error, *bufferSize);
501 	return error;
502 }
503 
504 // netfs_ioctl
505 static
506 int
507 netfs_ioctl(void *ns, void *_node, void *cookie, int cmd, void *buffer,
508 	size_t bufferSize)
509 {
510 	Node* node = (Node*)_node;
511 	PRINT("netfs_ioctl(%p, %p, %p, %d, %p, %lu)\n", ns, node, cookie, cmd,
512 		buffer, bufferSize);
513 	status_t error = node->GetVolume()->IOCtl(node, cookie, cmd, buffer,
514 		bufferSize);
515 	PRINT("netfs_ioctl() done: (%" B_PRIx32 ")\n", error);
516 	return error;
517 }
518 
519 // netfs_setflags
520 //static
521 //int
522 //netfs_setflags(void *ns, void *_node, void *cookie, int flags)
523 //{
524 //	Node* node = (Node*)_node;
525 //	PRINT(("netfs_setflags(%p, %p, %p, %d)\n", ns, node, cookie, flags));
526 //	status_t error = node->GetVolume()->SetFlags(node, cookie, flags);
527 //	PRINT(("netfs_setflags() done: (%lx)\n", error));
528 //	return error;
529 //}
530 
531 // #pragma mark -
532 // #pragma mark ----- hard links / symlinks -----
533 
534 // netfs_link
535 static
536 int
537 netfs_link(void *ns, void *_dir, const char *name, void *_node)
538 {
539 	Node* dir = (Node*)_dir;
540 	Node* node = (Node*)_node;
541 	PRINT("netfs_link(%p, %p, `%s', %p)\n", ns, dir, name, node);
542 	status_t error = dir->GetVolume()->Link(dir, name, node);
543 	PRINT("netfs_link() done: (%" B_PRIx32 ")\n", error);
544 	return error;
545 }
546 
547 // netfs_unlink
548 static
549 int
550 netfs_unlink(void *ns, void *_dir, const char *name)
551 {
552 	Node* dir = (Node*)_dir;
553 	PRINT("netfs_unlink(%p, %p, `%s')\n", ns, dir, name);
554 	status_t error = dir->GetVolume()->Unlink(dir, name);
555 	PRINT("netfs_unlink() done: (%" B_PRIx32 ")\n", error);
556 	return error;
557 }
558 
559 // netfs_symlink
560 static
561 int
562 netfs_symlink(void *ns, void *_dir, const char *name, const char *path)
563 {
564 	Node* dir = (Node*)_dir;
565 	PRINT("netfs_symlink(%p, %p, `%s', `%s')\n", ns, dir, name, path);
566 	status_t error = dir->GetVolume()->Symlink(dir, name, path);
567 	PRINT("netfs_symlink() done: (%" B_PRIx32 ")\n", error);
568 	return error;
569 }
570 
571 // netfs_read_link
572 static
573 int
574 netfs_read_link(void *ns, void *_node, char *buffer, size_t *bufferSize)
575 {
576 	Node* node = (Node*)_node;
577 	PRINT("netfs_read_link(%p, %p, %p, %lu)\n", ns, node, buffer,
578 		*bufferSize);
579 	status_t error = node->GetVolume()->ReadLink(node, buffer, *bufferSize,
580 		bufferSize);
581 	PRINT("netfs_read_link() done: (%" B_PRIx32 ", %lu)\n", error,
582 		*bufferSize);
583 	return error;
584 }
585 
586 // netfs_rename
587 static
588 int
589 netfs_rename(void *ns, void *_oldDir, const char *oldName, void *_newDir,
590 	const char *newName)
591 {
592 	Node* oldDir = (Node*)_oldDir;
593 	Node* newDir = (Node*)_newDir;
594 	PRINT("netfs_rename(%p, %p, `%s', %p, `%s')\n", ns, oldDir, oldName,
595 		newDir, newName);
596 	status_t error = oldDir->GetVolume()->Rename(oldDir, oldName,
597 		newDir, newName);
598 	PRINT("netfs_rename() done: (%" B_PRIx32 ")\n", error);
599 	return error;
600 }
601 
602 // #pragma mark -
603 // #pragma mark ----- directories -----
604 
605 // netfs_mkdir
606 static
607 int
608 netfs_mkdir(void *ns, void *_dir, const char *name, int mode)
609 {
610 	Node* dir = (Node*)_dir;
611 	PRINT("netfs_mkdir(%p, %p, `%s', %d)\n", ns, dir, name, mode);
612 	status_t error = dir->GetVolume()->MkDir(dir, name, mode);
613 	PRINT("netfs_mkdir() done: (%" B_PRIx32 ")\n", error);
614 	return error;
615 }
616 
617 // netfs_rmdir
618 static
619 int
620 netfs_rmdir(void *ns, void *_dir, const char *name)
621 {
622 	Node* dir = (Node*)_dir;
623 	PRINT("netfs_rmdir(%p, %p, `%s')\n", ns, dir, name);
624 	status_t error = dir->GetVolume()->RmDir(dir, name);
625 	PRINT("netfs_rmdir() done: (%" B_PRIx32 ")\n", error);
626 	return error;
627 }
628 
629 // netfs_open_dir
630 static
631 int
632 netfs_open_dir(void *ns, void *_node, void **cookie)
633 {
634 	Node* node = (Node*)_node;
635 	PRINT("netfs_open_dir(%p, %p)\n", ns, node);
636 	status_t error = node->GetVolume()->OpenDir(node, cookie);
637 	PRINT("netfs_open_dir() done: (%" B_PRIx32 ", %p)\n", error, *cookie);
638 	return error;
639 }
640 
641 // netfs_close_dir
642 static
643 int
644 netfs_close_dir(void *ns, void *_node, void *cookie)
645 {
646 	Node* node = (Node*)_node;
647 	PRINT("netfs_close_dir(%p, %p, %p)\n", ns, node, cookie);
648 	status_t error = node->GetVolume()->CloseDir(node, cookie);
649 	PRINT("netfs_close_dir() done: %" B_PRIx32 "\n", error);
650 	return error;
651 }
652 
653 // netfs_free_dir_cookie
654 static
655 int
656 netfs_free_dir_cookie(void *ns, void *_node, void *cookie)
657 {
658 	Node* node = (Node*)_node;
659 	PRINT("netfs_free_dir_cookie(%p, %p, %p)\n", ns, node, cookie);
660 	status_t error = node->GetVolume()->FreeDirCookie(node, cookie);
661 	PRINT("netfs_free_dir_cookie() done: %" B_PRIx32 " \n", error);
662 	return error;
663 }
664 
665 // netfs_read_dir
666 static
667 int
668 netfs_read_dir(void *ns, void *_node, void *cookie, long *count,
669 	struct dirent *buffer, size_t bufferSize)
670 {
671 	Node* node = (Node*)_node;
672 	PRINT("netfs_read_dir(%p, %p, %p, %ld, %p, %lu)\n", ns, node, cookie,
673 		*count, buffer, bufferSize);
674 	int32 _count = *count;
675 	status_t error = node->GetVolume()->ReadDir(node, cookie, buffer,
676 		bufferSize, _count, &_count);
677 	*count = _count;
678 	PRINT("netfs_read_dir() done: (%" B_PRIx32 ", %ld)\n", error, *count);
679 	#if DEBUG
680 		dirent* entry = buffer;
681 		for (int32 i = 0; i < *count; i++) {
682 			// R5's kernel vsprintf() doesn't seem to know `%.<number>s', so
683 			// we need to work around.
684 			char name[B_FILE_NAME_LENGTH];
685 			int nameLen = strnlen(entry->d_name, B_FILE_NAME_LENGTH - 1);
686 			strncpy(name, entry->d_name, nameLen);
687 			name[nameLen] = '\0';
688 			PRINT("  entry: d_dev: %" B_PRIdDEV ", d_pdev: %" B_PRIdDEV
689 				", d_ino: %" B_PRIdINO ", d_pino: %" B_PRIdINO
690 				", d_reclen: %hu, d_name: `%s'\n",
691 				entry->d_dev, entry->d_pdev, entry->d_ino,
692 				entry->d_pino, entry->d_reclen, name);
693 			entry = (dirent*)((char*)entry + entry->d_reclen);
694 		}
695 	#endif
696 
697 	return error;
698 }
699 
700 // netfs_rewind_dir
701 static
702 int
703 netfs_rewind_dir(void *ns, void *_node, void *cookie)
704 {
705 	Node* node = (Node*)_node;
706 	PRINT("netfs_rewind_dir(%p, %p, %p)\n", ns, node, cookie);
707 	status_t error = node->GetVolume()->RewindDir(node, cookie);
708 	PRINT("netfs_rewind_dir() done: %" B_PRIx32 "\n", error);
709 	return error;
710 }
711 
712 // netfs_walk
713 static
714 int
715 netfs_walk(void *ns, void *_dir, const char *entryName,
716 	char **resolvedPath, vnode_id *vnid)
717 {
718 	Node* dir = (Node*)_dir;
719 	PRINT("netfs_walk(%p, %p, `%s', %p, %p)\n", ns, dir,
720 		entryName, resolvedPath, vnid);
721 	status_t error = dir->GetVolume()->Walk(dir, entryName, resolvedPath, vnid);
722 	PRINT("netfs_walk() done: (%" B_PRIx32 ", `%s', %" B_PRIdINO ")\n", error,
723 		(resolvedPath ? *resolvedPath : NULL), *vnid);
724 	return error;
725 }
726 
727 // #pragma mark -
728 // #pragma mark ----- attributes -----
729 
730 // netfs_open_attrdir
731 static
732 int
733 netfs_open_attrdir(void *ns, void *_node, void **cookie)
734 {
735 	Node* node = (Node*)_node;
736 	PRINT("netfs_open_attrdir(%p, %p)\n", ns, node);
737 	status_t error = node->GetVolume()->OpenAttrDir(node, cookie);
738 	PRINT("netfs_open_attrdir() done: (%" B_PRIx32 ", %p)\n", error, *cookie);
739 	return error;
740 }
741 
742 // netfs_close_attrdir
743 static
744 int
745 netfs_close_attrdir(void *ns, void *_node, void *cookie)
746 {
747 	Node* node = (Node*)_node;
748 	PRINT("netfs_close_attrdir(%p, %p, %p)\n", ns, node, cookie);
749 	status_t error = node->GetVolume()->CloseAttrDir(node, cookie);
750 	PRINT("netfs_close_attrdir() done: (%" B_PRIx32 ")\n", error);
751 	return error;
752 }
753 
754 // netfs_free_attrdir_cookie
755 static
756 int
757 netfs_free_attrdir_cookie(void *ns, void *_node, void *cookie)
758 {
759 	Node* node = (Node*)_node;
760 	PRINT("netfs_free_attrdir_cookie(%p, %p, %p)\n", ns, node, cookie);
761 	status_t error = node->GetVolume()->FreeAttrDirCookie(node, cookie);
762 	PRINT("netfs_free_attrdir_cookie() done: (%" B_PRIx32 ")\n", error);
763 	return error;
764 }
765 
766 // netfs_read_attrdir
767 static
768 int
769 netfs_read_attrdir(void *ns, void *_node, void *cookie, long *count,
770 	struct dirent *buffer, size_t bufferSize)
771 {
772 	Node* node = (Node*)_node;
773 	PRINT("netfs_read_attrdir(%p, %p, %p, %ld, %p, %lu)\n", ns, node,
774 		cookie, *count, buffer, bufferSize);
775 	int32 _count = *count;
776 	status_t error = node->GetVolume()->ReadAttrDir(node, cookie, buffer,
777 		bufferSize, _count, &_count);
778 	*count = _count;
779 	PRINT("netfs_read_attrdir() done: (%" B_PRIx32 ", %ld)\n", error, *count);
780 	return error;
781 }
782 
783 // netfs_rewind_attrdir
784 static
785 int
786 netfs_rewind_attrdir(void *ns, void *_node, void *cookie)
787 {
788 	Node* node = (Node*)_node;
789 	PRINT("netfs_rewind_attrdir(%p, %p, %p)\n", ns, node, cookie);
790 	status_t error = node->GetVolume()->RewindAttrDir(node, cookie);
791 	PRINT("netfs_rewind_attrdir() done: (%" B_PRIx32 ")\n", error);
792 	return error;
793 }
794 
795 // netfs_read_attr
796 static
797 int
798 netfs_read_attr(void *ns, void *_node, const char *name, int type,
799 	void *buffer, size_t *bufferSize, off_t pos)
800 {
801 	Node* node = (Node*)_node;
802 	PRINT("netfs_read_attr(%p, %p, `%s', %d, %p, %lu, %" B_PRIdOFF ")\n", ns,
803 		node, name, type, buffer, *bufferSize, pos);
804 	status_t error = node->GetVolume()->ReadAttr(node, name, type, pos, buffer,
805 		*bufferSize, bufferSize);
806 	PRINT("netfs_read_attr() done: (%" B_PRIx32 ", %ld)\n", error,
807 		*bufferSize);
808 	return error;
809 }
810 
811 // netfs_write_attr
812 static
813 int
814 netfs_write_attr(void *ns, void *_node, const char *name, int type,
815 	const void *buffer, size_t *bufferSize, off_t pos)
816 {
817 	Node* node = (Node*)_node;
818 	PRINT("netfs_write_attr(%p, %p, `%s', %d, %p, %lu, %" B_PRIdOFF ")\n", ns,
819 		node, name, type, buffer, *bufferSize, pos);
820 	status_t error = node->GetVolume()->WriteAttr(node, name, type, pos, buffer,
821 		*bufferSize, bufferSize);
822 	PRINT("netfs_write_attr() done: (%" B_PRIx32 ", %ld)\n", error,
823 		*bufferSize);
824 	return error;
825 }
826 
827 // netfs_remove_attr
828 static
829 int
830 netfs_remove_attr(void *ns, void *_node, const char *name)
831 {
832 	Node* node = (Node*)_node;
833 	PRINT("netfs_remove_attr(%p, %p, `%s')\n", ns, node, name);
834 	status_t error = node->GetVolume()->RemoveAttr(node, name);
835 	PRINT("netfs_remove_attr() done: (%" B_PRIx32 ")\n", error);
836 	return error;
837 }
838 
839 // netfs_rename_attr
840 static
841 int
842 netfs_rename_attr(void *ns, void *_node, const char *oldName,
843 	const char *newName)
844 {
845 	Node* node = (Node*)_node;
846 	PRINT("netfs_rename_attr(%p, %p, `%s', `%s')\n", ns, node, oldName,
847 		newName);
848 	status_t error = node->GetVolume()->RenameAttr(node, oldName, newName);
849 	PRINT("netfs_rename_attr() done: (%" B_PRIx32 ")\n", error);
850 	return error;
851 }
852 
853 // netfs_stat_attr
854 static
855 int
856 netfs_stat_attr(void *ns, void *_node, const char *name,
857 	struct attr_info *attrInfo)
858 {
859 	Node* node = (Node*)_node;
860 	PRINT("netfs_stat_attr(%p, %p, `%s', %p)\n", ns, node, name,
861 		attrInfo);
862 	status_t error = node->GetVolume()->StatAttr(node, name, attrInfo);
863 	PRINT("netfs_stat_attr() done: (%" B_PRIx32 ")\n", error);
864 	return error;
865 }
866 
867 // #pragma mark -
868 // #pragma mark ----- queries -----
869 
870 // netfs_open_query
871 static
872 int
873 netfs_open_query(void *ns, const char *queryString, ulong flags,
874 	port_id port, long token, void **cookie)
875 {
876 	VolumeManager* volumeManager = (VolumeManager*)ns;
877 	Volume* volume = volumeManager->GetRootVolume();
878 	VolumePutter _(volume);
879 
880 	PRINT("netfs_open_query(%p, `%s', %lu, %" B_PRId32 ", %ld, %p)\n", ns,
881 		queryString, flags, port, token, cookie);
882 
883 	status_t error = B_BAD_VALUE;
884 	if (volume) {
885 		error = volume->OpenQuery(queryString, flags, port, token,
886 			(QueryIterator**)cookie);
887 	}
888 
889 	PRINT("netfs_open_query() done: (%" B_PRIx32 ", %p)\n", error, *cookie);
890 	return error;
891 }
892 
893 // netfs_close_query
894 static
895 int
896 netfs_close_query(void *ns, void *cookie)
897 {
898 	PRINT("netfs_close_query(%p, %p)\n", ns, cookie);
899 
900 	status_t error = B_OK;
901 	// no-op: we don't use this hook
902 
903 	PRINT("netfs_close_query() done: (%" B_PRIx32 ")\n", error);
904 	return error;
905 }
906 
907 // netfs_free_query_cookie
908 static
909 int
910 netfs_free_query_cookie(void *ns, void *node, void *cookie)
911 {
912 	VolumeManager* volumeManager = (VolumeManager*)ns;
913 	QueryIterator* iterator = (QueryIterator*)cookie;
914 
915 	PRINT("netfs_free_query_cookie(%p, %p)\n", ns, cookie);
916 
917 	status_t error = B_OK;
918 	volumeManager->GetQueryManager()->PutIterator(iterator);
919 
920 	PRINT("netfs_free_query_cookie() done: (%" B_PRIx32 ")\n", error);
921 	return error;
922 }
923 
924 // netfs_read_query
925 static
926 int
927 netfs_read_query(void *ns, void *cookie, long *count,
928 	struct dirent *buffer, size_t bufferSize)
929 {
930 	VolumeManager* volumeManager = (VolumeManager*)ns;
931 	Volume* volume = volumeManager->GetRootVolume();
932 	QueryIterator* iterator = (QueryIterator*)cookie;
933 	VolumePutter _(volume);
934 
935 	PRINT("netfs_read_query(%p, %p, %ld, %p, %lu)\n", ns, cookie,
936 		*count, buffer, bufferSize);
937 
938 	status_t error = B_BAD_VALUE;
939 	if (volume) {
940 		int32 _count = *count;
941 		error = volume->ReadQuery(iterator, buffer, bufferSize,
942 			_count, &_count);
943 		*count = _count;
944 	}
945 
946 	PRINT("netfs_read_query() done: (%" B_PRIx32 ", %ld)\n", error, *count);
947 	return error;
948 }
949 
950