1/*
2 * Copyright 2001-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6#include "kernel_interface.h"
7
8#include <dirent.h>
9
10#include <KernelExport.h>
11#include <fs_interface.h>
12
13#include "Debug.h"
14#include "FileSystem.h"
15#include "String.h"
16#include "UserlandFS.h"
17#include "Volume.h"
18
19
20// #pragma mark - general
21
22
23// parse_parameters
24static status_t
25parse_parameters(const char *parameters, String &fsName,
26	const char **fsParameters)
27{
28	// check parameters
29	if (!parameters)
30		return B_BAD_VALUE;
31
32	int32 len = strlen(parameters);
33
34	// skip leading white space
35	for (; len > 0; parameters++, len--) {
36		if (*parameters != ' ' && *parameters != '\t' && *parameters != '\n')
37			break;
38	}
39	if (len == 0)
40		return B_BAD_VALUE;
41
42	// get the file system name
43	int32 fsNameLen = len;
44	for (int32 i = 0; i < len; i++) {
45		if (parameters[i] == ' ' || parameters[i] == '\t'
46			|| parameters[i] == '\n') {
47			fsNameLen = i;
48			break;
49		}
50	}
51
52	fsName.SetTo(parameters, fsNameLen);
53	if (fsName.GetLength() == 0) {
54		exit_debugging();
55		return B_NO_MEMORY;
56	}
57	parameters += fsNameLen;
58	len -= fsNameLen;
59
60	// skip leading white space of the FS parameters
61	for (; len > 0; parameters++, len--) {
62		if (*parameters != ' ' && *parameters != '\t' && *parameters != '\n')
63			break;
64	}
65	*fsParameters = parameters;
66
67	return B_OK;
68}
69
70// userlandfs_mount
71static status_t
72userlandfs_mount(fs_volume* fsVolume, const char* device, uint32 flags,
73	const char* args, ino_t* rootVnodeID)
74{
75	PRINT(("userlandfs_mount(%p (%ld), %s, 0x%lx, %s, %p)\n", fsVolume,
76		fsVolume->id, device, flags, args, rootVnodeID));
77
78	status_t error = B_OK;
79
80	// get the parameters
81// TODO: The parameters are in driver settings format now.
82	String fsName;
83	const char* fsParameters;
84	error = parse_parameters(args, fsName, &fsParameters);
85	if (error != B_OK)
86		RETURN_ERROR(error);
87
88	// get the UserlandFS object
89	UserlandFS* userlandFS = UserlandFS::GetUserlandFS();
90	if (!userlandFS)
91		RETURN_ERROR(B_ERROR);
92
93	// get the file system
94	FileSystem* fileSystem = NULL;
95	error = userlandFS->RegisterFileSystem(fsName.GetString(), &fileSystem);
96	if (error != B_OK)
97		RETURN_ERROR(error);
98
99	// mount the volume
100	Volume* volume = NULL;
101	error = fileSystem->Mount(fsVolume, device, flags, fsParameters, &volume);
102	if (error != B_OK) {
103		userlandFS->UnregisterFileSystem(fileSystem);
104		RETURN_ERROR(error);
105	}
106
107	fsVolume->private_volume = volume;
108	fsVolume->ops = volume->GetVolumeOps();
109	*rootVnodeID = volume->GetRootID();
110
111	PRINT(("userlandfs_mount() done: %p, %lld\n", fsVolume->private_volume,
112		*rootVnodeID));
113
114	return error;
115}
116
117// userlandfs_unmount
118static status_t
119userlandfs_unmount(fs_volume* fsVolume)
120{
121	Volume* volume = (Volume*)fsVolume->private_volume;
122	PRINT(("userlandfs_unmount(%p)\n", volume));
123
124	FileSystem* fileSystem = volume->GetFileSystem();
125	status_t error = volume->Unmount();
126	// The error code the FS's unmount hook returns is completely irrelevant to
127	// the VFS. It considers the volume unmounted in any case.
128	volume->ReleaseReference();
129	UserlandFS::GetUserlandFS()->UnregisterFileSystem(fileSystem);
130
131	PRINT(("userlandfs_unmount() done: %lx\n", error));
132	return error;
133}
134
135// userlandfs_sync
136static status_t
137userlandfs_sync(fs_volume* fsVolume)
138{
139	Volume* volume = (Volume*)fsVolume->private_volume;
140	PRINT(("userlandfs_sync(%p)\n", volume));
141	status_t error = volume->Sync();
142	PRINT(("userlandfs_sync() done: %lx \n", error));
143	return error;
144}
145
146// userlandfs_read_fs_info
147static status_t
148userlandfs_read_fs_info(fs_volume* fsVolume, struct fs_info* info)
149{
150	Volume* volume = (Volume*)fsVolume->private_volume;
151	PRINT(("userlandfs_read_fs_info(%p, %p)\n", volume, info));
152	status_t error = volume->ReadFSInfo(info);
153	PRINT(("userlandfs_read_fs_info() done: %lx \n", error));
154	return error;
155}
156
157// userlandfs_write_fs_info
158static status_t
159userlandfs_write_fs_info(fs_volume* fsVolume, const struct fs_info* info,
160	uint32 mask)
161{
162	Volume* volume = (Volume*)fsVolume->private_volume;
163	PRINT(("userlandfs_write_fs_info(%p, %p, 0x%lx)\n", volume, info, mask));
164	status_t error = volume->WriteFSInfo(info, mask);
165	PRINT(("userlandfs_write_fs_info() done: %lx \n", error));
166	return error;
167}
168
169
170// #pragma mark - vnodes
171
172
173// userlandfs_lookup
174static status_t
175userlandfs_lookup(fs_volume* fsVolume, fs_vnode* fsDir, const char* entryName,
176	ino_t* vnid)
177{
178	Volume* volume = (Volume*)fsVolume->private_volume;
179	PRINT(("userlandfs_lookup(%p, %p, `%s', %p)\n", volume, fsDir->private_node,
180		entryName, vnid));
181	status_t error = volume->Lookup(fsDir->private_node, entryName, vnid);
182	PRINT(("userlandfs_lookup() done: (%lx, %lld)\n", error, *vnid));
183	return error;
184}
185
186// userlandfs_get_vnode_name
187static status_t
188userlandfs_get_vnode_name(fs_volume* fsVolume, fs_vnode* fsNode, char* buffer,
189	size_t bufferSize)
190{
191	Volume* volume = (Volume*)fsVolume->private_volume;
192	PRINT(("userlandfs_get_vnode_name(%p, %p, %p, %lu)\n", volume,
193		fsNode->private_node, buffer, bufferSize));
194	status_t error = volume->GetVNodeName(fsNode->private_node, buffer,
195		bufferSize);
196	PRINT(("userlandfs_get_vnode_name() done: (%lx, \"%.*s\")\n", error,
197		(int)bufferSize, (error == B_OK ? buffer : NULL)));
198	return error;
199}
200
201// userlandfs_get_vnode
202static status_t
203userlandfs_get_vnode(fs_volume* fsVolume, ino_t vnid, fs_vnode* fsNode,
204	int* _type, uint32* _flags, bool reenter)
205{
206	Volume* volume = (Volume*)fsVolume->private_volume;
207	PRINT(("userlandfs_get_vnode(%p, %lld, %p, %d)\n", volume, vnid,
208		fsNode->private_node, reenter));
209	void* node;
210	fs_vnode_ops* ops;
211	status_t error = volume->ReadVNode(vnid, reenter, &node, &ops, _type,
212		_flags);
213	if (error == B_OK) {
214		fsNode->private_node = node;
215		fsNode->ops = ops;
216	}
217
218	PRINT(("userlandfs_get_vnode() done: (%lx, %p, %#x, %#lx)\n", error, node,
219		*_type, *_flags));
220	return error;
221}
222
223// userlandfs_put_vnode
224static status_t
225userlandfs_put_vnode(fs_volume* fsVolume, fs_vnode* fsNode, bool reenter)
226{
227	Volume* volume = (Volume*)fsVolume->private_volume;
228// DANGER: If dbg_printf() is used, this thread will enter another FS and
229// even perform a write operation. The is dangerous here, since this hook
230// may be called out of the other FSs, since, for instance a put_vnode()
231// called from another FS may cause the VFS layer to free vnodes and thus
232// invoke this hook.
233//	PRINT(("userlandfs_put_vnode(%p, %p, %d)\n", volume, fsNode->private_node,
234//		reenter));
235	status_t error = volume->WriteVNode(fsNode->private_node, reenter);
236//	PRINT(("userlandfs_put_vnode() done: %lx\n", error));
237	return error;
238}
239
240// userlandfs_remove_vnode
241static status_t
242userlandfs_remove_vnode(fs_volume* fsVolume, fs_vnode* fsNode, bool reenter)
243{
244	Volume* volume = (Volume*)fsVolume->private_volume;
245// DANGER: See userlandfs_write_vnode().
246//	PRINT(("userlandfs_remove_vnode(%p, %p, %d)\n", volume,
247//		fsNode->private_node, reenter));
248	status_t error = volume->RemoveVNode(fsNode->private_node, reenter);
249//	PRINT(("userlandfs_remove_vnode() done: %lx\n", error));
250	return error;
251}
252
253
254// #pragma mark - asynchronous I/O
255
256
257// userlandfs_io
258status_t
259userlandfs_io(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie,
260	io_request* request)
261{
262	Volume* volume = (Volume*)fsVolume->private_volume;
263	PRINT(("userlandfs_io(%p, %p, %p, %p)\n", volume, fsNode->private_node,
264		cookie, request));
265	status_t error = volume->DoIO(fsNode->private_node, cookie, request);
266	PRINT(("userlandfs_io() done: (%lx)\n", error));
267	return error;
268}
269
270
271// userlandfs_cancel_io
272status_t
273userlandfs_cancel_io(fs_volume* fsVolume, fs_vnode* fsNode, void *cookie,
274	io_request *request)
275{
276	Volume* volume = (Volume*)fsVolume->private_volume;
277	PRINT(("userlandfs_cancel_io(%p, %p, %p, %p)\n", volume,
278		fsNode->private_node, cookie, request));
279	status_t error = volume->CancelIO(fsNode->private_node, cookie, request);
280	PRINT(("userlandfs_cancel_io() done: (%lx)\n", error));
281	return error;
282}
283
284
285// #pragma mark - common
286
287
288// userlandfs_ioctl
289static status_t
290userlandfs_ioctl(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie, uint32 op,
291	void* buffer, size_t length)
292{
293	Volume* volume = (Volume*)fsVolume->private_volume;
294	PRINT(("userlandfs_ioctl(%p, %p, %p, %lu, %p, %lu)\n", volume,
295		fsNode->private_node, cookie, op, buffer, length));
296	status_t error = volume->IOCtl(fsNode->private_node, cookie, op, buffer,
297		length);
298	PRINT(("userlandfs_ioctl() done: (%lx)\n", error));
299	return error;
300}
301
302// userlandfs_set_flags
303static status_t
304userlandfs_set_flags(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie,
305	int flags)
306{
307	Volume* volume = (Volume*)fsVolume->private_volume;
308	PRINT(("userlandfs_set_flags(%p, %p, %p, %d)\n", volume,
309		fsNode->private_node, cookie, flags));
310	status_t error = volume->SetFlags(fsNode->private_node, cookie, flags);
311	PRINT(("userlandfs_set_flags() done: (%lx)\n", error));
312	return error;
313}
314
315// userlandfs_select
316static status_t
317userlandfs_select(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie,
318	uint8 event, selectsync* sync)
319{
320	Volume* volume = (Volume*)fsVolume->private_volume;
321	PRINT(("userlandfs_select(%p, %p, %p, %hhd, %p)\n", volume,
322		fsNode->private_node, cookie, event, sync));
323	status_t error = volume->Select(fsNode->private_node, cookie, event, sync);
324	PRINT(("userlandfs_select() done: (%lx)\n", error));
325	return error;
326}
327
328// userlandfs_deselect
329static status_t
330userlandfs_deselect(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie,
331	uint8 event, selectsync* sync)
332{
333	Volume* volume = (Volume*)fsVolume->private_volume;
334	PRINT(("userlandfs_deselect(%p, %p, %p, %hhd, %p)\n", volume,
335		fsNode->private_node, cookie, event, sync));
336	status_t error = volume->Deselect(fsNode->private_node, cookie, event,
337		sync);
338	PRINT(("userlandfs_deselect() done: (%lx)\n", error));
339	return error;
340}
341
342// userlandfs_fsync
343static status_t
344userlandfs_fsync(fs_volume* fsVolume, fs_vnode* fsNode)
345{
346	Volume* volume = (Volume*)fsVolume->private_volume;
347	PRINT(("userlandfs_fsync(%p, %p)\n", volume, fsNode->private_node));
348	status_t error = volume->FSync(fsNode->private_node);
349	PRINT(("userlandfs_fsync() done: %lx\n", error));
350	return error;
351}
352
353// userlandfs_read_symlink
354static status_t
355userlandfs_read_symlink(fs_volume* fsVolume, fs_vnode* fsLink, char* buffer,
356	size_t* bufferSize)
357{
358	Volume* volume = (Volume*)fsVolume->private_volume;
359	PRINT(("userlandfs_read_symlink(%p, %p, %p, %lu)\n", volume,
360		fsLink->private_node, buffer, *bufferSize));
361	status_t error = volume->ReadSymlink(fsLink->private_node, buffer,
362		*bufferSize, bufferSize);
363	PRINT(("userlandfs_read_symlink() done: (%lx, %lu)\n", error, *bufferSize));
364	return error;
365}
366
367// userlandfs_create_symlink
368static status_t
369userlandfs_create_symlink(fs_volume* fsVolume, fs_vnode* fsDir,
370	const char* name, const char* path, int mode)
371{
372	Volume* volume = (Volume*)fsVolume->private_volume;
373	PRINT(("userlandfs_create_symlink(%p, %p, `%s', `%s', %d)\n", volume,
374		fsDir->private_node, name, path, mode));
375	status_t error = volume->CreateSymlink(fsDir->private_node, name, path,
376		mode);
377	PRINT(("userlandfs_create_symlink() done: (%lx)\n", error));
378	return error;
379}
380
381// userlandfs_link
382static status_t
383userlandfs_link(fs_volume* fsVolume, fs_vnode* fsDir, const char* name,
384	fs_vnode* fsNode)
385{
386	Volume* volume = (Volume*)fsVolume->private_volume;
387	PRINT(("userlandfs_link(%p, %p, `%s', %p)\n", volume,
388		fsDir->private_node, name, fsNode->private_node));
389	status_t error = volume->Link(fsDir->private_node, name,
390		fsNode->private_node);
391	PRINT(("userlandfs_link() done: (%lx)\n", error));
392	return error;
393}
394
395// userlandfs_unlink
396static status_t
397userlandfs_unlink(fs_volume* fsVolume, fs_vnode* fsDir, const char* name)
398{
399	Volume* volume = (Volume*)fsVolume->private_volume;
400	PRINT(("userlandfs_unlink(%p, %p, `%s')\n", volume, fsDir->private_node,
401		name));
402	status_t error = volume->Unlink(fsDir->private_node, name);
403	PRINT(("userlandfs_unlink() done: (%lx)\n", error));
404	return error;
405}
406
407// userlandfs_rename
408static status_t
409userlandfs_rename(fs_volume* fsVolume, fs_vnode* fsFromDir,
410	const char *fromName, fs_vnode* fsToDir, const char *toName)
411{
412	Volume* volume = (Volume*)fsVolume->private_volume;
413	PRINT(("userlandfs_rename(%p, %p, `%s', %p, `%s')\n", volume,
414		fsFromDir->private_node, fromName, fsToDir->private_node, toName));
415	status_t error = volume->Rename(fsFromDir->private_node, fromName,
416		fsToDir->private_node, toName);
417	PRINT(("userlandfs_rename() done: (%lx)\n", error));
418	return error;
419}
420
421// userlandfs_access
422static status_t
423userlandfs_access(fs_volume* fsVolume, fs_vnode* fsNode, int mode)
424{
425	Volume* volume = (Volume*)fsVolume->private_volume;
426	PRINT(("userlandfs_access(%p, %p, %d)\n", volume, fsNode->private_node,
427		mode));
428	status_t error = volume->Access(fsNode->private_node, mode);
429	PRINT(("userlandfs_access() done: %lx\n", error));
430	return error;
431}
432
433// userlandfs_read_stat
434static status_t
435userlandfs_read_stat(fs_volume* fsVolume, fs_vnode* fsNode, struct stat* st)
436{
437	Volume* volume = (Volume*)fsVolume->private_volume;
438	PRINT(("userlandfs_read_stat(%p, %p, %p)\n", volume, fsNode->private_node,
439		st));
440	status_t error = volume->ReadStat(fsNode->private_node, st);
441	PRINT(("userlandfs_read_stat() done: %lx\n", error));
442	return error;
443}
444
445// userlandfs_write_stat
446static status_t
447userlandfs_write_stat(fs_volume* fsVolume, fs_vnode* fsNode,
448	const struct stat* st, uint32 mask)
449{
450	Volume* volume = (Volume*)fsVolume->private_volume;
451	PRINT(("userlandfs_write_stat(%p, %p, %p, %ld)\n", volume,
452		fsNode->private_node, st, mask));
453	status_t error = volume->WriteStat(fsNode->private_node, st, mask);
454	PRINT(("userlandfs_write_stat() done: %lx\n", error));
455	return error;
456}
457
458
459// #pragma mark - files
460
461
462// userlandfs_create
463static status_t
464userlandfs_create(fs_volume* fsVolume, fs_vnode* fsDir, const char* name,
465	int openMode, int perms, void** cookie, ino_t* vnid)
466{
467	Volume* volume = (Volume*)fsVolume->private_volume;
468	PRINT(("userlandfs_create(%p, %p, `%s', %d, %d, %p, %p)\n", volume,
469		fsDir->private_node, name, openMode, perms, cookie, vnid));
470	status_t error = volume->Create(fsDir->private_node, name, openMode, perms,
471		cookie, vnid);
472	PRINT(("userlandfs_create() done: (%lx, %lld, %p)\n", error, *vnid,
473		*cookie));
474	return error;
475}
476
477// userlandfs_open
478static status_t
479userlandfs_open(fs_volume* fsVolume, fs_vnode* fsNode, int openMode,
480	void** cookie)
481{
482	Volume* volume = (Volume*)fsVolume->private_volume;
483	PRINT(("userlandfs_open(%p, %p, %d)\n", volume, fsNode->private_node,
484		openMode));
485	status_t error = volume->Open(fsNode->private_node, openMode, cookie);
486	PRINT(("userlandfs_open() done: (%lx, %p)\n", error, *cookie));
487	return error;
488}
489
490// userlandfs_close
491static status_t
492userlandfs_close(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie)
493{
494	Volume* volume = (Volume*)fsVolume->private_volume;
495	PRINT(("userlandfs_close(%p, %p, %p)\n", volume, fsNode->private_node,
496		cookie));
497	status_t error = volume->Close(fsNode->private_node, cookie);
498	PRINT(("userlandfs_close() done: %lx\n", error));
499	return error;
500}
501
502// userlandfs_free_cookie
503static status_t
504userlandfs_free_cookie(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie)
505{
506	Volume* volume = (Volume*)fsVolume->private_volume;
507	PRINT(("userlandfs_free_cookie(%p, %p, %p)\n", volume, fsNode->private_node,
508		cookie));
509	status_t error = volume->FreeCookie(fsNode->private_node, cookie);
510	PRINT(("userlandfs_free_cookie() done: %lx\n", error));
511	return error;
512}
513
514// userlandfs_read
515static status_t
516userlandfs_read(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie, off_t pos,
517	void* buffer, size_t* length)
518{
519	Volume* volume = (Volume*)fsVolume->private_volume;
520	PRINT(("userlandfs_read(%p, %p, %p, %Ld, %p, %lu)\n", volume,
521		fsNode->private_node, cookie, pos, buffer, *length));
522	status_t error = volume->Read(fsNode->private_node, cookie, pos, buffer,
523		*length, length);
524	PRINT(("userlandfs_read() done: (%lx, %lu)\n", error, *length));
525	return error;
526}
527
528// userlandfs_write
529static status_t
530userlandfs_write(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie, off_t pos,
531	const void* buffer, size_t* length)
532{
533	Volume* volume = (Volume*)fsVolume->private_volume;
534	PRINT(("userlandfs_write(%p, %p, %p, %Ld, %p, %lu)\n", volume,
535		fsNode->private_node, cookie, pos, buffer, *length));
536	status_t error = volume->Write(fsNode->private_node, cookie, pos, buffer,
537		*length, length);
538	PRINT(("userlandfs_write() done: (%lx, %lu)\n", error, *length));
539	return error;
540}
541
542
543// #pragma mark - directories
544
545
546// userlandfs_create_dir
547static status_t
548userlandfs_create_dir(fs_volume* fsVolume, fs_vnode* fsParent, const char* name,
549	int perms)
550{
551	Volume* volume = (Volume*)fsVolume->private_volume;
552	PRINT(("userlandfs_create_dir(%p, %p, `%s', %#x)\n", volume,
553		fsParent->private_node, name, perms));
554	status_t error = volume->CreateDir(fsParent->private_node, name, perms);
555	PRINT(("userlandfs_create_dir() done: (%lx)\n", error));
556	return error;
557}
558
559// userlandfs_remove_dir
560static status_t
561userlandfs_remove_dir(fs_volume* fsVolume, fs_vnode* fsParent, const char* name)
562{
563	Volume* volume = (Volume*)fsVolume->private_volume;
564	PRINT(("userlandfs_remove_dir(%p, %p, `%s')\n", volume,
565		fsParent->private_node, name));
566	status_t error = volume->RemoveDir(fsParent->private_node, name);
567	PRINT(("userlandfs_remove_dir() done: (%lx)\n", error));
568	return error;
569}
570
571// userlandfs_open_dir
572static status_t
573userlandfs_open_dir(fs_volume* fsVolume, fs_vnode* fsNode, void** cookie)
574{
575	Volume* volume = (Volume*)fsVolume->private_volume;
576	PRINT(("userlandfs_open_dir(%p, %p)\n", volume, fsNode->private_node));
577	status_t error = volume->OpenDir(fsNode->private_node, cookie);
578	PRINT(("userlandfs_open_dir() done: (%lx, %p)\n", error, *cookie));
579	return error;
580}
581
582// userlandfs_close_dir
583static status_t
584userlandfs_close_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie)
585{
586	Volume* volume = (Volume*)fsVolume->private_volume;
587	PRINT(("userlandfs_close_dir(%p, %p, %p)\n", volume, fsNode->private_node,
588		cookie));
589	status_t error = volume->CloseDir(fsNode->private_node, cookie);
590	PRINT(("userlandfs_close_dir() done: %lx\n", error));
591	return error;
592}
593
594// userlandfs_free_dir_cookie
595static status_t
596userlandfs_free_dir_cookie(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie)
597{
598	Volume* volume = (Volume*)fsVolume->private_volume;
599	PRINT(("userlandfs_free_dir_cookie(%p, %p, %p)\n", volume,
600		fsNode->private_node, cookie));
601	status_t error = volume->FreeDirCookie(fsNode->private_node, cookie);
602	PRINT(("userlandfs_free_dir_cookie() done: %lx \n", error));
603	return error;
604}
605
606// userlandfs_read_dir
607static status_t
608userlandfs_read_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie,
609	struct dirent* buffer, size_t bufferSize, uint32* count)
610{
611	Volume* volume = (Volume*)fsVolume->private_volume;
612	PRINT(("userlandfs_read_dir(%p, %p, %p, %p, %lu, %lu)\n", volume,
613		fsNode->private_node, cookie, buffer, bufferSize, *count));
614	status_t error = volume->ReadDir(fsNode->private_node, cookie, buffer,
615		bufferSize, *count, count);
616	PRINT(("userlandfs_read_dir() done: (%lx, %lu)\n", error, *count));
617	#if DEBUG
618		dirent* entry = buffer;
619		for (uint32 i = 0; error == B_OK && i < *count; i++) {
620			// R5's kernel vsprintf() doesn't seem to know `%.<number>s', so
621			// we need to work around.
622			char name[B_FILE_NAME_LENGTH];
623			int nameLen = strnlen(entry->d_name, B_FILE_NAME_LENGTH - 1);
624			strncpy(name, entry->d_name, nameLen);
625			name[nameLen] = '\0';
626			PRINT(("  entry: d_dev: %ld, d_pdev: %ld, d_ino: %Ld, d_pino: %Ld, "
627				"d_reclen: %hu, d_name: `%s'\n",
628				entry->d_dev, entry->d_pdev, entry->d_ino, entry->d_pino,
629				entry->d_reclen, name));
630			entry = (dirent*)((char*)entry + entry->d_reclen);
631		}
632	#endif
633	return error;
634}
635
636// userlandfs_rewind_dir
637static status_t
638userlandfs_rewind_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie)
639{
640	Volume* volume = (Volume*)fsVolume->private_volume;
641	PRINT(("userlandfs_rewind_dir(%p, %p, %p)\n", volume, fsNode->private_node,
642		cookie));
643	status_t error = volume->RewindDir(fsNode->private_node, cookie);
644	PRINT(("userlandfs_rewind_dir() done: %lx\n", error));
645	return error;
646}
647
648
649// #pragma mark - attribute directories
650
651
652// userlandfs_open_attr_dir
653static status_t
654userlandfs_open_attr_dir(fs_volume* fsVolume, fs_vnode* fsNode, void** cookie)
655{
656	Volume* volume = (Volume*)fsVolume->private_volume;
657	PRINT(("userlandfs_open_attr_dir(%p, %p)\n", volume, fsNode->private_node));
658	status_t error = volume->OpenAttrDir(fsNode->private_node, cookie);
659	PRINT(("userlandfs_open_attr_dir() done: (%lx, %p)\n", error, *cookie));
660	return error;
661}
662
663// userlandfs_close_attr_dir
664static status_t
665userlandfs_close_attr_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie)
666{
667	Volume* volume = (Volume*)fsVolume->private_volume;
668	PRINT(("userlandfs_close_attr_dir(%p, %p, %p)\n", volume,
669		fsNode->private_node, cookie));
670	status_t error = volume->CloseAttrDir(fsNode->private_node, cookie);
671	PRINT(("userlandfs_close_attr_dir() done: (%lx)\n", error));
672	return error;
673}
674
675// userlandfs_free_attr_dir_cookie
676static status_t
677userlandfs_free_attr_dir_cookie(fs_volume* fsVolume, fs_vnode* fsNode,
678	void* cookie)
679{
680	Volume* volume = (Volume*)fsVolume->private_volume;
681	PRINT(("userlandfs_free_attr_dir_cookie(%p, %p, %p)\n", volume,
682		fsNode->private_node, cookie));
683	status_t error = volume->FreeAttrDirCookie(fsNode->private_node, cookie);
684	PRINT(("userlandfs_free_attr_dir_cookie() done: (%lx)\n", error));
685	return error;
686}
687
688// userlandfs_read_attr_dir
689static status_t
690userlandfs_read_attr_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie,
691	struct dirent* buffer, size_t bufferSize, uint32* count)
692{
693	Volume* volume = (Volume*)fsVolume->private_volume;
694	PRINT(("userlandfs_read_attr_dir(%p, %p, %p, %p, %lu, %lu)\n", volume,
695		fsNode->private_node, cookie, buffer, bufferSize, *count));
696	status_t error = volume->ReadAttrDir(fsNode->private_node, cookie, buffer,
697		bufferSize, *count, count);
698	PRINT(("userlandfs_read_attr_dir() done: (%lx, %lu)\n", error, *count));
699	return error;
700}
701
702// userlandfs_rewind_attr_dir
703static status_t
704userlandfs_rewind_attr_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie)
705{
706	Volume* volume = (Volume*)fsVolume->private_volume;
707	PRINT(("userlandfs_rewind_attr_dir(%p, %p, %p)\n", volume,
708		fsNode->private_node, cookie));
709	status_t error = volume->RewindAttrDir(fsNode->private_node, cookie);
710	PRINT(("userlandfs_rewind_attr_dir() done: (%lx)\n", error));
711	return error;
712}
713
714
715// #pragma mark - attributes
716
717
718// userlandfs_create_attr
719status_t
720userlandfs_create_attr(fs_volume* fsVolume, fs_vnode* fsNode, const char* name,
721	uint32 type, int openMode, void** cookie)
722{
723	Volume* volume = (Volume*)fsVolume->private_volume;
724	PRINT(("userlandfs_create_attr(%p, %p, \"%s\", 0x%lx, %d, %p)\n", volume,
725		fsNode->private_node, name, type, openMode, cookie));
726	status_t error = volume->CreateAttr(fsNode->private_node, name, type,
727		openMode, cookie);
728	PRINT(("userlandfs_create_attr() done: (%lx, %p)\n", error, *cookie));
729	return error;
730}
731
732// userlandfs_open_attr
733status_t
734userlandfs_open_attr(fs_volume* fsVolume, fs_vnode* fsNode, const char* name,
735	int openMode, void** cookie)
736{
737	Volume* volume = (Volume*)fsVolume->private_volume;
738	PRINT(("userlandfs_open_attr(%p, %p, \"%s\", %d, %p)\n", volume,
739		fsNode->private_node, name, openMode, cookie));
740	status_t error = volume->OpenAttr(fsNode->private_node, name, openMode,
741		cookie);
742	PRINT(("userlandfs_open_attr() done: (%lx, %p)\n", error, *cookie));
743	return error;
744}
745
746// userlandfs_close_attr
747status_t
748userlandfs_close_attr(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie)
749{
750	Volume* volume = (Volume*)fsVolume->private_volume;
751	PRINT(("userlandfs_close_attr(%p, %p, %p)\n", volume, fsNode->private_node,
752		cookie));
753	status_t error = volume->CloseAttr(fsNode->private_node, cookie);
754	PRINT(("userlandfs_close_attr() done: %lx\n", error));
755	return error;
756}
757
758// userlandfs_free_attr_cookie
759status_t
760userlandfs_free_attr_cookie(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie)
761{
762	Volume* volume = (Volume*)fsVolume->private_volume;
763	PRINT(("userlandfs_free_attr_cookie(%p, %p, %p)\n", volume,
764		fsNode->private_node, cookie));
765	status_t error = volume->FreeAttrCookie(fsNode->private_node, cookie);
766	PRINT(("userlandfs_free_attr_cookie() done: %lx\n", error));
767	return error;
768}
769
770// userlandfs_read_attr
771static status_t
772userlandfs_read_attr(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie,
773	off_t pos, void* buffer, size_t* length)
774{
775	Volume* volume = (Volume*)fsVolume->private_volume;
776	PRINT(("userlandfs_read_attr(%p, %p, %p, %lld, %p, %lu)\n", volume,
777		fsNode->private_node, cookie, pos, buffer, *length));
778	status_t error = volume->ReadAttr(fsNode->private_node, cookie, pos, buffer,
779		*length, length);
780	PRINT(("userlandfs_read_attr() done: (%lx, %lu)\n", error, *length));
781	return error;
782}
783
784// userlandfs_write_attr
785static status_t
786userlandfs_write_attr(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie,
787	off_t pos, const void* buffer, size_t* length)
788{
789	Volume* volume = (Volume*)fsVolume->private_volume;
790	PRINT(("userlandfs_write_attr(%p, %p, %p, %lld, %p, %lu)\n", volume,
791		fsNode->private_node, cookie, pos, buffer, *length));
792	status_t error = volume->WriteAttr(fsNode->private_node, cookie, pos,
793		buffer, *length, length);
794	PRINT(("userlandfs_write_attr() done: (%lx, %lu)\n", error, *length));
795	return error;
796}
797
798// userlandfs_read_attr_stat
799static status_t
800userlandfs_read_attr_stat(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie,
801	struct stat* st)
802{
803	Volume* volume = (Volume*)fsVolume->private_volume;
804	PRINT(("userlandfs_read_attr_stat(%p, %p, %p, %p)\n", volume,
805		fsNode->private_node, cookie, st));
806	status_t error = volume->ReadAttrStat(fsNode->private_node, cookie, st);
807	PRINT(("userlandfs_read_attr_stat() done: (%lx)\n", error));
808	return error;
809}
810
811// userlandfs_write_attr_stat
812static status_t
813userlandfs_write_attr_stat(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie,
814	const struct stat* st, int statMask)
815{
816	Volume* volume = (Volume*)fsVolume->private_volume;
817	PRINT(("userlandfs_write_attr_stat(%p, %p, %p, %p, 0x%x)\n", volume,
818		fsNode->private_node, cookie, st, statMask));
819	status_t error = volume->WriteAttrStat(fsNode->private_node, cookie, st,
820		statMask);
821	PRINT(("userlandfs_write_attr_stat() done: (%lx)\n", error));
822	return error;
823}
824
825// userlandfs_rename_attr
826static status_t
827userlandfs_rename_attr(fs_volume* fsVolume, fs_vnode* fsFromNode,
828	const char* fromName, fs_vnode* fsToNode, const char* toName)
829{
830	Volume* volume = (Volume*)fsVolume->private_volume;
831	PRINT(("userlandfs_rename_attr(%p, %p, `%s', %p, `%s')\n", volume,
832		fsFromNode->private_node, fromName, fsToNode->private_node, toName));
833	status_t error = volume->RenameAttr(fsFromNode->private_node, fromName,
834		fsToNode->private_node, toName);
835	PRINT(("userlandfs_rename_attr() done: (%lx)\n", error));
836	return error;
837}
838
839// userlandfs_remove_attr
840static status_t
841userlandfs_remove_attr(fs_volume* fsVolume, fs_vnode* fsNode, const char* name)
842{
843	Volume* volume = (Volume*)fsVolume->private_volume;
844	PRINT(("userlandfs_remove_attr(%p, %p, `%s')\n", volume,
845		fsNode->private_node, name));
846	status_t error = volume->RemoveAttr(fsNode->private_node, name);
847	PRINT(("userlandfs_remove_attr() done: (%lx)\n", error));
848	return error;
849}
850
851
852// #pragma mark - indices
853
854
855// userlandfs_open_index_dir
856static status_t
857userlandfs_open_index_dir(fs_volume* fsVolume, void** cookie)
858{
859	Volume* volume = (Volume*)fsVolume->private_volume;
860	PRINT(("userlandfs_open_index_dir(%p, %p)\n", volume, cookie));
861	status_t error = volume->OpenIndexDir(cookie);
862	PRINT(("userlandfs_open_index_dir() done: (%lx, %p)\n", error, *cookie));
863	return error;
864}
865
866// userlandfs_close_index_dir
867static status_t
868userlandfs_close_index_dir(fs_volume* fsVolume, void* cookie)
869{
870	Volume* volume = (Volume*)fsVolume->private_volume;
871	PRINT(("userlandfs_close_index_dir(%p, %p)\n", volume, cookie));
872	status_t error = volume->CloseIndexDir(cookie);
873	PRINT(("userlandfs_close_index_dir() done: (%lx)\n", error));
874	return error;
875}
876
877// userlandfs_free_index_dir_cookie
878static status_t
879userlandfs_free_index_dir_cookie(fs_volume* fsVolume, void* cookie)
880{
881	Volume* volume = (Volume*)fsVolume->private_volume;
882	PRINT(("userlandfs_free_index_dir_cookie(%p, %p)\n", volume, cookie));
883	status_t error = volume->FreeIndexDirCookie(cookie);
884	PRINT(("userlandfs_free_index_dir_cookie() done: (%lx)\n", error));
885	return error;
886}
887
888// userlandfs_read_index_dir
889static status_t
890userlandfs_read_index_dir(fs_volume* fsVolume, void* cookie,
891	struct dirent* buffer, size_t bufferSize, uint32* count)
892{
893	Volume* volume = (Volume*)fsVolume->private_volume;
894	PRINT(("userlandfs_read_index_dir(%p, %p, %p, %lu, %lu)\n", volume, cookie,
895		buffer, bufferSize, *count));
896	status_t error = volume->ReadIndexDir(cookie, buffer, bufferSize,
897		*count, count);
898	PRINT(("userlandfs_read_index_dir() done: (%lx, %lu)\n", error, *count));
899	return error;
900}
901
902// userlandfs_rewind_index_dir
903static status_t
904userlandfs_rewind_index_dir(fs_volume* fsVolume, void* cookie)
905{
906	Volume* volume = (Volume*)fsVolume->private_volume;
907	PRINT(("userlandfs_rewind_index_dir(%p, %p)\n", volume, cookie));
908	status_t error = volume->RewindIndexDir(cookie);
909	PRINT(("userlandfs_rewind_index_dir() done: (%lx)\n", error));
910	return error;
911}
912
913// userlandfs_create_index
914static status_t
915userlandfs_create_index(fs_volume* fsVolume, const char* name, uint32 type,
916	uint32 flags)
917{
918	Volume* volume = (Volume*)fsVolume->private_volume;
919	PRINT(("userlandfs_create_index(%p, `%s', 0x%lx, 0x%lx)\n", volume, name,
920		type, flags));
921	status_t error = volume->CreateIndex(name, type, flags);
922	PRINT(("userlandfs_create_index() done: (%lx)\n", error));
923	return error;
924}
925
926// userlandfs_remove_index
927static status_t
928userlandfs_remove_index(fs_volume* fsVolume, const char* name)
929{
930	Volume* volume = (Volume*)fsVolume->private_volume;
931	PRINT(("userlandfs_remove_index(%p, `%s')\n", volume, name));
932	status_t error = volume->RemoveIndex(name);
933	PRINT(("userlandfs_remove_index() done: (%lx)\n", error));
934	return error;
935}
936
937// userlandfs_read_index_stat
938static status_t
939userlandfs_read_index_stat(fs_volume* fsVolume, const char* name,
940	struct stat* st)
941{
942	Volume* volume = (Volume*)fsVolume->private_volume;
943	PRINT(("userlandfs_read_index_stat(%p, `%s', %p)\n", volume, name, st));
944	status_t error = volume->ReadIndexStat(name, st);
945	PRINT(("userlandfs_read_index_stat() done: (%lx)\n", error));
946	return error;
947}
948
949
950// #pragma mark - queries
951
952
953// userlandfs_open_query
954static status_t
955userlandfs_open_query(fs_volume* fsVolume, const char *queryString,
956	uint32 flags, port_id port, uint32 token, void** cookie)
957{
958	Volume* volume = (Volume*)fsVolume->private_volume;
959	PRINT(("userlandfs_open_query(%p, `%s', %lu, %ld, %lu, %p)\n", volume,
960		queryString, flags, port, token, cookie));
961	status_t error = volume->OpenQuery(queryString, flags, port, token, cookie);
962	PRINT(("userlandfs_open_query() done: (%lx, %p)\n", error, *cookie));
963	return error;
964}
965
966// userlandfs_close_query
967static status_t
968userlandfs_close_query(fs_volume* fsVolume, void* cookie)
969{
970	Volume* volume = (Volume*)fsVolume->private_volume;
971	PRINT(("userlandfs_close_query(%p, %p)\n", volume, cookie));
972	status_t error = volume->CloseQuery(cookie);
973	PRINT(("userlandfs_close_query() done: (%lx)\n", error));
974	return error;
975}
976
977// userlandfs_free_query_cookie
978static status_t
979userlandfs_free_query_cookie(fs_volume* fsVolume, void* cookie)
980{
981	Volume* volume = (Volume*)fsVolume->private_volume;
982	PRINT(("userlandfs_free_query_cookie(%p, %p)\n", volume, cookie));
983	status_t error = volume->FreeQueryCookie(cookie);
984	PRINT(("userlandfs_free_query_cookie() done: (%lx)\n", error));
985	return error;
986}
987
988// userlandfs_read_query
989static status_t
990userlandfs_read_query(fs_volume* fsVolume, void* cookie,
991	struct dirent* buffer, size_t bufferSize, uint32* count)
992{
993	Volume* volume = (Volume*)fsVolume->private_volume;
994	PRINT(("userlandfs_read_query(%p, %p, %p, %lu, %lu)\n", volume, cookie,
995		buffer, bufferSize, *count));
996	status_t error = volume->ReadQuery(cookie, buffer, bufferSize, *count,
997		count);
998	PRINT(("userlandfs_read_query() done: (%lx, %ld)\n", error, *count));
999	#if DEBUG
1000		if (error == B_OK && *count > 0) {
1001			// R5's kernel vsprintf() doesn't seem to know `%.<number>s', so
1002			// we need to work around.
1003			char name[B_FILE_NAME_LENGTH];
1004			int nameLen = strnlen(buffer->d_name, B_FILE_NAME_LENGTH - 1);
1005			strncpy(name, buffer->d_name, nameLen);
1006			name[nameLen] = '\0';
1007			PRINT(("  entry: d_dev: %ld, d_pdev: %ld, d_ino: %Ld, d_pino: %Ld, "
1008				"d_reclen: %hu, d_name: `%s'\n",
1009				buffer->d_dev, buffer->d_pdev, buffer->d_ino, buffer->d_pino,
1010				buffer->d_reclen, name));
1011		}
1012	#endif
1013	return error;
1014}
1015
1016// userlandfs_rewind_query
1017static status_t
1018userlandfs_rewind_query(fs_volume* fsVolume, void* cookie)
1019{
1020	Volume* volume = (Volume*)fsVolume->private_volume;
1021	PRINT(("userlandfs_rewind_query(%p, %p)\n", volume, cookie));
1022	status_t error = volume->RewindQuery(cookie);
1023	PRINT(("userlandfs_rewind_query() done: (%lx)\n", error));
1024	return error;
1025}
1026
1027
1028// userlandfs_initialize
1029/*
1030static status_t
1031userlandfs_initialize(const char *deviceName, void *parameters,
1032	size_t len)
1033{
1034	// get the parameters
1035	String fsName;
1036	const char* fsParameters;
1037	int32 fsParameterLength;
1038	status_t error = parse_parameters(parameters, len, fsName, &fsParameters,
1039		&fsParameterLength);
1040	// make sure there is a UserlandFS we can work with
1041	UserlandFS* userlandFS = NULL;
1042	error = UserlandFS::RegisterUserlandFS(&userlandFS);
1043	if (error != B_OK) {
1044		exit_debugging();
1045		return error;
1046	}
1047	// get the file system
1048	FileSystem* fileSystem = NULL;
1049	if (error == B_OK)
1050		error = userlandFS->RegisterFileSystem(fsName.GetString(), &fileSystem);
1051	// initialize the volume
1052	if (error == B_OK) {
1053		error = fileSystem->Initialize(deviceName, fsParameters,
1054			fsParameterLength);
1055	}
1056	// cleanup
1057	if (fileSystem)
1058		userlandFS->UnregisterFileSystem(fileSystem);
1059	UserlandFS::UnregisterUserlandFS();
1060	return error;
1061}*/
1062
1063
1064
1065// #pragma mark ----- module -----
1066
1067
1068static status_t
1069userlandfs_std_ops(int32 op, ...)
1070{
1071	switch (op) {
1072		case B_MODULE_INIT:
1073		{
1074			init_debugging();
1075			PRINT(("userlandfs_std_ops(): B_MODULE_INIT\n"));
1076
1077			// make sure there is a UserlandFS we can work with
1078			UserlandFS* userlandFS = NULL;
1079			status_t error = UserlandFS::InitUserlandFS(&userlandFS);
1080			if (error != B_OK) {
1081				exit_debugging();
1082				return error;
1083			}
1084
1085			return B_OK;
1086		}
1087
1088		case B_MODULE_UNINIT:
1089			PRINT(("userlandfs_std_ops(): B_MODULE_UNINIT\n"));
1090			UserlandFS::UninitUserlandFS();
1091			exit_debugging();
1092			return B_OK;
1093
1094		default:
1095			return B_ERROR;
1096	}
1097}
1098
1099
1100static file_system_module_info sUserlandFSModuleInfo = {
1101	{
1102		"file_systems/userlandfs" B_CURRENT_FS_API_VERSION,
1103		0,
1104		userlandfs_std_ops,
1105	},
1106
1107	"userlandfs",				// short name
1108	"Userland File System",		// pretty name
1109	0,	// DDM flags
1110
1111	// scanning
1112	NULL,	// identify_partition()
1113	NULL,	// scan_partition()
1114	NULL,	// free_identify_partition_cookie()
1115	NULL,	// free_partition_content_cookie()
1116
1117	// general operations
1118	&userlandfs_mount,
1119
1120	// capability querying
1121	NULL,	// get_supported_operations()
1122	NULL,	// validate_resize()
1123	NULL,	// validate_move()
1124	NULL,	// validate_set_content_name()
1125	NULL,	// validate_set_content_parameters()
1126	NULL,	// validate_initialize()
1127
1128	// shadow partition modification
1129	NULL,	// shadow_changed()
1130
1131	// writing
1132	NULL,	// defragment()
1133	NULL,	// repair()
1134	NULL,	// resize()
1135	NULL,	// move()
1136	NULL,	// set_content_name()
1137	NULL,	// set_content_parameters()
1138	NULL	// initialize()
1139};
1140
1141
1142fs_volume_ops gUserlandFSVolumeOps = {
1143	// general operations
1144	&userlandfs_unmount,
1145	&userlandfs_read_fs_info,
1146	&userlandfs_write_fs_info,
1147	&userlandfs_sync,
1148
1149	&userlandfs_get_vnode,
1150
1151	// index directory & index operations
1152	&userlandfs_open_index_dir,
1153	&userlandfs_close_index_dir,
1154	&userlandfs_free_index_dir_cookie,
1155	&userlandfs_read_index_dir,
1156	&userlandfs_rewind_index_dir,
1157
1158	&userlandfs_create_index,
1159	&userlandfs_remove_index,
1160	&userlandfs_read_index_stat,
1161
1162	// query operations
1163	&userlandfs_open_query,
1164	&userlandfs_close_query,
1165	&userlandfs_free_query_cookie,
1166	&userlandfs_read_query,
1167	&userlandfs_rewind_query,
1168
1169	/* support for FS layers */
1170	NULL,	// all_layers_mounted()
1171	NULL,	// create_sub_vnode()
1172	NULL	// delete_sub_vnode()
1173};
1174
1175
1176fs_vnode_ops gUserlandFSVnodeOps = {
1177	// vnode operations
1178	&userlandfs_lookup,
1179	&userlandfs_get_vnode_name,
1180	&userlandfs_put_vnode,
1181	&userlandfs_remove_vnode,
1182
1183	// VM file access
1184	NULL,	// can_page() -- obsolete
1185	NULL,	// read_pages() -- obsolete
1186	NULL,	// write_pages() -- obsolete
1187
1188	// asynchronous I/O
1189	&userlandfs_io,
1190	&userlandfs_cancel_io,
1191
1192	// cache file access
1193	NULL,	// get_file_map() -- not needed
1194
1195	// common operations
1196	&userlandfs_ioctl,
1197	&userlandfs_set_flags,
1198	&userlandfs_select,
1199	&userlandfs_deselect,
1200	&userlandfs_fsync,
1201
1202	&userlandfs_read_symlink,
1203	&userlandfs_create_symlink,
1204
1205	&userlandfs_link,
1206	&userlandfs_unlink,
1207	&userlandfs_rename,
1208
1209	&userlandfs_access,
1210	&userlandfs_read_stat,
1211	&userlandfs_write_stat,
1212	NULL,	// preallocate()
1213
1214	// file operations
1215	&userlandfs_create,
1216	&userlandfs_open,
1217	&userlandfs_close,
1218	&userlandfs_free_cookie,
1219	&userlandfs_read,
1220	&userlandfs_write,
1221
1222	// directory operations
1223	&userlandfs_create_dir,
1224	&userlandfs_remove_dir,
1225	&userlandfs_open_dir,
1226	&userlandfs_close_dir,
1227	&userlandfs_free_dir_cookie,
1228	&userlandfs_read_dir,
1229	&userlandfs_rewind_dir,
1230
1231	// attribute directory operations
1232	&userlandfs_open_attr_dir,
1233	&userlandfs_close_attr_dir,
1234	&userlandfs_free_attr_dir_cookie,
1235	&userlandfs_read_attr_dir,
1236	&userlandfs_rewind_attr_dir,
1237
1238	// attribute operations
1239	&userlandfs_create_attr,
1240	&userlandfs_open_attr,
1241	&userlandfs_close_attr,
1242	&userlandfs_free_attr_cookie,
1243	&userlandfs_read_attr,
1244	&userlandfs_write_attr,
1245
1246	&userlandfs_read_attr_stat,
1247	&userlandfs_write_attr_stat,
1248	&userlandfs_rename_attr,
1249	&userlandfs_remove_attr,
1250
1251	// support for node and FS layers
1252	NULL,	// create_special_node()
1253	NULL	// get_super_vnode()
1254};
1255
1256
1257module_info *modules[] = {
1258	(module_info *)&sUserlandFSModuleInfo,
1259	NULL,
1260};
1261