1// kernel_interface.cpp
2//
3// Copyright (c) 2003, Axel Dörfler (axeld@pinc-software.de)
4// Copyright (c) 2003, Ingo Weinhold (bonefish@cs.tu-berlin.de)
5//
6// This program is free software; you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation; either version 2 of the License, or
9// (at your option) any later version.
10//
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14// GNU General Public License for more details.
15//
16// You should have received a copy of the GNU General Public License
17// along with this program; if not, write to the Free Software
18// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19//
20// You can alternatively use *this file* under the terms of the the MIT
21// license included in this package.
22
23#include <ctype.h>
24#include <dirent.h>
25#include <errno.h>
26#include <fcntl.h>
27#include <stdlib.h>
28#include <string.h>
29#include <time.h>
30#include <unistd.h>
31#include <stdio.h>
32#include <sys/stat.h>
33
34#include <new>
35
36#include <fs_index.h>
37#include <fs_query.h>
38#include <KernelExport.h>
39#include <TypeConstants.h>
40
41//#include "lock.h"
42//#include "cache.h"
43#include "fsproto.h"
44
45#include <AutoDeleter.h>
46
47#include "AllocationInfo.h"
48#include "AttributeIndex.h"
49#include "AttributeIterator.h"
50#include "Debug.h"
51#include "Directory.h"
52#include "Entry.h"
53#include "EntryIterator.h"
54#include "File.h"
55#include "Index.h"
56#include "IndexDirectory.h"
57#include "Locking.h"
58#include "Misc.h"
59#include "Node.h"
60#include "Query.h"
61#include "ramfs_ioctl.h"
62#include "SymLink.h"
63#include "Volume.h"
64
65// BFS returns the length of the entry name in dirent::d_reclen. This is
66// not correct, since this field should be set to the length of the complete
67// dirent. If set to != 0, KEEP_WRONG_DIRENT_RECLEN emulates the buggy
68// bahavior.
69#ifndef KEEP_WRONG_DIRENT_RECLEN
70#define KEEP_WRONG_DIRENT_RECLEN	0
71#endif
72
73extern "C" {
74
75static int ramfs_mount(nspace_id nsid, const char *device, ulong flags,
76					   void *parameters, size_t len, void **data,
77					   vnode_id *rootID);
78static int ramfs_unmount(void *ns);
79static int ramfs_initialize(const char *deviceName, void *parameters,
80							size_t len);
81static int ramfs_sync(void *_ns);
82
83static int ramfs_read_vnode(void *ns, vnode_id vnid, char reenter,
84							void **node);
85static int ramfs_write_vnode(void *ns, void *_node, char reenter);
86static int ramfs_remove_vnode(void *ns, void *_node, char reenter);
87static int ramfs_walk(void *ns, void *_dir, const char *entryName,
88					  char **resolvedPath, vnode_id *vnid);
89static int ramfs_access(void *ns, void *_node, int mode);
90
91static int ramfs_ioctl(void *ns, void *_node, void *_cookie, int cmd,
92					   void *buffer, size_t bufferSize);
93static int ramfs_setflags(void *ns, void *_node, void *_cookie, int flags);
94static int ramfs_fsync(void *ns, void *_node);
95static int ramfs_read_stat(void *ns, void *_node, struct stat *st);
96static int ramfs_write_stat(void *ns, void *_node, struct stat *st, long mask);
97static int ramfs_create(void *ns, void *dir, const char *name, int openMode,
98						int mode, vnode_id *vnid, void **cookie);
99static int ramfs_open(void *ns, void *_node, int openMode, void **cookie);
100static int ramfs_close(void *ns, void *node, void *cookie);
101static int ramfs_free_cookie(void *ns, void *node, void *cookie);
102static int ramfs_read(void *ns, void *_node, void *cookie, off_t pos,
103					  void *buffer, size_t *bufferSize);
104static int ramfs_write(void *ns, void *_node, void *cookie, off_t pos,
105					   const void *buffer, size_t *bufferSize);
106
107static int ramfs_rename(void *ns, void *_oldDir, const char *oldName,
108						void *_newDir, const char *newName);
109static int ramfs_link(void *ns, void *_dir, const char *name, void *node);
110static int ramfs_unlink(void *ns, void *_dir, const char *name);
111static int ramfs_rmdir(void *ns, void *_dir, const char *name);
112static int ramfs_mkdir(void *ns, void *_dir, const char *name, int mode);
113static int ramfs_open_dir(void *ns, void *_node, void **cookie);
114static int ramfs_read_dir(void *ns, void *_node, void *cookie, long *count,
115						  struct dirent *buffer, size_t bufferSize);
116static int ramfs_rewind_dir(void *ns, void *_node, void *cookie);
117static int ramfs_close_dir(void *ns, void *_node, void *cookie);
118static int ramfs_free_dir_cookie(void *ns, void *_node, void *cookie);
119
120static int ramfs_read_fs_stat(void *ns, struct fs_info *info);
121static int ramfs_write_fs_stat(void *ns, struct fs_info *info, long mask);
122
123static int ramfs_symlink(void *ns, void *_dir, const char *name,
124						 const char *path);
125static int ramfs_read_link(void *ns, void *_node, char *buffer,
126						   size_t *bufferSize);
127// attributes
128static int ramfs_open_attrdir(void *ns, void *_node, void **_cookie);
129static int ramfs_close_attrdir(void *ns, void *_node, void *_cookie);
130static int ramfs_free_attrdir_cookie(void *ns, void *_node, void *_cookie);
131static int ramfs_rewind_attrdir(void *ns, void *_node, void *_cookie);
132static int ramfs_read_attrdir(void *ns, void *_node, void *_cookie,
133							  long *count, struct dirent *buffer,
134							  size_t bufferSize);
135static int ramfs_read_attr(void *ns, void *_node, const char *name, int type,
136						   void *buffer, size_t *bufferSize, off_t pos);
137static int ramfs_write_attr(void *ns, void *_node, const char *name, int type,
138							const void *buffer, size_t *bufferSize, off_t pos);
139static int ramfs_remove_attr(void *ns, void *_node, const char *name);
140static int ramfs_rename_attr(void *ns, void *_node, const char *oldName,
141							 const char *newName);
142static int ramfs_stat_attr(void *ns, void *_node, const char *name,
143						   struct attr_info *attrInfo);
144// indices
145static int ramfs_open_indexdir(void *ns, void **_cookie);
146static int ramfs_close_indexdir(void *ns, void *_cookie);
147static int ramfs_free_indexdir_cookie(void *ns, void *_node, void *_cookie);
148static int ramfs_rewind_indexdir(void *_ns, void *_cookie);
149static int ramfs_read_indexdir(void *ns, void *_cookie, long *count,
150							   struct dirent *buffer, size_t bufferSize);
151static int ramfs_create_index(void *ns, const char *name, int type, int flags);
152static int ramfs_remove_index(void *ns, const char *name);
153static int ramfs_rename_index(void *ns, const char *oldname,
154							  const char *newname);
155static int ramfs_stat_index(void *ns, const char *name,
156							struct index_info *indexInfo);
157// queries
158int ramfs_open_query(void *ns, const char *queryString, ulong flags,
159					 port_id port, long token, void **cookie);
160int ramfs_close_query(void *ns, void *cookie);
161int ramfs_free_query_cookie(void *ns, void *node, void *cookie);
162int ramfs_read_query(void *ns, void *cookie, long *count,
163					 struct dirent *buffer, size_t bufferSize);
164
165} // extern "C"
166
167/* vnode_ops struct. Fill this in to tell the kernel how to call
168	functions in your driver.
169*/
170
171vnode_ops fs_entry =  {
172	&ramfs_read_vnode,				// read_vnode
173	&ramfs_write_vnode,				// write_vnode
174	&ramfs_remove_vnode,			// remove_vnode
175	NULL,							// secure_vnode (not needed)
176	&ramfs_walk,					// walk
177	&ramfs_access,					// access
178	&ramfs_create,					// create
179	&ramfs_mkdir,					// mkdir
180	&ramfs_symlink,					// symlink
181	&ramfs_link,					// link
182	&ramfs_rename,					// rename
183	&ramfs_unlink,					// unlink
184	&ramfs_rmdir,					// rmdir
185	&ramfs_read_link,				// readlink
186	&ramfs_open_dir,				// opendir
187	&ramfs_close_dir,				// closedir
188	&ramfs_free_dir_cookie,			// free_dircookie
189	&ramfs_rewind_dir,				// rewinddir
190	&ramfs_read_dir,				// readdir
191	&ramfs_open,					// open file
192	&ramfs_close,					// close file
193	&ramfs_free_cookie,				// free cookie
194	&ramfs_read,					// read file
195	&ramfs_write,					// write file
196	NULL,							// readv
197	NULL,							// writev
198	&ramfs_ioctl,					// ioctl
199	&ramfs_setflags,				// setflags file
200	&ramfs_read_stat,				// read stat
201	&ramfs_write_stat,				// write stat
202	&ramfs_fsync,					// fsync
203	&ramfs_initialize,				// initialize
204	&ramfs_mount,					// mount
205	&ramfs_unmount,					// unmount
206	&ramfs_sync,					// sync
207	&ramfs_read_fs_stat,			// read fs stat
208	&ramfs_write_fs_stat,			// write fs stat
209	NULL,							// select
210	NULL,							// deselect
211
212	&ramfs_open_indexdir,			// open index dir
213	&ramfs_close_indexdir,			// close index dir
214	&ramfs_free_indexdir_cookie,	// free index dir cookie
215	&ramfs_rewind_indexdir,			// rewind index dir
216	&ramfs_read_indexdir,			// read index dir
217	&ramfs_create_index,			// create index
218	&ramfs_remove_index,			// remove index
219	&ramfs_rename_index,			// rename index
220	&ramfs_stat_index,				// stat index
221
222	&ramfs_open_attrdir,			// open attr dir
223	&ramfs_close_attrdir,			// close attr dir
224	&ramfs_free_attrdir_cookie,		// free attr dir cookie
225	&ramfs_rewind_attrdir,			// rewind attr dir
226	&ramfs_read_attrdir,			// read attr dir
227	&ramfs_write_attr,				// write attr
228	&ramfs_read_attr,				// read attr
229	&ramfs_remove_attr,				// remove attr
230	&ramfs_rename_attr,				// rename attr
231	&ramfs_stat_attr,				// stat attr
232
233	&ramfs_open_query,				// open query
234	&ramfs_close_query,				// close query
235	&ramfs_free_query_cookie,		// free query cookie
236	&ramfs_read_query,				// read query
237};
238
239int32 api_version = B_CUR_FS_API_VERSION;
240
241static char *kFSName = "ramfs";
242static const size_t kOptimalIOSize = 65536;
243static const bigtime_t kNotificationInterval = 1000000LL;
244
245// notify_if_stat_changed
246void
247notify_if_stat_changed(Volume *volume, Node *node)
248{
249	if (volume && node && node->IsModified()) {
250		node->MarkUnmodified();
251		notify_listener(B_STAT_CHANGED, volume->GetID(), 0, 0, node->GetID(),
252						NULL);
253	}
254}
255
256
257// #pragma mark - FS
258
259
260// ramfs_mount
261static
262int
263ramfs_mount(nspace_id nsid, const char */*device*/, ulong flags,
264			void */*parameters*/, size_t /*len*/, void **data,
265			vnode_id *rootID)
266{
267	init_debugging();
268	FUNCTION_START();
269	// parameters are ignored for now
270	status_t error = B_OK;
271	// fail, if read-only mounting is requested
272	if (flags & B_MOUNT_READ_ONLY)
273		error = B_BAD_VALUE;
274	// allocate and init the volume
275	Volume *volume = NULL;
276	if (error == B_OK) {
277		volume = new(std::nothrow) Volume;
278		if (!volume)
279			SET_ERROR(error, B_NO_MEMORY);
280		if (error == B_OK)
281			error = volume->Mount(nsid);
282	}
283	// set the results
284	if (error == B_OK) {
285		*rootID = volume->GetRootDirectory()->GetID();
286		*data = volume;
287	}
288	// cleanup on failure
289	if (error != B_OK && volume)
290		delete volume;
291
292if (error == B_OK) {
293ramfs_create_index(volume, "myIndex", B_STRING_TYPE, 0);
294}
295
296	RETURN_ERROR(error);
297}
298
299// ramfs_unmount
300static
301int
302ramfs_unmount(void *ns)
303{
304	FUNCTION_START();
305	Volume *volume = (Volume*)ns;
306	status_t error = volume->Unmount();
307	if (error == B_OK)
308		delete volume;
309	if (error != B_OK)
310		REPORT_ERROR(error);
311	exit_debugging();
312	return error;
313}
314
315// ramfs_initialize
316static
317int
318ramfs_initialize(const char */*deviceName*/, void */*parameters*/,
319				 size_t /*len*/)
320{
321	FUNCTION_START();
322	return B_ERROR;
323}
324
325// ramfs_sync
326static
327int
328ramfs_sync(void */*_ns*/)
329{
330	FUNCTION_START();
331	return B_OK;
332}
333
334
335// #pragma mark - VNodes
336
337
338// ramfs_read_vnode
339static
340int
341ramfs_read_vnode(void *ns, vnode_id vnid, char /*reenter*/, void **node)
342{
343//	FUNCTION_START();
344FUNCTION(("node: %Ld\n", vnid));
345	Volume *volume = (Volume*)ns;
346	Node *foundNode = NULL;
347	status_t error = B_OK;
348	if (VolumeReadLocker locker = volume) {
349		error = volume->FindNode(vnid, &foundNode);
350		if (error == B_OK)
351			*node = foundNode;
352	} else
353		SET_ERROR(error, B_ERROR);
354	RETURN_ERROR(error);
355}
356
357// ramfs_write_vnode
358static
359int
360ramfs_write_vnode(void */*ns*/, void *DARG(_node), char /*reenter*/)
361{
362// DANGER: If dbg_printf() is used, this thread will enter another FS and
363// even perform a write operation. The is dangerous here, since this hook
364// may be called out of the other FSs, since, for instance a put_vnode()
365// called from another FS may cause the VFS layer to free vnodes and thus
366// invoke this hook.
367//	FUNCTION_START();
368//FUNCTION(("node: %Ld\n", ((Node*)_node)->GetID()));
369	status_t error = B_OK;
370	RETURN_ERROR(error);
371}
372
373// ramfs_remove_vnode
374static
375int
376ramfs_remove_vnode(void *ns, void *_node, char /*reenter*/)
377{
378FUNCTION(("node: %Ld\n", ((Node*)_node)->GetID()));
379	Volume *volume = (Volume*)ns;
380	Node *node = (Node*)_node;
381	status_t error = B_OK;
382	if (VolumeWriteLocker locker = volume) {
383		volume->NodeRemoved(node);
384		delete node;
385	} else
386		SET_ERROR(error, B_ERROR);
387	RETURN_ERROR(error);
388}
389
390
391// #pragma mark - Nodes
392
393
394// ramfs_walk
395static
396int
397ramfs_walk(void *ns, void *_dir, const char *entryName, char **resolvedPath,
398		   vnode_id *vnid)
399{
400//	FUNCTION_START();
401	Volume *volume = (Volume*)ns;
402	Directory *dir = dynamic_cast<Directory*>((Node*)_dir);
403FUNCTION(("dir: (%Lu), entry: `%s'\n", (dir ? dir->GetID() : -1), entryName));
404	status_t error = B_OK;
405	if (VolumeReadLocker locker = volume) {
406		Node *node = NULL;
407		// check for non-directories
408		if (!dir) {
409			error = B_NOT_A_DIRECTORY;
410		// special entries: "." and ".."
411		} else if (!strcmp(entryName, ".")) {
412			*vnid = dir->GetID();
413			if (volume->GetVNode(*vnid, &node) != B_OK)
414				error = B_BAD_VALUE;
415		} else if (!strcmp(entryName, "..")) {
416			Directory *parent = dir->GetParent();
417			if (parent && volume->GetVNode(parent->GetID(), &node) == B_OK)
418				*vnid = node->GetID();
419			else
420				error = B_BAD_VALUE;
421		// ordinary entries
422		} else {
423			// find the entry
424			error = dir->FindAndGetNode(entryName, &node);
425SET_ERROR(error, error);
426			if (error == B_OK)
427				*vnid = node->GetID();
428			// if it is a symlink, resolve it, if desired
429			if (error == B_OK && resolvedPath && node->IsSymLink()) {
430				SymLink *symLink = dynamic_cast<SymLink*>(node);
431				*resolvedPath = strdup(symLink->GetLinkedPath());
432				if (!*resolvedPath)
433					SET_ERROR(error, B_NO_MEMORY);
434				volume->PutVNode(*vnid);
435			}
436		}
437	} else
438		SET_ERROR(error, B_ERROR);
439	RETURN_ERROR(error);
440}
441
442// ramfs_ioctl
443static
444int
445ramfs_ioctl(void *ns, void */*_node*/, void */*_cookie*/, int cmd,
446			void *buffer, size_t /*bufferSize*/)
447{
448	FUNCTION_START();
449	Volume *volume = (Volume*)ns;
450	status_t error = B_OK;
451	switch (cmd) {
452		case RAMFS_IOCTL_GET_ALLOCATION_INFO:
453		{
454			if (buffer) {
455				if (VolumeReadLocker locker = volume) {
456					AllocationInfo *info = (AllocationInfo*)buffer;
457					volume->GetAllocationInfo(*info);
458				} else
459					SET_ERROR(error, B_ERROR);
460			} else
461				SET_ERROR(error, B_BAD_VALUE);
462			break;
463		}
464		case RAMFS_IOCTL_DUMP_INDEX:
465		{
466			if (buffer) {
467				if (VolumeReadLocker locker = volume) {
468					const char *name = (const char*)buffer;
469PRINT(("  RAMFS_IOCTL_DUMP_INDEX, `%s'\n", name));
470					IndexDirectory *indexDir = volume->GetIndexDirectory();
471					if (indexDir) {
472						if (Index *index = indexDir->FindIndex(name))
473							index->Dump();
474						else
475							SET_ERROR(error, B_ENTRY_NOT_FOUND);
476					} else
477						SET_ERROR(error, B_ENTRY_NOT_FOUND);
478				} else
479					SET_ERROR(error, B_ERROR);
480			} else
481				SET_ERROR(error, B_BAD_VALUE);
482			break;
483		}
484		default:
485			error = B_BAD_VALUE;
486			break;
487	}
488	RETURN_ERROR(error);
489}
490
491// ramfs_setflags
492static
493int
494ramfs_setflags(void */*ns*/, void */*_node*/, void */*_cookie*/, int /*flags*/)
495{
496	FUNCTION_START();
497// TODO:...
498	return B_OK;
499}
500
501// ramfs_fsync
502static
503int
504ramfs_fsync(void */*ns*/, void */*_node*/)
505{
506	FUNCTION_START();
507	return B_OK;
508}
509
510// ramfs_read_stat
511static
512int
513ramfs_read_stat(void *ns, void *_node, struct stat *st)
514{
515//	FUNCTION_START();
516	Volume *volume = (Volume*)ns;
517	Node *node = (Node*)_node;
518FUNCTION(("node: %Ld\n", node->GetID()));
519	status_t error = B_OK;
520	if (VolumeReadLocker locker = volume) {
521		st->st_dev = volume->GetID();
522		st->st_ino = node->GetID();
523		st->st_mode = node->GetMode();
524		st->st_nlink = node->GetRefCount();
525		st->st_uid = node->GetUID();
526		st->st_gid = node->GetGID();
527		st->st_size = node->GetSize();
528		st->st_blksize = kOptimalIOSize;
529		st->st_atime = node->GetATime();
530		st->st_mtime = node->GetMTime();
531		st->st_ctime = node->GetCTime();
532		st->st_crtime = node->GetCrTime();
533	} else
534		SET_ERROR(error, B_ERROR);
535	RETURN_ERROR(error);
536}
537
538// ramfs_write_stat
539static
540int
541ramfs_write_stat(void *ns, void *_node, struct stat *st, long mask)
542{
543	FUNCTION(("mask: %lx\n", mask));
544	Volume *volume = (Volume*)ns;
545	Node *node = (Node*)_node;
546	status_t error = B_OK;
547	if (VolumeWriteLocker locker = volume) {
548		NodeMTimeUpdater mTimeUpdater(node);
549		// check permissions
550		error = node->CheckPermissions(ACCESS_W);
551		// size
552		if (error == B_OK && (mask & WSTAT_SIZE))
553			error = node->SetSize(st->st_size);
554		if (error == B_OK) {
555			// permissions
556			if (mask & WSTAT_MODE) {
557				node->SetMode(node->GetMode() & ~S_IUMSK
558							  | st->st_mode & S_IUMSK);
559			}
560			// UID
561			if (mask & WSTAT_UID)
562				node->SetUID(st->st_uid);
563			// GID
564			if (mask & WSTAT_GID)
565				node->SetGID(st->st_gid);
566			// mtime
567			if (mask & WSTAT_MTIME)
568				node->SetMTime(st->st_mtime);
569			// crtime
570			if (mask & WSTAT_CRTIME)
571				node->SetCrTime(st->st_crtime);
572		}
573		// notify listeners
574		if (error == B_OK)
575			notify_if_stat_changed(volume, node);
576	} else
577		SET_ERROR(error, B_ERROR);
578	RETURN_ERROR(error);
579}
580
581
582// #pragma mark - Files
583
584
585// FileCookie
586class FileCookie {
587public:
588	FileCookie(int openMode) : fOpenMode(openMode), fLastNotificationTime(0) {}
589
590	inline int GetOpenMode()				{ return fOpenMode; }
591
592	inline bigtime_t GetLastNotificationTime()
593		{ return fLastNotificationTime; }
594
595	inline bool NotificationIntervalElapsed(bool set = false)
596	{
597		bigtime_t currentTime = system_time();
598		bool result = (currentTime - fLastNotificationTime
599					   > kNotificationInterval);
600		if (set && result)
601			fLastNotificationTime = currentTime;
602		return result;
603	}
604
605private:
606	int			fOpenMode;
607	bigtime_t	fLastNotificationTime;
608};
609
610// ramfs_create
611static
612int
613ramfs_create(void *ns, void *_dir, const char *name, int openMode,
614			 int mode, vnode_id *vnid, void **_cookie)
615{
616//	FUNCTION_START();
617	FUNCTION(("name: `%s', open mode: %x, mode: %x\n", name, openMode, mode));
618	Volume *volume = (Volume*)ns;
619	Directory *dir = dynamic_cast<Directory*>((Node*)_dir);
620	status_t error = B_OK;
621	// check name
622	if (!name || *name == '\0') {
623		SET_ERROR(error, B_BAD_VALUE);
624	// check directory
625	} else if (!dir) {
626		SET_ERROR(error, B_BAD_VALUE);
627	} else if (VolumeWriteLocker locker = volume) {
628		NodeMTimeUpdater mTimeUpdater(dir);
629		// directory deleted?
630		if (is_vnode_removed(volume->GetID(), dir->GetID()) > 0)
631			SET_ERROR(error, B_NOT_ALLOWED);
632		// create the file cookie
633		FileCookie *cookie = NULL;
634		if (error == B_OK) {
635			cookie = new(std::nothrow) FileCookie(openMode);
636			if (!cookie)
637				SET_ERROR(error, B_NO_MEMORY);
638		}
639		Node *node = NULL;
640		if (error == B_OK) {
641			// check if entry does already exist
642			if (dir->FindNode(name, &node) == B_OK) {
643				// entry does already exist
644				// fail, if we shall fail, when the file exists
645				if (openMode & O_EXCL) {
646					SET_ERROR(error, B_FILE_EXISTS);
647				// don't create a file over an existing directory or symlink
648				} else if (!node->IsFile()) {
649					SET_ERROR(error, B_NOT_ALLOWED);
650				// the user must have write permission for an existing entry
651				} else if ((error = node->CheckPermissions(ACCESS_W))
652						   == B_OK) {
653					// truncate, if requested
654					if (openMode & O_TRUNC)
655						error = node->SetSize(0);
656					// we ignore the supplied permissions in this case
657					// get vnode
658					if (error == B_OK) {
659						*vnid = node->GetID();
660						error = volume->GetVNode(node->GetID(), &node);
661					}
662				}
663			// the user must have dir write permission to create a new entry
664			} else if ((error = dir->CheckPermissions(ACCESS_W)) == B_OK) {
665				// entry doesn't exist: create a file
666				File *file = NULL;
667				error = dir->CreateFile(name, &file);
668				if (error == B_OK) {
669					node = file;
670					*vnid = node->GetID();
671					// set permissions, owner and group
672					node->SetMode(mode);
673					node->SetUID(geteuid());
674					node->SetGID(getegid());
675				}
676			}
677			// set result / cleanup on failure
678			if (error == B_OK)
679				*_cookie = cookie;
680			else if (cookie)
681				delete cookie;
682		}
683		NodeMTimeUpdater mTimeUpdater2(node);
684		// notify listeners
685		if (error == B_OK) {
686			notify_listener(B_ENTRY_CREATED, volume->GetID(), dir->GetID(), 0,
687							*vnid, name);
688		}
689	} else
690		SET_ERROR(error, B_ERROR);
691	RETURN_ERROR(error);
692}
693
694// ramfs_open
695static
696int
697ramfs_open(void *ns, void *_node, int openMode, void **_cookie)
698{
699//	FUNCTION_START();
700	Volume *volume = (Volume*)ns;
701	Node *node = (Node*)_node;
702FUNCTION(("node: %Ld\n", node->GetID()));
703	status_t error = B_OK;
704	if (VolumeReadLocker locker = volume) {
705		// directory can be opened read-only
706		if (node->IsDirectory() && (openMode & O_RWMASK))
707			openMode &= ~O_RWMASK;
708		int accessMode = open_mode_to_access(openMode);
709		// truncating requires write permission
710		if (error == B_OK && (openMode & O_TRUNC))
711			accessMode |= ACCESS_W;
712		// check open mode against permissions
713		if (error == B_OK)
714			error = node->CheckPermissions(accessMode);
715		// create the cookie
716		FileCookie *cookie = NULL;
717		if (error == B_OK) {
718			cookie = new(std::nothrow) FileCookie(openMode);
719			if (!cookie)
720				SET_ERROR(error, B_NO_MEMORY);
721		}
722		// truncate if requested
723		if (error == B_OK && (openMode & O_TRUNC))
724			error = node->SetSize(0);
725		NodeMTimeUpdater mTimeUpdater(node);
726		// set result / cleanup on failure
727		if (error == B_OK)
728			*_cookie = cookie;
729		else if (cookie)
730			delete cookie;
731	} else
732		SET_ERROR(error, B_ERROR);
733	RETURN_ERROR(error);
734}
735
736// ramfs_close
737static
738int
739ramfs_close(void *ns, void *_node, void */*_cookie*/)
740{
741//	FUNCTION_START();
742	Volume *volume = (Volume*)ns;
743	Node *node = (Node*)_node;
744FUNCTION(("node: %Ld\n", node->GetID()));
745	status_t error = B_OK;
746	// notify listeners
747	if (VolumeReadLocker locker = volume) {
748		notify_if_stat_changed(volume, node);
749	} else
750		SET_ERROR(error, B_ERROR);
751	return B_OK;
752
753}
754
755// ramfs_free_cookie
756static
757int
758ramfs_free_cookie(void */*ns*/, void */*node*/, void *_cookie)
759{
760	FUNCTION_START();
761	FileCookie *cookie = (FileCookie*)_cookie;
762	delete cookie;
763	return B_OK;
764}
765
766// ramfs_read
767static
768int
769ramfs_read(void *ns, void *_node, void *_cookie, off_t pos, void *buffer,
770		   size_t *bufferSize)
771{
772//	FUNCTION_START();
773	Volume *volume = (Volume*)ns;
774	Node *node = (Node*)_node;
775	FileCookie *cookie = (FileCookie*)_cookie;
776//	FUNCTION(("((%lu, %lu), %Ld, %p, %lu)\n", node->GetDirID(),
777//			  node->GetObjectID(), pos, buffer, *bufferSize));
778	status_t error = B_OK;
779	if (VolumeReadLocker locker = volume) {
780		// don't read anything but files
781		if (!node->IsFile())
782			SET_ERROR(error, B_BAD_VALUE);
783		// check, if reading is allowed
784		int rwMode = cookie->GetOpenMode() & O_RWMASK;
785		if (error == B_OK && rwMode != O_RDONLY && rwMode != O_RDWR)
786			SET_ERROR(error, B_FILE_ERROR);
787		// read
788		if (error == B_OK) {
789			if (File *file = dynamic_cast<File*>(node))
790				error = file->ReadAt(pos, buffer, *bufferSize, bufferSize);
791			else {
792				FATAL(("Node %Ld pretends to be a File, but isn't!\n",
793					   node->GetID()));
794				error = B_BAD_VALUE;
795			}
796		}
797	} else
798		SET_ERROR(error, B_ERROR);
799	RETURN_ERROR(error);
800}
801
802// ramfs_write
803static
804int
805ramfs_write(void *ns, void *_node, void *_cookie, off_t pos,
806			const void *buffer, size_t *bufferSize)
807{
808//	FUNCTION_START();
809	Volume *volume = (Volume*)ns;
810	Node *node = (Node*)_node;
811	FileCookie *cookie = (FileCookie*)_cookie;
812//	FUNCTION(("((%lu, %lu), %Ld, %p, %lu)\n", node->GetDirID(),
813//			  node->GetObjectID(), pos, buffer, *bufferSize));
814	status_t error = B_OK;
815	if (VolumeWriteLocker locker = volume) {
816		// don't write anything but files
817		if (!node->IsFile())
818			SET_ERROR(error, B_BAD_VALUE);
819		if (error == B_OK) {
820			// check, if reading is allowed
821			int rwMode = cookie->GetOpenMode() & O_RWMASK;
822			if (error == B_OK && rwMode != O_WRONLY && rwMode != O_RDWR)
823				SET_ERROR(error, B_FILE_ERROR);
824			if (error == B_OK) {
825				// reset the position, if opened in append mode
826				if (cookie->GetOpenMode() & O_APPEND)
827					pos = node->GetSize();
828				// write
829				if (File *file = dynamic_cast<File*>(node)) {
830					error = file->WriteAt(pos, buffer, *bufferSize,
831										  bufferSize);
832				} else {
833					FATAL(("Node %Ld pretends to be a File, but isn't!\n",
834						   node->GetID()));
835					error = B_BAD_VALUE;
836				}
837			}
838		}
839		// notify listeners
840		if (error == B_OK && cookie->NotificationIntervalElapsed(true))
841			notify_if_stat_changed(volume, node);
842		NodeMTimeUpdater mTimeUpdater(node);
843	} else
844		SET_ERROR(error, B_ERROR);
845	RETURN_ERROR(error);
846}
847
848// ramfs_access
849static
850int
851ramfs_access(void *ns, void *_node, int mode)
852{
853	FUNCTION_START();
854	Volume *volume = (Volume*)ns;
855	Node *node = (Node*)_node;
856	status_t error = B_OK;
857	if (VolumeReadLocker locker = volume) {
858		error = node->CheckPermissions(mode);
859	} else
860		SET_ERROR(error, B_ERROR);
861	RETURN_ERROR(error);
862}
863
864
865
866// #pragma mark - Directories
867
868
869// ramfs_rename
870static
871int
872ramfs_rename(void *ns, void *_oldDir, const char *oldName,
873			 void *_newDir, const char *newName)
874{
875	Volume *volume = (Volume*)ns;
876	Directory *oldDir = dynamic_cast<Directory*>((Node*)_oldDir);
877	Directory *newDir = dynamic_cast<Directory*>((Node*)_newDir);
878	status_t error = B_OK;
879
880	// check name
881	if (!oldName || *oldName == '\0'
882		|| !strcmp(oldName, ".")  || !strcmp(oldName, "..")
883		|| !newName || *newName == '\0'
884		|| !strcmp(newName, ".")  || !strcmp(newName, "..")) {
885		SET_ERROR(error, B_BAD_VALUE);
886
887	// check nodes
888	} else if (!oldDir || !newDir) {
889		SET_ERROR(error, B_BAD_VALUE);
890
891	// check if the entry isn't actually moved or renamed
892	} else if (oldDir == newDir && !strcmp(oldName, newName)) {
893		SET_ERROR(error, B_BAD_VALUE);
894	} else if (VolumeWriteLocker locker = volume) {
895FUNCTION(("old dir: %Ld, old name: `%s', new dir: %Ld, new name: `%s'\n",
896oldDir->GetID(), oldName, newDir->GetID(), newName));
897		NodeMTimeUpdater mTimeUpdater1(oldDir);
898		NodeMTimeUpdater mTimeUpdater2(newDir);
899
900		// target directory deleted?
901		if (is_vnode_removed(volume->GetID(), newDir->GetID()) > 0)
902			SET_ERROR(error, B_NOT_ALLOWED);
903
904		// check directory write permissions
905		if (error == B_OK)
906			error = oldDir->CheckPermissions(ACCESS_W);
907		if (error == B_OK)
908			error = newDir->CheckPermissions(ACCESS_W);
909
910		Node *node = NULL;
911		Entry *entry = NULL;
912		if (error == B_OK) {
913			// check if entry exists
914			if (oldDir->FindAndGetNode(oldName, &node, &entry) != B_OK) {
915				SET_ERROR(error, B_ENTRY_NOT_FOUND);
916			} else {
917				if (oldDir != newDir) {
918					// check whether the entry is a descendent of the target
919					// directory
920					for (Directory *parent = newDir;
921						 parent;
922						 parent = parent->GetParent()) {
923						if (parent == node) {
924							error = B_BAD_VALUE;
925							break;
926						} else if (parent == oldDir)
927							break;
928					}
929				}
930			}
931
932			// check the target directory situation
933			Node *clobberNode = NULL;
934			Entry *clobberEntry = NULL;
935			if (error == B_OK) {
936				if (newDir->FindAndGetNode(newName, &clobberNode,
937										   &clobberEntry) == B_OK) {
938					if (clobberNode->IsDirectory()
939						&& !dynamic_cast<Directory*>(clobberNode)->IsEmpty()) {
940						SET_ERROR(error, B_NAME_IN_USE);
941					}
942				}
943			}
944
945			// do the job
946			if (error == B_OK) {
947				// temporarily acquire an additional reference to make
948				// sure the node isn't deleted when we remove the entry
949				error = node->AddReference();
950				if (error == B_OK) {
951					// delete the original entry
952					error = oldDir->DeleteEntry(entry);
953					if (error == B_OK) {
954						// create the new one/relink the target entry
955						if (clobberEntry)
956							error = clobberEntry->Link(node);
957						else
958							error = newDir->CreateEntry(node, newName);
959
960						if (error == B_OK) {
961							// send a "removed" notification for the clobbered
962							// entry
963							if (clobberEntry) {
964								notify_listener(B_ENTRY_REMOVED,
965									volume->GetID(), newDir->GetID(), 0,
966									clobberNode->GetID(), newName);
967							}
968						} else {
969							// try to recreate the original entry, in case of
970							// failure
971							newDir->CreateEntry(node, oldName);
972						}
973					}
974					node->RemoveReference();
975				}
976			}
977
978			// release the entries
979			if (clobberEntry)
980				volume->PutVNode(clobberNode);
981			if (entry)
982				volume->PutVNode(node);
983		}
984
985		// notify listeners
986		if (error == B_OK) {
987			notify_listener(B_ENTRY_MOVED, volume->GetID(), oldDir->GetID(),
988							newDir->GetID(), node->GetID(), newName);
989		}
990	} else
991		SET_ERROR(error, B_ERROR);
992
993	RETURN_ERROR(error);
994}
995
996// ramfs_link
997static
998int
999ramfs_link(void *ns, void *_dir, const char *name, void *_node)
1000{
1001	FUNCTION(("name: `%s'\n", name));
1002	Volume *volume = (Volume*)ns;
1003	Directory *dir = dynamic_cast<Directory*>((Node*)_dir);
1004	Node *node = (Node*)_node;
1005	status_t error = B_OK;
1006	// check directory
1007	if (!dir) {
1008		SET_ERROR(error, B_BAD_VALUE);
1009	} else if (VolumeWriteLocker locker = volume) {
1010		NodeMTimeUpdater mTimeUpdater(dir);
1011		// directory deleted?
1012		if (is_vnode_removed(volume->GetID(), dir->GetID()) > 0)
1013			SET_ERROR(error, B_NOT_ALLOWED);
1014		// check directory write permissions
1015		error = dir->CheckPermissions(ACCESS_W);
1016		Entry *entry = NULL;
1017		if (error == B_OK) {
1018			// check if entry does already exist
1019			if (dir->FindEntry(name, &entry) == B_OK) {
1020				SET_ERROR(error, B_FILE_EXISTS);
1021			} else {
1022				// entry doesn't exist: create a link
1023				error = dir->CreateEntry(node, name);
1024			}
1025		}
1026		// notify listeners
1027		if (error == B_OK) {
1028			notify_listener(B_ENTRY_CREATED, volume->GetID(), dir->GetID(), 0,
1029							node->GetID(), name);
1030		}
1031	} else
1032		SET_ERROR(error, B_ERROR);
1033	RETURN_ERROR(error);
1034}
1035
1036// ramfs_unlink
1037static
1038int
1039ramfs_unlink(void *ns, void *_dir, const char *name)
1040{
1041	FUNCTION(("name: `%s'\n", name));
1042	Volume *volume = (Volume*)ns;
1043	Directory *dir = dynamic_cast<Directory*>((Node*)_dir);
1044	status_t error = B_OK;
1045	// check name
1046	if (!name || *name == '\0' || !strcmp(name, ".") || !strcmp(name, "..")) {
1047		SET_ERROR(error, B_BAD_VALUE);
1048	// check node
1049	} else if (!dir) {
1050		SET_ERROR(error, B_BAD_VALUE);
1051	} else if (VolumeWriteLocker locker = volume) {
1052		NodeMTimeUpdater mTimeUpdater(dir);
1053		// check directory write permissions
1054		error = dir->CheckPermissions(ACCESS_W);
1055		vnode_id nodeID = -1;
1056		if (error == B_OK) {
1057			// check if entry exists
1058			Node *node = NULL;
1059			Entry *entry = NULL;
1060			if (dir->FindAndGetNode(name, &node, &entry) == B_OK) {
1061				nodeID = node->GetID();
1062				// unlink the entry, if it isn't a non-empty directory
1063				if (node->IsDirectory()
1064					&& !dynamic_cast<Directory*>(node)->IsEmpty()) {
1065					SET_ERROR(error, B_DIRECTORY_NOT_EMPTY);
1066				} else
1067					error = dir->DeleteEntry(entry);
1068				volume->PutVNode(node);
1069			} else
1070				SET_ERROR(error, B_ENTRY_NOT_FOUND);
1071		}
1072		// notify listeners
1073		if (error == B_OK) {
1074			notify_listener(B_ENTRY_REMOVED, volume->GetID(), dir->GetID(), 0,
1075							nodeID, NULL);
1076		}
1077	} else
1078		SET_ERROR(error, B_ERROR);
1079	RETURN_ERROR(error);
1080}
1081
1082// ramfs_rmdir
1083static
1084int
1085ramfs_rmdir(void *ns, void *_dir, const char *name)
1086{
1087	FUNCTION(("name: `%s'\n", name));
1088	Volume *volume = (Volume*)ns;
1089	Directory *dir = dynamic_cast<Directory*>((Node*)_dir);
1090	status_t error = B_OK;
1091	// check name
1092	if (!name || *name == '\0' || !strcmp(name, ".") || !strcmp(name, "..")) {
1093		SET_ERROR(error, B_BAD_VALUE);
1094	// check node
1095	} else if (!dir) {
1096		SET_ERROR(error, B_BAD_VALUE);
1097	} else if (VolumeWriteLocker locker = volume) {
1098		NodeMTimeUpdater mTimeUpdater(dir);
1099		// check directory write permissions
1100		error = dir->CheckPermissions(ACCESS_W);
1101		vnode_id nodeID = -1;
1102		if (error == B_OK) {
1103			// check if entry exists
1104			Node *node = NULL;
1105			Entry *entry = NULL;
1106			if (dir->FindAndGetNode(name, &node, &entry) == B_OK) {
1107				nodeID = node->GetID();
1108				if (!node->IsDirectory()) {
1109					SET_ERROR(error, B_NOT_A_DIRECTORY);
1110				} else if (!dynamic_cast<Directory*>(node)->IsEmpty()) {
1111					SET_ERROR(error, B_DIRECTORY_NOT_EMPTY);
1112				} else
1113					error = dir->DeleteEntry(entry);
1114				volume->PutVNode(node);
1115			} else
1116				SET_ERROR(error, B_ENTRY_NOT_FOUND);
1117		}
1118		// notify listeners
1119		if (error == B_OK) {
1120			notify_listener(B_ENTRY_REMOVED, volume->GetID(), dir->GetID(), 0,
1121							nodeID, NULL);
1122		}
1123	} else
1124		SET_ERROR(error, B_ERROR);
1125	RETURN_ERROR(error);
1126}
1127
1128// DirectoryCookie
1129class DirectoryCookie {
1130public:
1131	DirectoryCookie(Directory *directory = NULL)
1132		: fIterator(directory),
1133		  fDotIndex(DOT_INDEX),
1134		  // debugging
1135		  fIteratorID(atomic_add(&fNextIteratorID, 1)),
1136		  fGetNextCounter(0)
1137	{
1138	}
1139
1140	void Unset() { fIterator.Unset(); }
1141
1142//	EntryIterator *GetIterator() const { return &fIterator; }
1143
1144	status_t GetNext(ino_t *nodeID, const char **entryName)
1145	{
1146fGetNextCounter++;
1147		status_t error = B_OK;
1148		if (fDotIndex == DOT_INDEX) {
1149			// "."
1150			Node *entry = fIterator.GetDirectory();
1151			*nodeID = entry->GetID();
1152			*entryName = ".";
1153			fDotIndex++;
1154		} else if (fDotIndex == DOT_DOT_INDEX) {
1155			// ".."
1156			Directory *dir = fIterator.GetDirectory();
1157			if (dir->GetParent())
1158				*nodeID = dir->GetParent()->GetID();
1159			else
1160				*nodeID = dir->GetID();
1161			*entryName = "..";
1162			fDotIndex++;
1163		} else {
1164			// ordinary entries
1165			Entry *entry = NULL;
1166			error = fIterator.GetNext(&entry);
1167			if (error == B_OK) {
1168				*nodeID = entry->GetNode()->GetID();
1169				*entryName = entry->GetName();
1170			}
1171		}
1172PRINT(("EntryIterator %ld, GetNext() counter: %ld, entry: %p (%Ld)\n",
1173fIteratorID, fGetNextCounter, fIterator.GetCurrent(),
1174(fIterator.GetCurrent() ? fIterator.GetCurrent()->GetNode()->GetID() : -1)));
1175		return error;
1176	}
1177
1178	status_t Rewind()
1179	{
1180		fDotIndex = DOT_INDEX;
1181		return fIterator.Rewind();
1182	}
1183
1184	status_t Suspend() { return fIterator.Suspend(); }
1185	status_t Resume() { return fIterator.Resume(); }
1186
1187private:
1188	enum {
1189		DOT_INDEX		= 0,
1190		DOT_DOT_INDEX	= 1,
1191		ENTRY_INDEX		= 2,
1192	};
1193
1194private:
1195	EntryIterator	fIterator;
1196	uint32			fDotIndex;
1197
1198	// debugging
1199	int32			fIteratorID;
1200	int32			fGetNextCounter;
1201	static vint32	fNextIteratorID;
1202};
1203vint32 DirectoryCookie::fNextIteratorID = 0;
1204
1205// ramfs_mkdir
1206static
1207int
1208ramfs_mkdir(void *ns, void *_dir, const char *name, int mode)
1209{
1210	FUNCTION(("name: `%s', mode: %x\n", name, mode));
1211	Volume *volume = (Volume*)ns;
1212	Directory *dir = dynamic_cast<Directory*>((Node*)_dir);
1213	status_t error = B_OK;
1214	// check name
1215	if (!name || *name == '\0') {
1216		SET_ERROR(error, B_BAD_VALUE);
1217	// check directory
1218	} else if (!dir) {
1219		SET_ERROR(error, B_BAD_VALUE);
1220	} else if (VolumeWriteLocker locker = volume) {
1221		NodeMTimeUpdater mTimeUpdater(dir);
1222		// directory deleted?
1223		if (is_vnode_removed(volume->GetID(), dir->GetID()) > 0)
1224			SET_ERROR(error, B_NOT_ALLOWED);
1225		// check directory write permissions
1226		error = dir->CheckPermissions(ACCESS_W);
1227		Node *node = NULL;
1228		if (error == B_OK) {
1229			// check if entry does already exist
1230			if (dir->FindNode(name, &node) == B_OK) {
1231				SET_ERROR(error, B_FILE_EXISTS);
1232			} else {
1233				// entry doesn't exist: create a directory
1234				Directory *newDir = NULL;
1235				error = dir->CreateDirectory(name, &newDir);
1236				if (error == B_OK) {
1237					node = newDir;
1238					// set permissions, owner and group
1239					node->SetMode(mode);
1240					node->SetUID(geteuid());
1241					node->SetGID(getegid());
1242					// put the node
1243					volume->PutVNode(node->GetID());
1244				}
1245			}
1246		}
1247		NodeMTimeUpdater mTimeUpdater2(node);
1248		// notify listeners
1249		if (error == B_OK) {
1250			notify_listener(B_ENTRY_CREATED, volume->GetID(), dir->GetID(), 0,
1251							node->GetID(), name);
1252		}
1253	} else
1254		SET_ERROR(error, B_ERROR);
1255	RETURN_ERROR(error);
1256}
1257
1258// ramfs_open_dir
1259static
1260int
1261ramfs_open_dir(void */*ns*/, void *_node, void **_cookie)
1262{
1263//	FUNCTION_START();
1264//	Volume *volume = (Volume*)ns;
1265	Node *node = (Node*)_node;
1266FUNCTION(("dir: (%Lu)\n", node->GetID()));
1267	// get the Directory
1268	status_t error = (node->IsDirectory() ? B_OK : B_BAD_VALUE);
1269	Directory *dir = NULL;
1270	if (error == B_OK) {
1271		dir = dynamic_cast<Directory*>(node);
1272		if (!dir) {
1273			FATAL(("Node %Ld pretends to be a Directory, but isn't!\n",
1274				   node->GetID()));
1275			error = B_BAD_VALUE;
1276		}
1277	}
1278	// create a DirectoryCookie
1279	if (error == B_OK) {
1280		DirectoryCookie *cookie = new(std::nothrow) DirectoryCookie(dir);
1281		if (cookie) {
1282			error = cookie->Suspend();
1283			if (error == B_OK)
1284				*_cookie = cookie;
1285			else
1286				delete cookie;
1287		} else
1288			SET_ERROR(error, B_NO_MEMORY);
1289	}
1290	FUNCTION_END();
1291	RETURN_ERROR(error);
1292}
1293
1294// ramfs_read_dir
1295static
1296int
1297ramfs_read_dir(void *ns, void *DARG(_node), void *_cookie, long *count,
1298			   struct dirent *buffer, size_t bufferSize)
1299{
1300	FUNCTION_START();
1301	Volume *volume = (Volume*)ns;
1302DARG(Node *node = (Node*)_node; )
1303FUNCTION(("dir: (%Lu)\n", node->GetID()));
1304	DirectoryCookie *cookie = (DirectoryCookie*)_cookie;
1305	status_t error = B_OK;
1306	if (VolumeReadLocker locker = volume) {
1307		error = cookie->Resume();
1308		if (error == B_OK) {
1309			// read one entry
1310			ino_t nodeID = -1;
1311			const char *name = NULL;
1312			if (cookie->GetNext(&nodeID, &name) == B_OK) {
1313PRINT(("  entry: `%s'\n", name));
1314				size_t nameLen = strlen(name);
1315				// check, whether the entry fits into the buffer,
1316				// and fill it in
1317				size_t length = (buffer->d_name + nameLen + 1) - (char*)buffer;
1318				if (length <= bufferSize) {
1319					buffer->d_dev = volume->GetID();
1320					buffer->d_ino = nodeID;
1321					memcpy(buffer->d_name, name, nameLen);
1322					buffer->d_name[nameLen] = '\0';
1323#if KEEP_WRONG_DIRENT_RECLEN
1324					buffer->d_reclen = nameLen;
1325#else
1326					buffer->d_reclen = length;
1327#endif
1328					*count = 1;
1329				} else {
1330					SET_ERROR(error, B_BUFFER_OVERFLOW);
1331				}
1332	 		} else
1333	 			*count = 0;
1334	 		cookie->Suspend();
1335		}
1336	} else
1337		SET_ERROR(error, B_ERROR);
1338	RETURN_ERROR(error);
1339}
1340
1341// ramfs_rewind_dir
1342static
1343int
1344ramfs_rewind_dir(void */*ns*/, void */*_node*/, void *_cookie)
1345{
1346	FUNCTION_START();
1347	// No locking needed, since the Directory is guaranteed to live at this
1348	// time and for iterators there is a separate locking.
1349	DirectoryCookie *cookie = (DirectoryCookie*)_cookie;
1350	// no need to Resume(), iterator remains suspended
1351	status_t error = cookie->Rewind();
1352	RETURN_ERROR(error);
1353}
1354
1355// ramfs_close_dir
1356static
1357int
1358ramfs_close_dir(void */*ns*/, void *DARG(_node), void *_cookie)
1359{
1360	FUNCTION_START();
1361FUNCTION(("dir: (%Lu)\n", ((Node*)_node)->GetID()));
1362	// No locking needed, since the Directory is guaranteed to live at this
1363	// time and for iterators there is a separate locking.
1364	DirectoryCookie *cookie = (DirectoryCookie*)_cookie;
1365	cookie->Unset();
1366	return B_OK;
1367}
1368
1369// ramfs_free_dir_cookie
1370static
1371int
1372ramfs_free_dir_cookie(void */*ns*/, void */*_node*/, void *_cookie)
1373{
1374	FUNCTION_START();
1375	DirectoryCookie *cookie = (DirectoryCookie*)_cookie;
1376	delete cookie;
1377	return B_OK;
1378}
1379
1380
1381// #pragma mark - FS Stats
1382
1383
1384// ramfs_read_fs_stat
1385static
1386int
1387ramfs_read_fs_stat(void *ns, struct fs_info *info)
1388{
1389	FUNCTION_START();
1390	Volume *volume = (Volume*)ns;
1391	status_t error = B_OK;
1392	if (VolumeReadLocker locker = volume) {
1393		info->flags = B_FS_IS_PERSISTENT | B_FS_HAS_ATTR | B_FS_HAS_MIME
1394					  | B_FS_HAS_QUERY;
1395		info->block_size = volume->GetBlockSize();
1396		info->io_size = kOptimalIOSize;
1397		info->total_blocks = volume->CountBlocks();
1398		info->free_blocks = volume->CountFreeBlocks();
1399		info->device_name[0] = '\0';
1400		strncpy(info->volume_name, volume->GetName(), sizeof(info->volume_name));
1401		strcpy(info->fsh_name, kFSName);
1402	} else
1403		SET_ERROR(error, B_ERROR);
1404	return B_OK;
1405}
1406
1407
1408// ramfs_write_fs_stat
1409static
1410int
1411ramfs_write_fs_stat(void *ns, struct fs_info *info, long mask)
1412{
1413	FUNCTION_START();
1414	Volume *volume = (Volume*)ns;
1415	status_t error = B_OK;
1416	if (VolumeWriteLocker locker = volume) {
1417		if (mask & WFSSTAT_NAME)
1418			error = volume->SetName(info->volume_name);
1419	} else
1420		SET_ERROR(error, B_ERROR);
1421	RETURN_ERROR(error);
1422}
1423
1424
1425// #pragma mark - Symlinks
1426
1427
1428// ramfs_symlink
1429static
1430int
1431ramfs_symlink(void *ns, void *_dir, const char *name, const char *path)
1432{
1433	FUNCTION(("name: `%s', path: `%s'\n", name, path));
1434	Volume *volume = (Volume*)ns;
1435	Directory *dir = dynamic_cast<Directory*>((Node*)_dir);
1436	status_t error = B_OK;
1437	// check name
1438	if (!name || *name == '\0') {
1439		SET_ERROR(error, B_BAD_VALUE);
1440	// check directory
1441	} else if (!dir) {
1442		SET_ERROR(error, B_BAD_VALUE);
1443	} else if (VolumeWriteLocker locker = volume) {
1444		NodeMTimeUpdater mTimeUpdater(dir);
1445		// directory deleted?
1446		if (is_vnode_removed(volume->GetID(), dir->GetID()) > 0)
1447			SET_ERROR(error, B_NOT_ALLOWED);
1448		// check directory write permissions
1449		error = dir->CheckPermissions(ACCESS_W);
1450		Node *node = NULL;
1451		if (error == B_OK) {
1452			// check if entry does already exist
1453			if (dir->FindNode(name, &node) == B_OK) {
1454				SET_ERROR(error, B_FILE_EXISTS);
1455			} else {
1456				// entry doesn't exist: create a symlink
1457				SymLink *symLink = NULL;
1458				error = dir->CreateSymLink(name, path, &symLink);
1459				if (error == B_OK) {
1460					node = symLink;
1461					// set permissions, owner and group
1462					node->SetMode(S_IRWXU | S_IRWXG | S_IRWXO);
1463					node->SetUID(geteuid());
1464					node->SetGID(getegid());
1465					// put the node
1466					volume->PutVNode(node->GetID());
1467				}
1468			}
1469		}
1470		NodeMTimeUpdater mTimeUpdater2(node);
1471		// notify listeners
1472		if (error == B_OK) {
1473			notify_listener(B_ENTRY_CREATED, volume->GetID(), dir->GetID(), 0,
1474							node->GetID(), name);
1475		}
1476	} else
1477		SET_ERROR(error, B_ERROR);
1478	RETURN_ERROR(error);
1479}
1480
1481// ramfs_read_link
1482static
1483int
1484ramfs_read_link(void *ns, void *_node, char *buffer, size_t *bufferSize)
1485{
1486	FUNCTION_START();
1487	Volume *volume = (Volume*)ns;
1488	Node *node = (Node*)_node;
1489	status_t error = B_OK;
1490	if (VolumeReadLocker locker = volume) {
1491		// read symlinks only
1492		if (!node->IsSymLink())
1493			error = B_BAD_VALUE;
1494		if (error == B_OK) {
1495			if (SymLink *symLink = dynamic_cast<SymLink*>(node)) {
1496				// copy the link contents
1497				size_t toRead = min(*bufferSize,
1498									symLink->GetLinkedPathLength());
1499				if (toRead > 0)
1500					memcpy(buffer, symLink->GetLinkedPath(), toRead);
1501				*bufferSize = toRead;
1502			} else {
1503				FATAL(("Node %Ld pretends to be a SymLink, but isn't!\n",
1504					   node->GetID()));
1505				error = B_BAD_VALUE;
1506			}
1507		}
1508	} else
1509		SET_ERROR(error, B_ERROR);
1510	RETURN_ERROR(error);
1511}
1512
1513
1514// #pragma mark - Attributes
1515
1516
1517// ramfs_open_attrdir
1518static
1519int
1520ramfs_open_attrdir(void *ns, void *_node, void **cookie)
1521{
1522	FUNCTION_START();
1523	Volume *volume = (Volume*)ns;
1524	Node *node = (Node*)_node;
1525	status_t error = B_OK;
1526	if (VolumeReadLocker locker = volume) {
1527		// check permissions
1528		error = node->CheckPermissions(ACCESS_R);
1529		// create iterator
1530		AttributeIterator *iterator = NULL;
1531		if (error == B_OK) {
1532			iterator = new(std::nothrow) AttributeIterator(node);
1533			if (iterator)
1534				error = iterator->Suspend();
1535			else
1536				SET_ERROR(error, B_NO_MEMORY);
1537		}
1538		// set result / cleanup on failure
1539		if (error == B_OK)
1540			*cookie = iterator;
1541		else
1542			delete iterator;
1543	} else
1544		SET_ERROR(error, B_ERROR);
1545	RETURN_ERROR(error);
1546}
1547
1548// ramfs_close_attrdir
1549static
1550int
1551ramfs_close_attrdir(void */*ns*/, void */*_node*/, void *cookie)
1552{
1553	FUNCTION_START();
1554	// No locking needed, since the Node is guaranteed to live at this time
1555	// and for iterators there is a separate locking.
1556	AttributeIterator *iterator = (AttributeIterator*)cookie;
1557	iterator->Unset();
1558	return B_OK;
1559}
1560
1561// ramfs_free_attrdir_cookie
1562static
1563int
1564ramfs_free_attrdir_cookie(void */*ns*/, void */*_node*/, void *cookie)
1565{
1566	FUNCTION_START();
1567	// No locking needed, since the Node is guaranteed to live at this time
1568	// and for iterators there is a separate locking.
1569	AttributeIterator *iterator = (AttributeIterator*)cookie;
1570	delete iterator;
1571	return B_OK;
1572}
1573
1574// ramfs_rewind_attrdir
1575static
1576int
1577ramfs_rewind_attrdir(void */*ns*/, void */*_node*/, void *cookie)
1578{
1579	FUNCTION_START();
1580	// No locking needed, since the Node is guaranteed to live at this time
1581	// and for iterators there is a separate locking.
1582	AttributeIterator *iterator = (AttributeIterator*)cookie;
1583	// no need to Resume(), iterator remains suspended
1584	status_t error = iterator->Rewind();
1585	RETURN_ERROR(error);
1586}
1587
1588// ramfs_read_attrdir
1589static
1590int
1591ramfs_read_attrdir(void *ns, void */*_node*/, void *cookie, long *count,
1592				   struct dirent *buffer, size_t bufferSize)
1593{
1594	FUNCTION_START();
1595	Volume *volume = (Volume*)ns;
1596	AttributeIterator *iterator = (AttributeIterator*)cookie;
1597	status_t error = B_OK;
1598	if (VolumeReadLocker locker = volume) {
1599		error = iterator->Resume();
1600		if (error == B_OK) {
1601			// get next attribute
1602			Attribute *attribute = NULL;
1603			if (iterator->GetNext(&attribute) == B_OK) {
1604				const char *name = attribute->GetName();
1605				size_t nameLen = strlen(name);
1606				// check, whether the entry fits into the buffer,
1607				// and fill it in
1608				size_t length = (buffer->d_name + nameLen + 1) - (char*)buffer;
1609				if (length <= bufferSize) {
1610					buffer->d_dev = volume->GetID();
1611					buffer->d_ino = -1;	// attributes don't have a node ID
1612					memcpy(buffer->d_name, name, nameLen);
1613					buffer->d_name[nameLen] = '\0';
1614#if KEEP_WRONG_DIRENT_RECLEN
1615					buffer->d_reclen = nameLen;
1616#else
1617					buffer->d_reclen = length;
1618#endif
1619					*count = 1;
1620				} else {
1621					SET_ERROR(error, B_BUFFER_OVERFLOW);
1622				}
1623			} else
1624				*count = 0;
1625	 		iterator->Suspend();
1626		}
1627	} else
1628		SET_ERROR(error, B_ERROR);
1629	RETURN_ERROR(error);
1630}
1631
1632// ramfs_write_attr
1633static
1634int
1635ramfs_write_attr(void *ns, void *_node, const char *name, int type,
1636				 const void *buffer, size_t *bufferSize, off_t pos)
1637{
1638//	FUNCTION_START();
1639	Volume *volume = (Volume*)ns;
1640	Node *node = (Node*)_node;
1641	status_t error = B_OK;
1642	// Don't allow writing the reserved attributes.
1643	if (name[0] == '\0' || !strcmp(name, "name")
1644		|| !strcmp(name, "last_modified") || !strcmp(name, "size")) {
1645//FUNCTION(("failed: node: %s, attribute: %s\n", node->GetName(), name));
1646		error = B_NOT_ALLOWED;
1647	} else if (VolumeWriteLocker locker = volume) {
1648		NodeMTimeUpdater mTimeUpdater(node);
1649		// check permissions
1650		error = node->CheckPermissions(ACCESS_W);
1651		// find the attribute or create it, if it doesn't exist yet
1652		Attribute *attribute = NULL;
1653		if (error == B_OK && node->FindAttribute(name, &attribute) != B_OK)
1654			error = node->CreateAttribute(name, &attribute);
1655REPORT_ERROR(error);
1656		// set the new type and write the data
1657		if (error == B_OK) {
1658			attribute->SetType(type);
1659			error = attribute->WriteAt(pos, buffer, *bufferSize, bufferSize);
1660REPORT_ERROR(error);
1661		}
1662		// notify listeners
1663		if (error == B_OK) {
1664			notify_listener(B_ATTR_CHANGED, volume->GetID(), 0, 0,
1665							node->GetID(), name);
1666		}
1667	} else
1668		SET_ERROR(error, B_ERROR);
1669	RETURN_ERROR(error);
1670}
1671
1672// ramfs_read_attr
1673static
1674int
1675ramfs_read_attr(void *ns, void *_node, const char *name, int /*type*/,
1676				void *buffer, size_t *bufferSize, off_t pos)
1677{
1678//	FUNCTION_START();
1679	Volume *volume = (Volume*)ns;
1680	Node *node = (Node*)_node;
1681	status_t error = B_OK;
1682	if (VolumeReadLocker locker = volume) {
1683		// check permissions
1684		error = node->CheckPermissions(ACCESS_R);
1685		// find the attribute
1686		Attribute *attribute = NULL;
1687		if (error == B_OK)
1688			error = node->FindAttribute(name, &attribute);
1689		// read
1690		if (error == B_OK)
1691			error = attribute->ReadAt(pos, buffer, *bufferSize, bufferSize);
1692	} else
1693		SET_ERROR(error, B_ERROR);
1694	RETURN_ERROR(error);
1695}
1696
1697// ramfs_remove_attr
1698static
1699int
1700ramfs_remove_attr(void *ns, void *_node, const char *name)
1701{
1702	FUNCTION_START();
1703	Volume *volume = (Volume*)ns;
1704	Node *node = (Node*)_node;
1705	status_t error = B_OK;
1706	if (VolumeWriteLocker locker = volume) {
1707		NodeMTimeUpdater mTimeUpdater(node);
1708		// check permissions
1709		error = node->CheckPermissions(ACCESS_W);
1710		// find the attribute
1711		Attribute *attribute = NULL;
1712		if (error == B_OK)
1713			error = node->FindAttribute(name, &attribute);
1714		// delete it
1715		if (error == B_OK)
1716			error = node->DeleteAttribute(attribute);
1717		// notify listeners
1718		if (error == B_OK) {
1719			notify_listener(B_ATTR_CHANGED, volume->GetID(), 0, 0,
1720							node->GetID(), name);
1721		}
1722	} else
1723		SET_ERROR(error, B_ERROR);
1724	RETURN_ERROR(error);
1725}
1726
1727// ramfs_rename_attr
1728static
1729int
1730ramfs_rename_attr(void */*ns*/, void */*_node*/, const char */*oldName*/,
1731				  const char */*newName*/)
1732{
1733	// TODO:...
1734	return B_ENTRY_NOT_FOUND;
1735}
1736
1737// ramfs_stat_attr
1738static
1739int
1740ramfs_stat_attr(void *ns, void *_node, const char *name,
1741				struct attr_info *attrInfo)
1742{
1743//	FUNCTION_START();
1744	Volume *volume = (Volume*)ns;
1745	Node *node = (Node*)_node;
1746	status_t error = B_OK;
1747	if (VolumeReadLocker locker = volume) {
1748		// check permissions
1749		error = node->CheckPermissions(ACCESS_R);
1750		// find the attribute
1751		Attribute *attribute = NULL;
1752		if (error == B_OK)
1753			error = node->FindAttribute(name, &attribute);
1754		// read
1755		if (error == B_OK) {
1756			attrInfo->type = attribute->GetType();
1757			attrInfo->size = attribute->GetSize();
1758		}
1759	} else
1760		SET_ERROR(error, B_ERROR);
1761	RETURN_ERROR(error);
1762}
1763
1764
1765// #pragma mark - Indices
1766
1767
1768// IndexDirCookie
1769class IndexDirCookie {
1770public:
1771	IndexDirCookie() : index_index(0) {}
1772
1773	int32	index_index;
1774};
1775
1776// ramfs_open_indexdir
1777static
1778int
1779ramfs_open_indexdir(void *ns, void **_cookie)
1780{
1781	FUNCTION_START();
1782	Volume *volume = (Volume*)ns;
1783	status_t error = B_OK;
1784	if (VolumeReadLocker locker = volume) {
1785		// check whether an index directory exists
1786		if (volume->GetIndexDirectory()) {
1787			IndexDirCookie *cookie = new(std::nothrow) IndexDirCookie;
1788			if (cookie)
1789				*_cookie = cookie;
1790			else
1791				SET_ERROR(error, B_NO_MEMORY);
1792		} else
1793			SET_ERROR(error, B_ENTRY_NOT_FOUND);
1794	} else
1795		SET_ERROR(error, B_ERROR);
1796	RETURN_ERROR(error);
1797}
1798
1799// ramfs_close_indexdir
1800static
1801int
1802ramfs_close_indexdir(void */*ns*/, void */*_cookie*/)
1803{
1804	FUNCTION_START();
1805	return B_OK;
1806}
1807
1808// ramfs_free_indexdir_cookie
1809static
1810int
1811ramfs_free_indexdir_cookie(void */*ns*/, void */*_node*/, void *_cookie)
1812{
1813	FUNCTION_START();
1814	IndexDirCookie *cookie = (IndexDirCookie*)_cookie;
1815	delete cookie;
1816	return B_OK;
1817}
1818
1819// ramfs_rewind_indexdir
1820static
1821int
1822ramfs_rewind_indexdir(void */*_ns*/, void *_cookie)
1823{
1824	FUNCTION_START();
1825	IndexDirCookie *cookie = (IndexDirCookie*)_cookie;
1826	cookie->index_index = 0;
1827	return B_OK;
1828}
1829
1830// ramfs_read_indexdir
1831static
1832int
1833ramfs_read_indexdir(void *ns, void *_cookie, long *count,
1834					struct dirent *buffer, size_t bufferSize)
1835{
1836	FUNCTION_START();
1837	Volume *volume = (Volume*)ns;
1838	IndexDirCookie *cookie = (IndexDirCookie*)_cookie;
1839	status_t error = B_OK;
1840	if (VolumeReadLocker locker = volume) {
1841		// get the next index
1842		Index *index = volume->GetIndexDirectory()->IndexAt(
1843			cookie->index_index++);
1844		if (index) {
1845			const char *name = index->GetName();
1846			size_t nameLen = strlen(name);
1847			// check, whether the entry fits into the buffer,
1848			// and fill it in
1849			size_t length = (buffer->d_name + nameLen + 1) - (char*)buffer;
1850			if (length <= bufferSize) {
1851				buffer->d_dev = volume->GetID();
1852				buffer->d_ino = -1;	// indices don't have a node ID
1853				memcpy(buffer->d_name, name, nameLen);
1854				buffer->d_name[nameLen] = '\0';
1855#if KEEP_WRONG_DIRENT_RECLEN
1856				buffer->d_reclen = nameLen;
1857#else
1858				buffer->d_reclen = length;
1859#endif
1860				*count = 1;
1861			} else {
1862				SET_ERROR(error, B_BUFFER_OVERFLOW);
1863			}
1864		} else
1865			*count = 0;
1866	} else
1867		SET_ERROR(error, B_ERROR);
1868	RETURN_ERROR(error);
1869}
1870
1871// ramfs_create_index
1872static
1873int
1874ramfs_create_index(void *ns, const char *name, int type, int /*flags*/)
1875{
1876	FUNCTION_START();
1877	Volume *volume = (Volume*)ns;
1878	status_t error = B_OK;
1879	// only root is allowed to manipulate the indices
1880	if (geteuid() != 0) {
1881		SET_ERROR(error, B_NOT_ALLOWED);
1882	} else if (VolumeWriteLocker locker = volume) {
1883		// get the index directory
1884		if (IndexDirectory *indexDir = volume->GetIndexDirectory()) {
1885			// check whether an index with that name does already exist
1886			if (indexDir->FindIndex(name)) {
1887				SET_ERROR(error, B_FILE_EXISTS);
1888			} else {
1889				// create the index
1890				AttributeIndex *index;
1891				error = indexDir->CreateIndex(name, type, &index);
1892			}
1893		} else
1894			SET_ERROR(error, B_ENTRY_NOT_FOUND);
1895	} else
1896		SET_ERROR(error, B_ERROR);
1897	RETURN_ERROR(error);
1898}
1899
1900// ramfs_remove_index
1901static
1902int
1903ramfs_remove_index(void *ns, const char *name)
1904{
1905	FUNCTION_START();
1906	Volume *volume = (Volume*)ns;
1907	status_t error = B_OK;
1908	// only root is allowed to manipulate the indices
1909	if (geteuid() != 0) {
1910		SET_ERROR(error, B_NOT_ALLOWED);
1911	} else if (VolumeWriteLocker locker = volume) {
1912		// get the index directory
1913		if (IndexDirectory *indexDir = volume->GetIndexDirectory()) {
1914			// check whether an index with that name does exist
1915			if (Index *index = indexDir->FindIndex(name)) {
1916				// don't delete a special index
1917				if (indexDir->IsSpecialIndex(index)) {
1918					SET_ERROR(error, B_BAD_VALUE);
1919				} else
1920					indexDir->DeleteIndex(index);
1921			} else
1922				SET_ERROR(error, B_ENTRY_NOT_FOUND);
1923		} else
1924			SET_ERROR(error, B_ENTRY_NOT_FOUND);
1925	} else
1926		SET_ERROR(error, B_ERROR);
1927	RETURN_ERROR(error);
1928}
1929
1930// ramfs_rename_index
1931static
1932int
1933ramfs_rename_index(void */*ns*/, const char */*oldname*/,
1934				   const char */*newname*/)
1935{
1936	FUNCTION_START();
1937	return B_ERROR;
1938}
1939
1940// ramfs_stat_index
1941static
1942int
1943ramfs_stat_index(void *ns, const char *name, struct index_info *indexInfo)
1944{
1945	FUNCTION_START();
1946	Volume *volume = (Volume*)ns;
1947	status_t error = B_OK;
1948	if (VolumeReadLocker locker = volume) {
1949		// get the index directory
1950		if (IndexDirectory *indexDir = volume->GetIndexDirectory()) {
1951			// find the index
1952			if (Index *index = indexDir->FindIndex(name)) {
1953				indexInfo->type = index->GetType();
1954				if (index->HasFixedKeyLength())
1955					indexInfo->size = index->GetKeyLength();
1956				else
1957					indexInfo->size = kMaxIndexKeyLength;
1958				indexInfo->modification_time = 0;	// TODO: index times
1959				indexInfo->creation_time = 0;		// ...
1960				indexInfo->uid = 0;		// root owns the indices
1961				indexInfo->gid = 0;		//
1962			} else
1963				SET_ERROR(error, B_ENTRY_NOT_FOUND);
1964		} else
1965			SET_ERROR(error, B_ENTRY_NOT_FOUND);
1966	} else
1967		SET_ERROR(error, B_ERROR);
1968	RETURN_ERROR(error);
1969}
1970
1971
1972// #pragma mark - Queries
1973
1974// Query implementation by Axel Dörfler. Slightly adjusted.
1975
1976// ramfs_open_query
1977int
1978ramfs_open_query(void *ns, const char *queryString, ulong flags, port_id port,
1979				 long token, void **cookie)
1980{
1981	FUNCTION_START();
1982	if (ns == NULL || queryString == NULL || cookie == NULL)
1983		RETURN_ERROR(B_BAD_VALUE);
1984
1985	PRINT(("query = \"%s\", flags = %lu, port_id = %ld, token = %ld\n", queryString, flags, port, token));
1986
1987	Volume *volume = (Volume *)ns;
1988
1989	// lock the volume
1990	VolumeReadLocker locker(volume);
1991	if (!locker.IsLocked())
1992		RETURN_ERROR(B_ERROR);
1993
1994	// parse the query expression
1995	Expression *expression = new Expression((char *)queryString);
1996	if (expression == NULL)
1997		RETURN_ERROR(B_NO_MEMORY);
1998	ObjectDeleter<Expression> expressionDeleter(expression);
1999
2000	if (expression->InitCheck() < B_OK) {
2001		WARN(("Could not parse query, stopped at: \"%s\"\n",
2002			expression->Position()));
2003		RETURN_ERROR(B_BAD_VALUE);
2004	}
2005
2006	// create the query
2007	Query *query = new Query(volume, expression, flags);
2008	if (query == NULL)
2009		RETURN_ERROR(B_NO_MEMORY);
2010	expressionDeleter.Detach();
2011	// TODO: The Query references an Index, but nothing prevents the Index
2012	// from being deleted, while the Query is in existence.
2013
2014	if (flags & B_LIVE_QUERY)
2015		query->SetLiveMode(port, token);
2016
2017	*cookie = (void *)query;
2018
2019	return B_OK;
2020}
2021
2022// ramfs_close_query
2023int
2024ramfs_close_query(void */*ns*/, void */*cookie*/)
2025{
2026	FUNCTION_START();
2027	return B_OK;
2028}
2029
2030// ramfs_free_query_cookie
2031int
2032ramfs_free_query_cookie(void *ns, void */*node*/, void *cookie)
2033{
2034	FUNCTION_START();
2035	if (ns == NULL || cookie == NULL)
2036		RETURN_ERROR(B_BAD_VALUE);
2037
2038	Volume *volume = (Volume *)ns;
2039
2040	// lock the volume
2041	VolumeReadLocker locker(volume);
2042	if (!locker.IsLocked())
2043		RETURN_ERROR(B_ERROR);
2044
2045	Query *query = (Query *)cookie;
2046	Expression *expression = query->GetExpression();
2047	delete query;
2048	delete expression;
2049
2050	return B_OK;
2051}
2052
2053// ramfs_read_query
2054int
2055ramfs_read_query(void *ns, void *cookie, long *count,
2056				 struct dirent *buffer, size_t bufferSize)
2057{
2058	FUNCTION_START();
2059	Query *query = (Query *)cookie;
2060	if (ns == NULL || query == NULL)
2061		RETURN_ERROR(B_BAD_VALUE);
2062
2063	Volume *volume = (Volume *)ns;
2064
2065	// lock the volume
2066	VolumeReadLocker locker(volume);
2067	if (!locker.IsLocked())
2068		RETURN_ERROR(B_ERROR);
2069
2070	status_t status = query->GetNextEntry(buffer, bufferSize);
2071	if (status == B_OK)
2072		*count = 1;
2073	else if (status == B_ENTRY_NOT_FOUND)
2074		*count = 0;
2075	else
2076		return status;
2077
2078	return B_OK;
2079}
2080
2081