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
18extern "C" {
19
20// fs
21static int netfs_mount(nspace_id nsid, const char *device, ulong flags,
22				void *parameters, size_t len, void **data, vnode_id *rootID);
23static int netfs_unmount(void *ns);
24//static int netfs_sync(void *ns);
25static 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
29static int netfs_read_vnode(void *ns, vnode_id vnid, char reenter,
30				void **node);
31static int netfs_write_vnode(void *ns, void *node, char reenter);
32static int netfs_remove_vnode(void *ns, void *node, char reenter);
33
34// nodes
35//static int netfs_fsync(void *ns, void *node);
36static int netfs_read_stat(void *ns, void *node, struct stat *st);
37static int netfs_write_stat(void *ns, void *node, struct stat *st,
38				long mask);
39static int netfs_access(void *ns, void *node, int mode);
40
41// files
42static int netfs_create(void *ns, void *dir, const char *name,
43				int openMode, int mode, vnode_id *vnid, void **cookie);
44static int netfs_open(void *ns, void *node, int openMode, void **cookie);
45static int netfs_close(void *ns, void *node, void *cookie);
46static int netfs_free_cookie(void *ns, void *node, void *cookie);
47static int netfs_read(void *ns, void *node, void *cookie, off_t pos,
48				void *buffer, size_t *bufferSize);
49static int netfs_write(void *ns, void *node, void *cookie, off_t pos,
50				const void *buffer, size_t *bufferSize);
51static 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
56static int netfs_link(void *ns, void *dir, const char *name, void *node);
57static int netfs_unlink(void *ns, void *dir, const char *name);
58static int netfs_symlink(void *ns, void *dir, const char *name,
59				const char *path);
60static int netfs_read_link(void *ns, void *node, char *buffer,
61				size_t *bufferSize);
62static int netfs_rename(void *ns, void *oldDir, const char *oldName,
63				void *newDir, const char *newName);
64
65// directories
66static int netfs_mkdir(void *ns, void *dir, const char *name, int mode);
67static int netfs_rmdir(void *ns, void *dir, const char *name);
68static int netfs_open_dir(void *ns, void *node, void **cookie);
69static int netfs_close_dir(void *ns, void *node, void *cookie);
70static int netfs_free_dir_cookie(void *ns, void *node, void *cookie);
71static int netfs_read_dir(void *ns, void *node, void *cookie,
72				long *count, struct dirent *buffer, size_t bufferSize);
73static int netfs_rewind_dir(void *ns, void *node, void *cookie);
74static int netfs_walk(void *ns, void *dir, const char *entryName,
75				char **resolvedPath, vnode_id *vnid);
76
77// attributes
78static int netfs_open_attrdir(void *ns, void *node, void **cookie);
79static int netfs_close_attrdir(void *ns, void *node, void *cookie);
80static int netfs_free_attrdir_cookie(void *ns, void *node, void *cookie);
81static int netfs_read_attrdir(void *ns, void *node, void *cookie,
82				long *count, struct dirent *buffer, size_t bufferSize);
83static int netfs_read_attr(void *ns, void *node, const char *name,
84				int type, void *buffer, size_t *bufferSize, off_t pos);
85static int netfs_rewind_attrdir(void *ns, void *node, void *cookie);
86static int netfs_write_attr(void *ns, void *node, const char *name,
87				int type, const void *buffer, size_t *bufferSize, off_t pos);
88static int netfs_remove_attr(void *ns, void *node, const char *name);
89static int netfs_rename_attr(void *ns, void *node, const char *oldName,
90				const char *newName);
91static int netfs_stat_attr(void *ns, void *node, const char *name,
92				struct attr_info *attrInfo);
93
94// queries
95static int netfs_open_query(void *ns, const char *queryString, ulong flags,
96				port_id port, long token, void **cookie);
97static int netfs_close_query(void *ns, void *cookie);
98static int netfs_free_query_cookie(void *ns, void *node, void *cookie);
99static 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*/
107vnode_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
175int32 api_version = B_CUR_FS_API_VERSION;
176
177// #pragma mark -
178// #pragma mark ----- fs -----
179
180// netfs_mount
181static
182int
183netfs_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
221static
222int
223netfs_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
245static
246int
247netfs_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
267static
268int
269netfs_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
289static
290int
291netfs_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
314static
315int
316netfs_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
335static
336int
337netfs_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
352static
353int
354netfs_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
370static
371int
372netfs_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
384static
385int
386netfs_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
396static
397int
398netfs_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
408static
409int
410netfs_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
423static
424int
425netfs_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
439static
440int
441netfs_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
451static
452int
453netfs_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
463static
464int
465netfs_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
475static
476int
477netfs_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
490static
491int
492netfs_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
505static
506int
507netfs_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
535static
536int
537netfs_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
548static
549int
550netfs_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
560static
561int
562netfs_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
572static
573int
574netfs_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
587static
588int
589netfs_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
606static
607int
608netfs_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
618static
619int
620netfs_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
630static
631int
632netfs_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
642static
643int
644netfs_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
654static
655int
656netfs_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
666static
667int
668netfs_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
701static
702int
703netfs_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
713static
714int
715netfs_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
731static
732int
733netfs_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
743static
744int
745netfs_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
755static
756int
757netfs_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
767static
768int
769netfs_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
784static
785int
786netfs_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
796static
797int
798netfs_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
812static
813int
814netfs_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
828static
829int
830netfs_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
840static
841int
842netfs_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
854static
855int
856netfs_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
871static
872int
873netfs_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
894static
895int
896netfs_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
908static
909int
910netfs_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
925static
926int
927netfs_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