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