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