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: %lx \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: %lx \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: %lx \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, %Ld, %d, %p)\n", ns, vnid, reenter, node);
323
324	status_t error = B_BAD_VALUE;
325	if (volume)
326		error = volume->ReadVNode(vnid, reenter, (Node**)node);
327
328	PRINT("netfs_read_vnode() done: (%lx, %p)\n", error, *node);
329
330	return error;
331}
332
333// netfs_write_vnode
334static
335int
336netfs_write_vnode(void *ns, void *_node, char reenter)
337{
338	Node* node = (Node*)_node;
339// DANGER: If dbg_printf() is used, this thread will enter another FS and
340// even perform a write operation. The is dangerous here, since this hook
341// may be called out of the other FSs, since, for instance a put_vnode()
342// called from another FS may cause the VFS layer to free vnodes and thus
343// invoke this hook.
344//	PRINT(("netfs_write_vnode(%p, %p, %d)\n", ns, node, reenter));
345	status_t error = node->GetVolume()->WriteVNode(node, reenter);
346//	PRINT(("netfs_write_vnode() done: %lx\n", error));
347	return error;
348}
349
350// netfs_remove_vnode
351static
352int
353netfs_remove_vnode(void *ns, void *_node, char reenter)
354{
355	Node* node = (Node*)_node;
356// DANGER: See netfs_write_vnode().
357//	PRINT(("netfs_remove_vnode(%p, %p, %d)\n", ns, node, reenter));
358	status_t error = node->GetVolume()->RemoveVNode(node, reenter);
359//	PRINT(("netfs_remove_vnode() done: %lx\n", error));
360	return error;
361}
362
363// #pragma mark -
364// #pragma mark ----- nodes -----
365
366#if 0 // not used
367
368// netfs_fsync
369static
370int
371netfs_fsync(void *ns, void *_node)
372{
373	Node* node = (Node*)_node;
374	PRINT("netfs_fsync(%p, %p)\n", ns, node);
375	status_t error = node->GetVolume()->FSync(node);
376	PRINT("netfs_fsync() done: %lx\n", error);
377	return error;
378}
379
380#endif
381
382// netfs_read_stat
383static
384int
385netfs_read_stat(void *ns, void *_node, struct stat *st)
386{
387	Node* node = (Node*)_node;
388	PRINT("netfs_read_stat(%p, %p, %p)\n", ns, node, st);
389	status_t error = node->GetVolume()->ReadStat(node, st);
390	PRINT("netfs_read_stat() done: %lx\n", error);
391	return error;
392}
393
394// netfs_write_stat
395static
396int
397netfs_write_stat(void *ns, void *_node, struct stat *st, long mask)
398{
399	Node* node = (Node*)_node;
400	PRINT("netfs_write_stat(%p, %p, %p, %ld)\n", ns, node, st, mask);
401	status_t error = node->GetVolume()->WriteStat(node, st, mask);
402	PRINT("netfs_write_stat() done: %lx\n", error);
403	return error;
404}
405
406// netfs_access
407static
408int
409netfs_access(void *ns, void *_node, int mode)
410{
411	Node* node = (Node*)_node;
412	PRINT("netfs_access(%p, %p, %d)\n", ns, node, mode);
413	status_t error = node->GetVolume()->Access(node, mode);
414	PRINT("netfs_access() done: %lx\n", error);
415	return error;
416}
417
418// #pragma mark -
419// #pragma mark ----- files -----
420
421// netfs_create
422static
423int
424netfs_create(void *ns, void *_dir, const char *name, int openMode, int mode,
425	vnode_id *vnid, void **cookie)
426{
427	Node* dir = (Node*)_dir;
428	PRINT("netfs_create(%p, %p, `%s', %d, %d, %p, %p)\n", ns, dir,
429		name, openMode, mode, vnid, cookie);
430	status_t error = dir->GetVolume()->Create(dir, name, openMode, mode, vnid,
431		cookie);
432	PRINT("netfs_create() done: (%lx, %Ld, %p)\n", error, *vnid,
433		*cookie);
434	return error;
435}
436
437// netfs_open
438static
439int
440netfs_open(void *ns, void *_node, int openMode, void **cookie)
441{
442	Node* node = (Node*)_node;
443	PRINT("netfs_open(%p, %p, %d)\n", ns, node, openMode);
444	status_t error = node->GetVolume()->Open(node, openMode, cookie);
445	PRINT("netfs_open() done: (%lx, %p)\n", error, *cookie);
446	return error;
447}
448
449// netfs_close
450static
451int
452netfs_close(void *ns, void *_node, void *cookie)
453{
454	Node* node = (Node*)_node;
455	PRINT("netfs_close(%p, %p, %p)\n", ns, node, cookie);
456	status_t error = node->GetVolume()->Close(node, cookie);
457	PRINT("netfs_close() done: %lx\n", error);
458	return error;
459}
460
461// netfs_free_cookie
462static
463int
464netfs_free_cookie(void *ns, void *_node, void *cookie)
465{
466	Node* node = (Node*)_node;
467	PRINT("netfs_free_cookie(%p, %p, %p)\n", ns, node, cookie);
468	status_t error = node->GetVolume()->FreeCookie(node, cookie);
469	PRINT("netfs_free_cookie() done: %lx\n", error);
470	return error;
471}
472
473// netfs_read
474static
475int
476netfs_read(void *ns, void *_node, void *cookie, off_t pos, void *buffer,
477	size_t *bufferSize)
478{
479	Node* node = (Node*)_node;
480	PRINT("netfs_read(%p, %p, %p, %Ld, %p, %lu)\n", ns, node, cookie, pos,
481		buffer, *bufferSize);
482	status_t error = node->GetVolume()->Read(node, cookie, pos, buffer,
483		*bufferSize, bufferSize);
484	PRINT("netfs_read() done: (%lx, %lu)\n", error, *bufferSize);
485	return error;
486}
487
488// netfs_write
489static
490int
491netfs_write(void *ns, void *_node, void *cookie, off_t pos,
492	const void *buffer, size_t *bufferSize)
493{
494	Node* node = (Node*)_node;
495	PRINT("netfs_write(%p, %p, %p, %Ld, %p, %lu)\n", ns, node, cookie, pos,
496		buffer, *bufferSize);
497	status_t error = node->GetVolume()->Write(node, cookie, pos, buffer,
498		*bufferSize, bufferSize);
499	PRINT("netfs_write() done: (%lx, %lu)\n", error, *bufferSize);
500	return error;
501}
502
503// netfs_ioctl
504static
505int
506netfs_ioctl(void *ns, void *_node, void *cookie, int cmd, void *buffer,
507	size_t bufferSize)
508{
509	Node* node = (Node*)_node;
510	PRINT("netfs_ioctl(%p, %p, %p, %d, %p, %lu)\n", ns, node, cookie, cmd,
511		buffer, bufferSize);
512	status_t error = node->GetVolume()->IOCtl(node, cookie, cmd, buffer,
513		bufferSize);
514	PRINT("netfs_ioctl() done: (%lx)\n", error);
515	return error;
516}
517
518// netfs_setflags
519//static
520//int
521//netfs_setflags(void *ns, void *_node, void *cookie, int flags)
522//{
523//	Node* node = (Node*)_node;
524//	PRINT(("netfs_setflags(%p, %p, %p, %d)\n", ns, node, cookie, flags));
525//	status_t error = node->GetVolume()->SetFlags(node, cookie, flags);
526//	PRINT(("netfs_setflags() done: (%lx)\n", error));
527//	return error;
528//}
529
530// #pragma mark -
531// #pragma mark ----- hard links / symlinks -----
532
533// netfs_link
534static
535int
536netfs_link(void *ns, void *_dir, const char *name, void *_node)
537{
538	Node* dir = (Node*)_dir;
539	Node* node = (Node*)_node;
540	PRINT("netfs_link(%p, %p, `%s', %p)\n", ns, dir, name, node);
541	status_t error = dir->GetVolume()->Link(dir, name, node);
542	PRINT("netfs_link() done: (%lx)\n", error);
543	return error;
544}
545
546// netfs_unlink
547static
548int
549netfs_unlink(void *ns, void *_dir, const char *name)
550{
551	Node* dir = (Node*)_dir;
552	PRINT("netfs_unlink(%p, %p, `%s')\n", ns, dir, name);
553	status_t error = dir->GetVolume()->Unlink(dir, name);
554	PRINT("netfs_unlink() done: (%lx)\n", error);
555	return error;
556}
557
558// netfs_symlink
559static
560int
561netfs_symlink(void *ns, void *_dir, const char *name, const char *path)
562{
563	Node* dir = (Node*)_dir;
564	PRINT("netfs_symlink(%p, %p, `%s', `%s')\n", ns, dir, name, path);
565	status_t error = dir->GetVolume()->Symlink(dir, name, path);
566	PRINT("netfs_symlink() done: (%lx)\n", error);
567	return error;
568}
569
570// netfs_read_link
571static
572int
573netfs_read_link(void *ns, void *_node, char *buffer, size_t *bufferSize)
574{
575	Node* node = (Node*)_node;
576	PRINT("netfs_read_link(%p, %p, %p, %lu)\n", ns, node, buffer,
577		*bufferSize);
578	status_t error = node->GetVolume()->ReadLink(node, buffer, *bufferSize,
579		bufferSize);
580	PRINT("netfs_read_link() done: (%lx, %lu)\n", error, *bufferSize);
581	return error;
582}
583
584// netfs_rename
585static
586int
587netfs_rename(void *ns, void *_oldDir, const char *oldName, void *_newDir,
588	const char *newName)
589{
590	Node* oldDir = (Node*)_oldDir;
591	Node* newDir = (Node*)_newDir;
592	PRINT("netfs_rename(%p, %p, `%s', %p, `%s')\n", ns, oldDir, oldName,
593		newDir, newName);
594	status_t error = oldDir->GetVolume()->Rename(oldDir, oldName,
595		newDir, newName);
596	PRINT("netfs_rename() done: (%lx)\n", error);
597	return error;
598}
599
600// #pragma mark -
601// #pragma mark ----- directories -----
602
603// netfs_mkdir
604static
605int
606netfs_mkdir(void *ns, void *_dir, const char *name, int mode)
607{
608	Node* dir = (Node*)_dir;
609	PRINT("netfs_mkdir(%p, %p, `%s', %d)\n", ns, dir, name, mode);
610	status_t error = dir->GetVolume()->MkDir(dir, name, mode);
611	PRINT("netfs_mkdir() done: (%lx)\n", error);
612	return error;
613}
614
615// netfs_rmdir
616static
617int
618netfs_rmdir(void *ns, void *_dir, const char *name)
619{
620	Node* dir = (Node*)_dir;
621	PRINT("netfs_rmdir(%p, %p, `%s')\n", ns, dir, name);
622	status_t error = dir->GetVolume()->RmDir(dir, name);
623	PRINT("netfs_rmdir() done: (%lx)\n", error);
624	return error;
625}
626
627// netfs_open_dir
628static
629int
630netfs_open_dir(void *ns, void *_node, void **cookie)
631{
632	Node* node = (Node*)_node;
633	PRINT("netfs_open_dir(%p, %p)\n", ns, node);
634	status_t error = node->GetVolume()->OpenDir(node, cookie);
635	PRINT("netfs_open_dir() done: (%lx, %p)\n", error, *cookie);
636	return error;
637}
638
639// netfs_close_dir
640static
641int
642netfs_close_dir(void *ns, void *_node, void *cookie)
643{
644	Node* node = (Node*)_node;
645	PRINT("netfs_close_dir(%p, %p, %p)\n", ns, node, cookie);
646	status_t error = node->GetVolume()->CloseDir(node, cookie);
647	PRINT("netfs_close_dir() done: %lx\n", error);
648	return error;
649}
650
651// netfs_free_dir_cookie
652static
653int
654netfs_free_dir_cookie(void *ns, void *_node, void *cookie)
655{
656	Node* node = (Node*)_node;
657	PRINT("netfs_free_dir_cookie(%p, %p, %p)\n", ns, node, cookie);
658	status_t error = node->GetVolume()->FreeDirCookie(node, cookie);
659	PRINT("netfs_free_dir_cookie() done: %lx \n", error);
660	return error;
661}
662
663// netfs_read_dir
664static
665int
666netfs_read_dir(void *ns, void *_node, void *cookie, long *count,
667	struct dirent *buffer, size_t bufferSize)
668{
669	Node* node = (Node*)_node;
670	PRINT("netfs_read_dir(%p, %p, %p, %ld, %p, %lu)\n", ns, node, cookie,
671		*count, buffer, bufferSize);
672	status_t error = node->GetVolume()->ReadDir(node, cookie, buffer,
673		bufferSize, *count, count);
674	PRINT("netfs_read_dir() done: (%lx, %ld)\n", error, *count);
675	#if DEBUG
676		dirent* entry = buffer;
677		for (int32 i = 0; i < *count; i++) {
678			// R5's kernel vsprintf() doesn't seem to know `%.<number>s', so
679			// we need to work around.
680			char name[B_FILE_NAME_LENGTH];
681			int nameLen = strnlen(entry->d_name, B_FILE_NAME_LENGTH - 1);
682			strncpy(name, entry->d_name, nameLen);
683			name[nameLen] = '\0';
684			PRINT("  entry: d_dev: %ld, d_pdev: %ld, d_ino: %Ld,"
685				" d_pino: %Ld, d_reclen: %hu, d_name: `%s'\n",
686				entry->d_dev, entry->d_pdev, entry->d_ino,
687				entry->d_pino, entry->d_reclen, name);
688			entry = (dirent*)((char*)entry + entry->d_reclen);
689		}
690	#endif
691
692	return error;
693}
694
695// netfs_rewind_dir
696static
697int
698netfs_rewind_dir(void *ns, void *_node, void *cookie)
699{
700	Node* node = (Node*)_node;
701	PRINT("netfs_rewind_dir(%p, %p, %p)\n", ns, node, cookie);
702	status_t error = node->GetVolume()->RewindDir(node, cookie);
703	PRINT("netfs_rewind_dir() done: %lx\n", error);
704	return error;
705}
706
707// netfs_walk
708static
709int
710netfs_walk(void *ns, void *_dir, const char *entryName,
711	char **resolvedPath, vnode_id *vnid)
712{
713	Node* dir = (Node*)_dir;
714	PRINT("netfs_walk(%p, %p, `%s', %p, %p)\n", ns, dir,
715		entryName, resolvedPath, vnid);
716	status_t error = dir->GetVolume()->Walk(dir, entryName, resolvedPath, vnid);
717	PRINT("netfs_walk() done: (%lx, `%s', %Ld)\n", error,
718		(resolvedPath ? *resolvedPath : NULL), *vnid);
719	return error;
720}
721
722// #pragma mark -
723// #pragma mark ----- attributes -----
724
725// netfs_open_attrdir
726static
727int
728netfs_open_attrdir(void *ns, void *_node, void **cookie)
729{
730	Node* node = (Node*)_node;
731	PRINT("netfs_open_attrdir(%p, %p)\n", ns, node);
732	status_t error = node->GetVolume()->OpenAttrDir(node, cookie);
733	PRINT("netfs_open_attrdir() done: (%lx, %p)\n", error, *cookie);
734	return error;
735}
736
737// netfs_close_attrdir
738static
739int
740netfs_close_attrdir(void *ns, void *_node, void *cookie)
741{
742	Node* node = (Node*)_node;
743	PRINT("netfs_close_attrdir(%p, %p, %p)\n", ns, node, cookie);
744	status_t error = node->GetVolume()->CloseAttrDir(node, cookie);
745	PRINT("netfs_close_attrdir() done: (%lx)\n", error);
746	return error;
747}
748
749// netfs_free_attrdir_cookie
750static
751int
752netfs_free_attrdir_cookie(void *ns, void *_node, void *cookie)
753{
754	Node* node = (Node*)_node;
755	PRINT("netfs_free_attrdir_cookie(%p, %p, %p)\n", ns, node, cookie);
756	status_t error = node->GetVolume()->FreeAttrDirCookie(node, cookie);
757	PRINT("netfs_free_attrdir_cookie() done: (%lx)\n", error);
758	return error;
759}
760
761// netfs_read_attrdir
762static
763int
764netfs_read_attrdir(void *ns, void *_node, void *cookie, long *count,
765	struct dirent *buffer, size_t bufferSize)
766{
767	Node* node = (Node*)_node;
768	PRINT("netfs_read_attrdir(%p, %p, %p, %ld, %p, %lu)\n", ns, node,
769		cookie, *count, buffer, bufferSize);
770	status_t error = node->GetVolume()->ReadAttrDir(node, cookie, buffer,
771		bufferSize, *count, count);
772	PRINT("netfs_read_attrdir() done: (%lx, %ld)\n", error, *count);
773	return error;
774}
775
776// netfs_rewind_attrdir
777static
778int
779netfs_rewind_attrdir(void *ns, void *_node, void *cookie)
780{
781	Node* node = (Node*)_node;
782	PRINT("netfs_rewind_attrdir(%p, %p, %p)\n", ns, node, cookie);
783	status_t error = node->GetVolume()->RewindAttrDir(node, cookie);
784	PRINT("netfs_rewind_attrdir() done: (%lx)\n", error);
785	return error;
786}
787
788// netfs_read_attr
789static
790int
791netfs_read_attr(void *ns, void *_node, const char *name, int type,
792	void *buffer, size_t *bufferSize, off_t pos)
793{
794	Node* node = (Node*)_node;
795	PRINT("netfs_read_attr(%p, %p, `%s', %d, %p, %lu, %Ld)\n", ns, node,
796		name, type, buffer, *bufferSize, pos);
797	status_t error = node->GetVolume()->ReadAttr(node, name, type, pos, buffer,
798		*bufferSize, bufferSize);
799	PRINT("netfs_read_attr() done: (%lx, %ld)\n", error, *bufferSize);
800	return error;
801}
802
803// netfs_write_attr
804static
805int
806netfs_write_attr(void *ns, void *_node, const char *name, int type,
807	const void *buffer, size_t *bufferSize, off_t pos)
808{
809	Node* node = (Node*)_node;
810	PRINT("netfs_write_attr(%p, %p, `%s', %d, %p, %lu, %Ld)\n", ns, node,
811		name, type, buffer, *bufferSize, pos);
812	status_t error = node->GetVolume()->WriteAttr(node, name, type, pos, buffer,
813		*bufferSize, bufferSize);
814	PRINT("netfs_write_attr() done: (%lx, %ld)\n", error, *bufferSize);
815	return error;
816}
817
818// netfs_remove_attr
819static
820int
821netfs_remove_attr(void *ns, void *_node, const char *name)
822{
823	Node* node = (Node*)_node;
824	PRINT("netfs_remove_attr(%p, %p, `%s')\n", ns, node, name);
825	status_t error = node->GetVolume()->RemoveAttr(node, name);
826	PRINT("netfs_remove_attr() done: (%lx)\n", error);
827	return error;
828}
829
830// netfs_rename_attr
831static
832int
833netfs_rename_attr(void *ns, void *_node, const char *oldName,
834	const char *newName)
835{
836	Node* node = (Node*)_node;
837	PRINT("netfs_rename_attr(%p, %p, `%s', `%s')\n", ns, node, oldName,
838		newName);
839	status_t error = node->GetVolume()->RenameAttr(node, oldName, newName);
840	PRINT("netfs_rename_attr() done: (%lx)\n", error);
841	return error;
842}
843
844// netfs_stat_attr
845static
846int
847netfs_stat_attr(void *ns, void *_node, const char *name,
848	struct attr_info *attrInfo)
849{
850	Node* node = (Node*)_node;
851	PRINT("netfs_stat_attr(%p, %p, `%s', %p)\n", ns, node, name,
852		attrInfo);
853	status_t error = node->GetVolume()->StatAttr(node, name, attrInfo);
854	PRINT("netfs_stat_attr() done: (%lx)\n", error);
855	return error;
856}
857
858// #pragma mark -
859// #pragma mark ----- queries -----
860
861// netfs_open_query
862static
863int
864netfs_open_query(void *ns, const char *queryString, ulong flags,
865	port_id port, long token, void **cookie)
866{
867	VolumeManager* volumeManager = (VolumeManager*)ns;
868	Volume* volume = volumeManager->GetRootVolume();
869	VolumePutter _(volume);
870
871	PRINT("netfs_open_query(%p, `%s', %lu, %ld, %ld, %p)\n", ns,
872		queryString, flags, port, token, cookie);
873
874	status_t error = B_BAD_VALUE;
875	if (volume) {
876		error = volume->OpenQuery(queryString, flags, port, token,
877			(QueryIterator**)cookie);
878	}
879
880	PRINT("netfs_open_query() done: (%lx, %p)\n", error, *cookie);
881	return error;
882}
883
884// netfs_close_query
885static
886int
887netfs_close_query(void *ns, void *cookie)
888{
889	PRINT("netfs_close_query(%p, %p)\n", ns, cookie);
890
891	status_t error = B_OK;
892	// no-op: we don't use this hook
893
894	PRINT("netfs_close_query() done: (%lx)\n", error);
895	return error;
896}
897
898// netfs_free_query_cookie
899static
900int
901netfs_free_query_cookie(void *ns, void *node, void *cookie)
902{
903	VolumeManager* volumeManager = (VolumeManager*)ns;
904	QueryIterator* iterator = (QueryIterator*)cookie;
905
906	PRINT("netfs_free_query_cookie(%p, %p)\n", ns, cookie);
907
908	status_t error = B_OK;
909	volumeManager->GetQueryManager()->PutIterator(iterator);
910
911	PRINT("netfs_free_query_cookie() done: (%lx)\n", error);
912	return error;
913}
914
915// netfs_read_query
916static
917int
918netfs_read_query(void *ns, void *cookie, long *count,
919	struct dirent *buffer, size_t bufferSize)
920{
921	VolumeManager* volumeManager = (VolumeManager*)ns;
922	Volume* volume = volumeManager->GetRootVolume();
923	QueryIterator* iterator = (QueryIterator*)cookie;
924	VolumePutter _(volume);
925
926	PRINT("netfs_read_query(%p, %p, %ld, %p, %lu)\n", ns, cookie,
927		*count, buffer, bufferSize);
928
929	status_t error = B_BAD_VALUE;
930	if (volume) {
931		error = volume->ReadQuery(iterator, buffer, bufferSize,
932		*count, count);
933	}
934
935	PRINT("netfs_read_query() done: (%lx, %ld)\n", error, *count);
936	return error;
937}
938
939