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