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