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