xref: /haiku/src/add-ons/kernel/file_systems/ramfs/kernel_interface.cpp (revision 52c4471a3024d2eb81fe88e2c3982b9f8daa5e56)
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_IS_PERSISTENT | B_FS_HAS_ATTR | B_FS_HAS_MIME
142 			| B_FS_HAS_QUERY | 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: %Ld\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: %Ld\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: %Ld\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: %Ld, old name: `%s', new dir: %Ld, 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: %Ld\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_atime = node->GetATime();
697 		st->st_mtime = node->GetMTime();
698 		st->st_ctime = node->GetCTime();
699 		st->st_crtime = node->GetCrTime();
700 	} else
701 		SET_ERROR(error, B_ERROR);
702 	RETURN_ERROR(error);
703 }
704 
705 
706 // ramfs_write_stat
707 static status_t
708 ramfs_write_stat(fs_volume* _volume, fs_vnode* _node, const struct stat *st,
709 	uint32 mask)
710 {
711 	Volume* volume = (Volume*)_volume->private_volume;
712 	Node* node = (Node*)_node->private_node;
713 
714 	FUNCTION(("mask: %lx\n", mask));
715 	status_t error = B_OK;
716 	if (VolumeWriteLocker locker = volume) {
717 		NodeMTimeUpdater mTimeUpdater(node);
718 		// check permissions
719 		error = node->CheckPermissions(ACCESS_W);
720 		// size
721 		if (error == B_OK && (mask & B_STAT_SIZE))
722 			error = node->SetSize(st->st_size);
723 		if (error == B_OK) {
724 			// permissions
725 			if (mask & B_STAT_MODE) {
726 				node->SetMode((node->GetMode() & ~S_IUMSK)
727 					| (st->st_mode & S_IUMSK));
728 			}
729 			// UID
730 			if (mask & B_STAT_UID)
731 				node->SetUID(st->st_uid);
732 			// GID
733 			if (mask & B_STAT_GID)
734 				node->SetGID(st->st_gid);
735 			// mtime
736 			if (mask & B_STAT_MODIFICATION_TIME)
737 				node->SetMTime(st->st_mtime);
738 			// crtime
739 			if (mask & B_STAT_CREATION_TIME)
740 				node->SetCrTime(st->st_crtime);
741 		}
742 		// notify listeners
743 		if (error == B_OK)
744 			notify_if_stat_changed(volume, node);
745 	} else
746 		SET_ERROR(error, B_ERROR);
747 	RETURN_ERROR(error);
748 }
749 
750 
751 // #pragma mark - Files
752 
753 
754 // FileCookie
755 class FileCookie {
756 public:
757 	FileCookie(int openMode) : fOpenMode(openMode), fLastNotificationTime(0) {}
758 
759 	inline int GetOpenMode() { return fOpenMode; }
760 	inline bigtime_t GetLastNotificationTime() { return fLastNotificationTime; }
761 
762 	inline bool	NotificationIntervalElapsed(bool set = false)
763 	{
764 		bigtime_t currentTime = system_time();
765 		bool result = (currentTime
766 			- fLastNotificationTime > kNotificationInterval);
767 
768 		if (set && result)
769 			fLastNotificationTime = currentTime;
770 
771 		return result;
772 	}
773 
774 private:
775 	int fOpenMode;
776 	bigtime_t fLastNotificationTime;
777 };
778 
779 
780 // ramfs_create
781 static status_t
782 ramfs_create(fs_volume* _volume, fs_vnode* _dir, const char *name, int openMode,
783 	int mode, void** _cookie, ino_t *vnid)
784 {
785 //	FUNCTION_START();
786 	FUNCTION(("name: `%s', open mode: %x, mode: %x\n", name, openMode, mode));
787 	Volume* volume = (Volume*)_volume->private_volume;
788 	Directory* dir = dynamic_cast<Directory*>((Node*)_dir->private_node);
789 
790 	status_t error = B_OK;
791 	// check name
792 	if (!name || *name == '\0') {
793 		SET_ERROR(error, B_BAD_VALUE);
794 	// check directory
795 	} else if (!dir) {
796 		SET_ERROR(error, B_BAD_VALUE);
797 	// check special names
798 	} else if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
799 		SET_ERROR(error, B_FILE_EXISTS);
800 	} else if (VolumeWriteLocker locker = volume) {
801 		NodeMTimeUpdater mTimeUpdater(dir);
802 		// directory deleted?
803 		bool removed;
804 		if (get_vnode_removed(volume->FSVolume(), dir->GetID(), &removed)
805 			!= B_OK || removed) {
806 			SET_ERROR(error, B_NOT_ALLOWED);
807 		}
808 		// create the file cookie
809 		FileCookie *cookie = NULL;
810 		if (error == B_OK) {
811 			cookie = new(nothrow) FileCookie(openMode);
812 			if (!cookie)
813 				SET_ERROR(error, B_NO_MEMORY);
814 		}
815 		Node *node = NULL;
816 		if (error == B_OK) {
817 			// check if entry does already exist
818 			if (dir->FindNode(name, &node) == B_OK) {
819 				// entry does already exist
820 				// fail, if we shall fail, when the file exists
821 				if (openMode & O_EXCL) {
822 					SET_ERROR(error, B_FILE_EXISTS);
823 				// don't create a file over an existing directory or symlink
824 				} else if (!node->IsFile()) {
825 					SET_ERROR(error, B_NOT_ALLOWED);
826 				// the user must have write permission for an existing entry
827 				} else if ((error = node->CheckPermissions(ACCESS_W)) == B_OK) {
828 					// truncate, if requested
829 					if (openMode & O_TRUNC)
830 						error = node->SetSize(0);
831 					// we ignore the supplied permissions in this case
832 					// get vnode
833 					if (error == B_OK) {
834 						*vnid = node->GetID();
835 						error = volume->GetVNode(node->GetID(), &node);
836 					}
837 				}
838 			// the user must have dir write permission to create a new entry
839 			} else if ((error = dir->CheckPermissions(ACCESS_W)) == B_OK) {
840 				// entry doesn't exist: create a file
841 				File *file = NULL;
842 				error = dir->CreateFile(name, &file);
843 				if (error == B_OK) {
844 					node = file;
845 					*vnid = node->GetID();
846 					// set permissions, owner and group
847 					node->SetMode(mode);
848 					node->SetUID(geteuid());
849 					node->SetGID(getegid());
850 
851 					// set cache in vnode
852 					struct vnode* vnode;
853 					if (vfs_lookup_vnode(_volume->id, node->GetID(), &vnode) == B_OK) {
854 						vfs_set_vnode_cache(vnode, file->GetCache());
855 					}
856 				}
857 			}
858 			// set result / cleanup on failure
859 			if (error == B_OK)
860 				*_cookie = cookie;
861 			else if (cookie)
862 				delete cookie;
863 		}
864 		NodeMTimeUpdater mTimeUpdater2(node);
865 		// notify listeners
866 		if (error == B_OK)
867 			notify_entry_created(volume->GetID(), dir->GetID(), name, *vnid);
868 	} else
869 		SET_ERROR(error, B_ERROR);
870 	RETURN_ERROR(error);
871 }
872 
873 
874 // ramfs_open
875 static status_t
876 ramfs_open(fs_volume* _volume, fs_vnode* _node, int openMode, void** _cookie)
877 {
878 //	FUNCTION_START();
879 	Volume* volume = (Volume*)_volume->private_volume;
880 	Node* node = (Node*)_node->private_node;
881 
882 	FUNCTION(("node: %Ld\n", node->GetID()));
883 	status_t error = B_OK;
884 	if (VolumeReadLocker locker = volume) {
885 		// directory can be opened read-only
886 		if (node->IsDirectory() && (openMode & O_RWMASK))
887 			openMode &= ~O_RWMASK;
888 		int accessMode = open_mode_to_access(openMode);
889 		// truncating requires write permission
890 		if (error == B_OK && (openMode & O_TRUNC))
891 			accessMode |= ACCESS_W;
892 		// check open mode against permissions
893 		if (error == B_OK)
894 			error = node->CheckPermissions(accessMode);
895 		// create the cookie
896 		FileCookie *cookie = NULL;
897 		if (error == B_OK) {
898 			cookie = new(nothrow) FileCookie(openMode);
899 			if (!cookie)
900 				SET_ERROR(error, B_NO_MEMORY);
901 		}
902 		// truncate if requested
903 		if (error == B_OK && (openMode & O_TRUNC))
904 			error = node->SetSize(0);
905 		NodeMTimeUpdater mTimeUpdater(node);
906 		// set result / cleanup on failure
907 		if (error == B_OK)
908 			*_cookie = cookie;
909 		else if (cookie)
910 			delete cookie;
911 	} else
912 		SET_ERROR(error, B_ERROR);
913 	RETURN_ERROR(error);
914 }
915 
916 
917 // ramfs_close
918 static status_t
919 ramfs_close(fs_volume* _volume, fs_vnode* _node, void* /*cookie*/)
920 {
921 //	FUNCTION_START();
922 	Volume* volume = (Volume*)_volume->private_volume;
923 	Node* node = (Node*)_node->private_node;
924 
925 	FUNCTION(("node: %Ld\n", node->GetID()));
926 	status_t error = B_OK;
927 	// notify listeners
928 	if (VolumeReadLocker locker = volume) {
929 		notify_if_stat_changed(volume, node);
930 	} else
931 		SET_ERROR(error, B_ERROR);
932 	return error;
933 
934 }
935 
936 
937 // ramfs_free_cookie
938 static status_t
939 ramfs_free_cookie(fs_volume* /*fs*/, fs_vnode* /*_node*/, void* _cookie)
940 {
941 	FUNCTION_START();
942 	FileCookie *cookie = (FileCookie*)_cookie;
943 	delete cookie;
944 	return B_OK;
945 }
946 
947 
948 // ramfs_read
949 static status_t
950 ramfs_read(fs_volume* _volume, fs_vnode* _node, void* _cookie, off_t pos,
951 	void *buffer, size_t *bufferSize)
952 {
953 //	FUNCTION_START();
954 	Volume* volume = (Volume*)_volume->private_volume;
955 	Node* node = (Node*)_node->private_node;
956 	FileCookie *cookie = (FileCookie*)_cookie;
957 
958 //	FUNCTION(("((%lu, %lu), %Ld, %p, %lu)\n", node->GetDirID(),
959 //			  node->GetObjectID(), pos, buffer, *bufferSize));
960 	status_t error = B_OK;
961 	if (VolumeReadLocker locker = volume) {
962 		// don't read anything but files
963 		if (!node->IsFile())
964 			SET_ERROR(error, B_BAD_VALUE);
965 		// check, if reading is allowed
966 		int rwMode = cookie->GetOpenMode() & O_RWMASK;
967 		if (error == B_OK && rwMode != O_RDONLY && rwMode != O_RDWR)
968 			SET_ERROR(error, B_FILE_ERROR);
969 		// read
970 		if (error == B_OK) {
971 			if (File *file = dynamic_cast<File*>(node))
972 				error = file->ReadAt(pos, buffer, *bufferSize, bufferSize);
973 			else {
974 				FATAL("Node %" B_PRIdINO " pretends to be a File, but isn't!\n",
975 					node->GetID());
976 				error = B_BAD_VALUE;
977 			}
978 		}
979 	} else
980 		SET_ERROR(error, B_ERROR);
981 	RETURN_ERROR(error);
982 }
983 
984 
985 // ramfs_write
986 static status_t
987 ramfs_write(fs_volume* _volume, fs_vnode* _node, void* _cookie, off_t pos,
988 	const void *buffer, size_t *bufferSize)
989 {
990 //	FUNCTION_START();
991 	Volume* volume = (Volume*)_volume->private_volume;
992 	Node* node = (Node*)_node->private_node;
993 
994 	FileCookie *cookie = (FileCookie*)_cookie;
995 //	FUNCTION(("((%lu, %lu), %Ld, %p, %lu)\n", node->GetDirID(),
996 //			  node->GetObjectID(), pos, buffer, *bufferSize));
997 	status_t error = B_OK;
998 	if (VolumeWriteLocker locker = volume) {
999 		// don't write anything but files
1000 		if (!node->IsFile())
1001 			SET_ERROR(error, B_BAD_VALUE);
1002 		if (error == B_OK) {
1003 			// check, if reading is allowed
1004 			int rwMode = cookie->GetOpenMode() & O_RWMASK;
1005 			if (error == B_OK && rwMode != O_WRONLY && rwMode != O_RDWR)
1006 				SET_ERROR(error, B_FILE_ERROR);
1007 			if (error == B_OK) {
1008 				// reset the position, if opened in append mode
1009 				if (cookie->GetOpenMode() & O_APPEND)
1010 					pos = node->GetSize();
1011 				// write
1012 				if (File *file = dynamic_cast<File*>(node)) {
1013 					error = file->WriteAt(pos, buffer, *bufferSize,
1014 						bufferSize);
1015 				} else {
1016 					FATAL("Node %" B_PRIdINO " pretends to be a File, but isn't!\n",
1017 						node->GetID());
1018 					error = B_BAD_VALUE;
1019 				}
1020 			}
1021 		}
1022 		// notify listeners
1023 		if (error == B_OK && cookie->NotificationIntervalElapsed(true))
1024 			notify_if_stat_changed(volume, node);
1025 		NodeMTimeUpdater mTimeUpdater(node);
1026 	} else
1027 		SET_ERROR(error, B_ERROR);
1028 	RETURN_ERROR(error);
1029 }
1030 
1031 
1032 // #pragma mark - Directories
1033 
1034 
1035 // DirectoryCookie
1036 class DirectoryCookie {
1037 public:
1038 	DirectoryCookie(Directory *directory = NULL)
1039 		:
1040 		fIterator(directory),
1041 		fDotIndex(DOT_INDEX),
1042 		// debugging
1043 		fIteratorID(atomic_add(&fNextIteratorID, 1)),
1044 		fGetNextCounter(0)
1045 	{
1046 	}
1047 
1048 	void Unset() { fIterator.Unset(); }
1049 
1050 //	EntryIterator *GetIterator() const { return &fIterator; }
1051 
1052 	status_t GetNext(ino_t *nodeID, const char **entryName)
1053 	{
1054 fGetNextCounter++;
1055 		status_t error = B_OK;
1056 		if (fDotIndex == DOT_INDEX) {
1057 			// "."
1058 			Node *entry = fIterator.GetDirectory();
1059 			*nodeID = entry->GetID();
1060 			*entryName = ".";
1061 			fDotIndex++;
1062 		} else if (fDotIndex == DOT_DOT_INDEX) {
1063 			// ".."
1064 			Directory *dir = fIterator.GetDirectory();
1065 			if (dir->GetParent())
1066 				*nodeID = dir->GetParent()->GetID();
1067 			else
1068 				*nodeID = dir->GetID();
1069 			*entryName = "..";
1070 			fDotIndex++;
1071 		} else {
1072 			// ordinary entries
1073 			Entry *entry = NULL;
1074 			error = fIterator.GetNext(&entry);
1075 			if (error == B_OK) {
1076 				*nodeID = entry->GetNode()->GetID();
1077 				*entryName = entry->GetName();
1078 			}
1079 		}
1080 		PRINT("EntryIterator %" B_PRId32 ", GetNext() counter: %" B_PRId32 ", entry: %p (%Ld)\n",
1081 		fIteratorID, fGetNextCounter, fIterator.GetCurrent(),
1082 			(fIterator.GetCurrent()
1083 				? fIterator.GetCurrent()->GetNode()->GetID() : -1));
1084 		return error;
1085 	}
1086 
1087 	status_t Rewind()
1088 	{
1089 		fDotIndex = DOT_INDEX;
1090 		return fIterator.Rewind();
1091 	}
1092 
1093 	status_t Suspend() { return fIterator.Suspend(); }
1094 	status_t Resume() { return fIterator.Resume(); }
1095 
1096 private:
1097 	enum {
1098 		DOT_INDEX		= 0,
1099 		DOT_DOT_INDEX	= 1,
1100 		ENTRY_INDEX		= 2,
1101 	};
1102 
1103 private:
1104 	EntryIterator	fIterator;
1105 	uint32			fDotIndex;
1106 
1107 	// debugging
1108 	int32			fIteratorID;
1109 	int32			fGetNextCounter;
1110 	static int32	fNextIteratorID;
1111 };
1112 
1113 
1114 int32 DirectoryCookie::fNextIteratorID = 0;
1115 
1116 
1117 // ramfs_create_dir
1118 static status_t
1119 ramfs_create_dir(fs_volume* _volume, fs_vnode* _dir, const char *name, int mode)
1120 {
1121 	FUNCTION(("name: `%s', mode: %x\n", name, mode));
1122 	Volume* volume = (Volume*)_volume->private_volume;
1123 	Directory* dir = dynamic_cast<Directory*>((Node*)_dir->private_node);
1124 
1125 	status_t error = B_OK;
1126 	// check name
1127 	if (!name || *name == '\0') {
1128 		SET_ERROR(error, B_BAD_VALUE);
1129 	// check directory
1130 	} else if (!dir) {
1131 		SET_ERROR(error, B_BAD_VALUE);
1132 	// check special names
1133 	} else if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
1134 		SET_ERROR(error, B_FILE_EXISTS);
1135 	} else if (VolumeWriteLocker locker = volume) {
1136 		NodeMTimeUpdater mTimeUpdater(dir);
1137 		// directory deleted?
1138 		bool removed;
1139 		if (get_vnode_removed(volume->FSVolume(), dir->GetID(), &removed)
1140 			!= B_OK || removed) {
1141 			SET_ERROR(error, B_NOT_ALLOWED);
1142 		}
1143 		// check directory write permissions
1144 		error = dir->CheckPermissions(ACCESS_W);
1145 		Node *node = NULL;
1146 		if (error == B_OK) {
1147 			// check if entry does already exist
1148 			if (dir->FindNode(name, &node) == B_OK) {
1149 				SET_ERROR(error, B_FILE_EXISTS);
1150 			} else {
1151 				// entry doesn't exist: create a directory
1152 				Directory *newDir = NULL;
1153 				error = dir->CreateDirectory(name, &newDir);
1154 				if (error == B_OK) {
1155 					node = newDir;
1156 					// set permissions, owner and group
1157 					node->SetMode(mode);
1158 					node->SetUID(geteuid());
1159 					node->SetGID(getegid());
1160 					// put the node
1161 					volume->PutVNode(node->GetID());
1162 				}
1163 			}
1164 		}
1165 		NodeMTimeUpdater mTimeUpdater2(node);
1166 		// notify listeners
1167 		if (error == B_OK) {
1168 			notify_entry_created(volume->GetID(), dir->GetID(), name,
1169 				node->GetID());
1170 		}
1171 	} else
1172 		SET_ERROR(error, B_ERROR);
1173 	RETURN_ERROR(error);
1174 }
1175 
1176 
1177 // ramfs_remove_dir
1178 static status_t
1179 ramfs_remove_dir(fs_volume* _volume, fs_vnode* _dir, const char *name)
1180 {
1181 	FUNCTION(("name: `%s'\n", name));
1182 	Volume* volume = (Volume*)_volume->private_volume;
1183 	Directory* dir = dynamic_cast<Directory*>((Node*)_dir->private_node);
1184 	status_t error = B_OK;
1185 
1186 	// check name
1187 	if (!name || *name == '\0' || !strcmp(name, ".") || !strcmp(name, "..")) {
1188 		SET_ERROR(error, B_BAD_VALUE);
1189 	// check node
1190 	} else if (!dir) {
1191 		SET_ERROR(error, B_BAD_VALUE);
1192 	} else if (VolumeWriteLocker locker = volume) {
1193 		NodeMTimeUpdater mTimeUpdater(dir);
1194 		// check directory write permissions
1195 		error = dir->CheckPermissions(ACCESS_W);
1196 		ino_t nodeID = -1;
1197 		if (error == B_OK) {
1198 			// check if entry exists
1199 			Node *node = NULL;
1200 			Entry *entry = NULL;
1201 			if (dir->FindAndGetNode(name, &node, &entry) == B_OK) {
1202 				nodeID = node->GetID();
1203 				if (!node->IsDirectory()) {
1204 					SET_ERROR(error, B_NOT_A_DIRECTORY);
1205 				} else if (!dynamic_cast<Directory*>(node)->IsEmpty()) {
1206 					SET_ERROR(error, B_DIRECTORY_NOT_EMPTY);
1207 				} else
1208 					error = dir->DeleteEntry(entry);
1209 				volume->PutVNode(node);
1210 			} else
1211 				SET_ERROR(error, B_ENTRY_NOT_FOUND);
1212 		}
1213 		// notify listeners
1214 		if (error == B_OK)
1215 			notify_entry_removed(volume->GetID(), dir->GetID(), name, nodeID);
1216 	} else
1217 		SET_ERROR(error, B_ERROR);
1218 	RETURN_ERROR(error);
1219 }
1220 
1221 
1222 // ramfs_open_dir
1223 static status_t
1224 ramfs_open_dir(fs_volume* /*fs*/, fs_vnode* _node, void** _cookie)
1225 {
1226 //	FUNCTION_START();
1227 //	Volume *volume = (Volume*)fs;
1228 	Node* node = (Node*)_node->private_node;
1229 
1230 	FUNCTION(("dir: (%Lu)\n", node->GetID()));
1231 	// get the Directory
1232 	status_t error = (node->IsDirectory() ? B_OK : B_NOT_A_DIRECTORY);
1233 	Directory *dir = NULL;
1234 	if (error == B_OK) {
1235 		dir = dynamic_cast<Directory*>(node);
1236 		if (!dir) {
1237 			FATAL("Node %" B_PRIdINO " pretends to be a Directory, but isn't!\n",
1238 				node->GetID());
1239 			error = B_NOT_A_DIRECTORY;
1240 		}
1241 	}
1242 	// create a DirectoryCookie
1243 	if (error == B_OK) {
1244 		DirectoryCookie *cookie = new(nothrow) DirectoryCookie(dir);
1245 		if (cookie) {
1246 			error = cookie->Suspend();
1247 			if (error == B_OK)
1248 				*_cookie = cookie;
1249 			else
1250 				delete cookie;
1251 		} else
1252 			SET_ERROR(error, B_NO_MEMORY);
1253 	}
1254 	FUNCTION_END();
1255 	RETURN_ERROR(error);
1256 }
1257 
1258 
1259 // ramfs_close_dir
1260 static status_t
1261 ramfs_close_dir(fs_volume* /*fs*/, fs_vnode* DARG(_node), void* _cookie)
1262 {
1263 	FUNCTION_START();
1264 	FUNCTION(("dir: (%Lu)\n", ((Node*)_node)->GetID()));
1265 	// No locking needed, since the Directory is guaranteed to live at this
1266 	// time and for iterators there is a separate locking.
1267 	DirectoryCookie *cookie = (DirectoryCookie*)_cookie;
1268 	cookie->Unset();
1269 	return B_OK;
1270 }
1271 
1272 
1273 // ramfs_free_dir_cookie
1274 static status_t
1275 ramfs_free_dir_cookie(fs_volume* /*fs*/, fs_vnode* /*_node*/, void* _cookie)
1276 {
1277 	FUNCTION_START();
1278 	DirectoryCookie *cookie = (DirectoryCookie*)_cookie;
1279 	delete cookie;
1280 	return B_OK;
1281 }
1282 
1283 
1284 // ramfs_read_dir
1285 static status_t
1286 ramfs_read_dir(fs_volume* _volume, fs_vnode* DARG(_node), void* _cookie,
1287 	struct dirent *buffer, size_t bufferSize, uint32 *count)
1288 {
1289 	FUNCTION_START();
1290 	Volume* volume = (Volume*)_volume->private_volume;
1291 	DARG(Node *node = (Node*)_node; )
1292 
1293 	FUNCTION(("dir: (%Lu)\n", node->GetID()));
1294 	DirectoryCookie *cookie = (DirectoryCookie*)_cookie;
1295 	status_t error = B_OK;
1296 	if (VolumeReadLocker locker = volume) {
1297 		error = cookie->Resume();
1298 		if (error == B_OK) {
1299 			// read one entry
1300 			ino_t nodeID = -1;
1301 			const char *name = NULL;
1302 			if (cookie->GetNext(&nodeID, &name) == B_OK) {
1303 				PRINT("  entry: `%s'\n", name);
1304 				size_t nameLen = strlen(name);
1305 				// check, whether the entry fits into the buffer,
1306 				// and fill it in
1307 				size_t length = (buffer->d_name + nameLen + 1) - (char*)buffer;
1308 				if (length <= bufferSize) {
1309 					buffer->d_dev = volume->GetID();
1310 					buffer->d_ino = nodeID;
1311 					memcpy(buffer->d_name, name, nameLen);
1312 					buffer->d_name[nameLen] = '\0';
1313 					buffer->d_reclen = length;
1314 					*count = 1;
1315 				} else {
1316 					SET_ERROR(error, B_BUFFER_OVERFLOW);
1317 				}
1318 			} else
1319 				*count = 0;
1320 
1321 			cookie->Suspend();
1322 		}
1323 	} else
1324 		SET_ERROR(error, B_ERROR);
1325 
1326 	RETURN_ERROR(error);
1327 }
1328 
1329 
1330 // ramfs_rewind_dir
1331 static status_t
1332 ramfs_rewind_dir(fs_volume* /*fs*/, fs_vnode* /*_node*/, void* _cookie)
1333 {
1334 	FUNCTION_START();
1335 	// No locking needed, since the Directory is guaranteed to live at this
1336 	// time and for iterators there is a separate locking.
1337 	DirectoryCookie *cookie = (DirectoryCookie*)_cookie;
1338 	// no need to Resume(), iterator remains suspended
1339 	status_t error = cookie->Rewind();
1340 	RETURN_ERROR(error);
1341 }
1342 
1343 
1344 // #pragma mark - Attribute Directories
1345 
1346 
1347 // ramfs_open_attr_dir
1348 static status_t
1349 ramfs_open_attr_dir(fs_volume* _volume, fs_vnode* _node, void** _cookie)
1350 {
1351 	FUNCTION_START();
1352 	Volume* volume = (Volume*)_volume->private_volume;
1353 	Node* node = (Node*)_node->private_node;
1354 
1355 	status_t error = B_OK;
1356 	if (VolumeReadLocker locker = volume) {
1357 		// check permissions
1358 		error = node->CheckPermissions(ACCESS_R);
1359 		// create iterator
1360 		AttributeIterator *iterator = NULL;
1361 		if (error == B_OK) {
1362 			iterator = new(nothrow) AttributeIterator(node);
1363 			if (iterator)
1364 				error = iterator->Suspend();
1365 			else
1366 				SET_ERROR(error, B_NO_MEMORY);
1367 		}
1368 		// set result / cleanup on failure
1369 		if (error == B_OK)
1370 			*_cookie = iterator;
1371 		else
1372 			delete iterator;
1373 	} else
1374 		SET_ERROR(error, B_ERROR);
1375 	RETURN_ERROR(error);
1376 }
1377 
1378 
1379 // ramfs_close_attr_dir
1380 static status_t
1381 ramfs_close_attr_dir(fs_volume* /*fs*/, fs_vnode* /*_node*/, void* _cookie)
1382 {
1383 	FUNCTION_START();
1384 	// No locking needed, since the Node is guaranteed to live at this time
1385 	// and for iterators there is a separate locking.
1386 	AttributeIterator *iterator = (AttributeIterator*)_cookie;
1387 	iterator->Unset();
1388 	return B_OK;
1389 }
1390 
1391 
1392 // ramfs_free_attr_dir_cookie
1393 static status_t
1394 ramfs_free_attr_dir_cookie(fs_volume* /*fs*/, fs_vnode* /*_node*/,
1395 	void* _cookie)
1396 {
1397 	FUNCTION_START();
1398 	// No locking needed, since the Node is guaranteed to live at this time
1399 	// and for iterators there is a separate locking.
1400 	AttributeIterator *iterator = (AttributeIterator*)_cookie;
1401 	delete iterator;
1402 	return B_OK;
1403 }
1404 
1405 
1406 // ramfs_read_attr_dir
1407 static status_t
1408 ramfs_read_attr_dir(fs_volume* _volume, fs_vnode* _node, void* _cookie,
1409 	struct dirent *buffer, size_t bufferSize, uint32 *count)
1410 {
1411 	FUNCTION_START();
1412 	Volume* volume = (Volume*)_volume->private_volume;
1413 
1414 	AttributeIterator *iterator = (AttributeIterator*)_cookie;
1415 	status_t error = B_OK;
1416 	if (VolumeReadLocker locker = volume) {
1417 		error = iterator->Resume();
1418 		if (error == B_OK) {
1419 			// get next attribute
1420 			Attribute *attribute = NULL;
1421 			if (iterator->GetNext(&attribute) == B_OK) {
1422 				const char *name = attribute->GetName();
1423 				size_t nameLen = strlen(name);
1424 				// check, whether the entry fits into the buffer,
1425 				// and fill it in
1426 				size_t length = (buffer->d_name + nameLen + 1) - (char*)buffer;
1427 				if (length <= bufferSize) {
1428 					buffer->d_dev = volume->GetID();
1429 					buffer->d_ino = -1;	// attributes don't have a node ID
1430 					memcpy(buffer->d_name, name, nameLen);
1431 					buffer->d_name[nameLen] = '\0';
1432 					buffer->d_reclen = length;
1433 					*count = 1;
1434 				} else {
1435 					SET_ERROR(error, B_BUFFER_OVERFLOW);
1436 				}
1437 			} else
1438 				*count = 0;
1439 
1440 			iterator->Suspend();
1441 		}
1442 	} else
1443 		SET_ERROR(error, B_ERROR);
1444 
1445 	RETURN_ERROR(error);
1446 }
1447 
1448 
1449 // ramfs_rewind_attr_dir
1450 static status_t
1451 ramfs_rewind_attr_dir(fs_volume* /*fs*/, fs_vnode* /*_node*/, void* _cookie)
1452 {
1453 	FUNCTION_START();
1454 	// No locking needed, since the Node is guaranteed to live at this time
1455 	// and for iterators there is a separate locking.
1456 	AttributeIterator *iterator = (AttributeIterator*)_cookie;
1457 	// no need to Resume(), iterator remains suspended
1458 	status_t error = iterator->Rewind();
1459 	RETURN_ERROR(error);
1460 }
1461 
1462 
1463 // #pragma mark - Attributes
1464 
1465 
1466 // AttributeCookie
1467 class AttributeCookie {
1468 public:
1469 	AttributeCookie() : fOpenMode(0), fLastNotificationTime(0) {}
1470 
1471 	status_t Init(const char* name, int openMode)
1472 	{
1473 		if (!fName.SetTo(name))
1474 			return B_NO_MEMORY;
1475 		fOpenMode = openMode;
1476 
1477 		return B_OK;
1478 	}
1479 
1480 	inline const char* GetName() const		{ return fName.GetString(); }
1481 
1482 	inline int GetOpenMode() const			{ return fOpenMode; }
1483 
1484 	inline bigtime_t GetLastNotificationTime() const
1485 		{ return fLastNotificationTime; }
1486 
1487 	inline bool NotificationIntervalElapsed(bool set = false)
1488 	{
1489 		bigtime_t currentTime = system_time();
1490 		bool result = (currentTime - fLastNotificationTime
1491 			> kNotificationInterval);
1492 		if (set && result)
1493 			fLastNotificationTime = currentTime;
1494 		return result;
1495 	}
1496 
1497 private:
1498 	String		fName;
1499 	int			fOpenMode;
1500 	bigtime_t	fLastNotificationTime;
1501 };
1502 
1503 
1504 // ramfs_create_attr
1505 static status_t
1506 ramfs_create_attr(fs_volume* _volume, fs_vnode* _node, const char *name,
1507 	uint32 type, int openMode, void** _cookie)
1508 {
1509 
1510 	Volume* volume = (Volume*)_volume->private_volume;
1511 	Node* node = (Node*)_node->private_node;
1512 
1513 	if (VolumeWriteLocker locker = volume) {
1514 		// try to find the attribute
1515 		Attribute *attribute = NULL;
1516 		node->FindAttribute(name, &attribute);
1517 
1518 		// in case the attribute exists we fail if required by the openMode
1519 		if (attribute && (openMode & O_EXCL))
1520 			RETURN_ERROR(B_FILE_EXISTS);
1521 
1522 		// creating and truncating require write permission
1523 		int accessMode = open_mode_to_access(openMode);
1524 		if (!attribute || (openMode & O_TRUNC))
1525 			accessMode |= ACCESS_W;
1526 
1527 		// check required permissions against node permissions
1528 		status_t error = node->CheckPermissions(accessMode);
1529 		if (error != B_OK)
1530 			RETURN_ERROR(error);
1531 
1532 		// create the cookie
1533 		AttributeCookie *cookie = new(nothrow) AttributeCookie();
1534 		if (!cookie)
1535 			return B_NO_MEMORY;
1536 		ObjectDeleter<AttributeCookie> cookieDeleter(cookie);
1537 
1538 		// init the cookie
1539 		error = cookie->Init(name, openMode);
1540 		if (error != B_OK)
1541 			RETURN_ERROR(error);
1542 
1543 		// if not existing yet, create the attribute and set its type
1544 		if (!attribute) {
1545 			error = node->CreateAttribute(name, &attribute);
1546 			if (error != B_OK)
1547 				RETURN_ERROR(error);
1548 
1549 			attribute->SetType(type);
1550 
1551 			notify_attribute_changed(volume->GetID(), -1, node->GetID(), name,
1552 				B_ATTR_CREATED);
1553 
1554 		// else truncate if requested
1555 		} else if (openMode & O_TRUNC) {
1556 			error = attribute->SetSize(0);
1557 			if (error != B_OK)
1558 				return error;
1559 
1560 			notify_attribute_changed(volume->GetID(), -1, node->GetID(), name,
1561 				B_ATTR_CHANGED);
1562 		}
1563 		NodeMTimeUpdater mTimeUpdater(node);
1564 
1565 		// success
1566 		cookieDeleter.Detach();
1567 		*_cookie = cookie;
1568 	} else
1569 		RETURN_ERROR(B_ERROR);
1570 
1571 	return B_OK;
1572 }
1573 
1574 
1575 // ramfs_open_attr
1576 static status_t
1577 ramfs_open_attr(fs_volume* _volume, fs_vnode* _node, const char *name,
1578 	int openMode, void** _cookie)
1579 {
1580 //	FUNCTION_START();
1581 	Volume* volume = (Volume*)_volume->private_volume;
1582 	Node* node = (Node*)_node->private_node;
1583 
1584 	FUNCTION(("node: %lld\n", node->GetID()));
1585 	status_t error = B_OK;
1586 
1587 	if (VolumeWriteLocker locker = volume) {
1588 		// find the attribute
1589 		Attribute *attribute = NULL;
1590 		if (error == B_OK)
1591 			error = node->FindAttribute(name, &attribute);
1592 
1593 		// truncating requires write permission
1594 		int accessMode = open_mode_to_access(openMode);
1595 		if (error == B_OK && (openMode & O_TRUNC))
1596 			accessMode |= ACCESS_W;
1597 
1598 		// check open mode against permissions
1599 		if (error == B_OK)
1600 			error = node->CheckPermissions(accessMode);
1601 
1602 		// create the cookie
1603 		AttributeCookie *cookie = NULL;
1604 		if (error == B_OK) {
1605 			cookie = new(nothrow) AttributeCookie();
1606 			if (cookie) {
1607 				SET_ERROR(error, cookie->Init(name, openMode));
1608 			} else {
1609 				SET_ERROR(error, B_NO_MEMORY);
1610 			}
1611 		}
1612 
1613 		// truncate if requested
1614 		if (error == B_OK && (openMode & O_TRUNC)) {
1615 			error = attribute->SetSize(0);
1616 
1617 			if (error == B_OK) {
1618 				notify_attribute_changed(volume->GetID(), -1, node->GetID(),
1619 					name, B_ATTR_CHANGED);
1620 			}
1621 		}
1622 		NodeMTimeUpdater mTimeUpdater(node);
1623 
1624 		// set result / cleanup on failure
1625 		if (error == B_OK)
1626 			*_cookie = cookie;
1627 		else if (cookie)
1628 			delete cookie;
1629 	} else
1630 		SET_ERROR(error, B_ERROR);
1631 	RETURN_ERROR(error);
1632 }
1633 
1634 
1635 // ramfs_close_attr
1636 static status_t
1637 ramfs_close_attr(fs_volume* _volume, fs_vnode* _node, void* _cookie)
1638 {
1639 //	FUNCTION_START();
1640 	Volume* volume = (Volume*)_volume->private_volume;
1641 	Node* node = (Node*)_node->private_node;
1642 
1643 	FUNCTION(("node: %lld\n", node->GetID()));
1644 	status_t error = B_OK;
1645 
1646 	// notify listeners
1647 	if (VolumeReadLocker locker = volume) {
1648 		notify_if_stat_changed(volume, node);
1649 	} else
1650 		SET_ERROR(error, B_ERROR);
1651 	return error;
1652 }
1653 
1654 
1655 // ramfs_free_attr_cookie
1656 static status_t
1657 ramfs_free_attr_cookie(fs_volume* /*fs*/, fs_vnode* /*_node*/, void* _cookie)
1658 {
1659 	FUNCTION_START();
1660 	AttributeCookie *cookie = (AttributeCookie*)_cookie;
1661 	delete cookie;
1662 	return B_OK;
1663 }
1664 
1665 
1666 // ramfs_read_attr
1667 static status_t
1668 ramfs_read_attr(fs_volume* _volume, fs_vnode* _node, void* _cookie, off_t pos,
1669 	void *buffer, size_t *bufferSize)
1670 {
1671 //	FUNCTION_START();
1672 	Volume* volume = (Volume*)_volume->private_volume;
1673 	Node* node = (Node*)_node->private_node;
1674 
1675 	AttributeCookie *cookie = (AttributeCookie*)_cookie;
1676 
1677 	status_t error = B_OK;
1678 	if (VolumeReadLocker locker = volume) {
1679 		// find the attribute
1680 		Attribute *attribute = NULL;
1681 		if (error == B_OK)
1682 			error = node->FindAttribute(cookie->GetName(), &attribute);
1683 
1684 		// check permissions
1685 		int accessMode = open_mode_to_access(cookie->GetOpenMode());
1686 		if (error == B_OK && !(accessMode & ACCESS_R))
1687 			SET_ERROR(error, B_NOT_ALLOWED);
1688 
1689 		// read
1690 		if (error == B_OK)
1691 			error = attribute->ReadAt(pos, buffer, *bufferSize, bufferSize);
1692 	} else
1693 		SET_ERROR(error, B_ERROR);
1694 	RETURN_ERROR(error);
1695 }
1696 
1697 
1698 // ramfs_write_attr
1699 static status_t
1700 ramfs_write_attr(fs_volume* _volume, fs_vnode* _node, void* _cookie,
1701 	off_t pos, const void *buffer, size_t *bufferSize)
1702 {
1703 	//	FUNCTION_START();
1704 	Volume* volume = (Volume*)_volume->private_volume;
1705 	Node* node = (Node*)_node->private_node;
1706 	AttributeCookie *cookie = (AttributeCookie*)_cookie;
1707 
1708 	status_t error = B_OK;
1709 	// Don't allow writing the reserved attributes.
1710 	const char *name = cookie->GetName();
1711 	if (name[0] == '\0' || !strcmp(name, "name")
1712 		|| !strcmp(name, "last_modified") || !strcmp(name, "size")) {
1713 		// FUNCTION(("failed: node: %s, attribute: %s\n",
1714 		//	node->GetName(), name));
1715 		RETURN_ERROR(B_NOT_ALLOWED);
1716 	}
1717 
1718 	if (VolumeWriteLocker locker = volume) {
1719 		NodeMTimeUpdater mTimeUpdater(node);
1720 
1721 		// find the attribute
1722 		Attribute *attribute = NULL;
1723 		if (error == B_OK)
1724 			error = node->FindAttribute(cookie->GetName(), &attribute);
1725 
1726 		// check permissions
1727 		int accessMode = open_mode_to_access(cookie->GetOpenMode());
1728 		if (error == B_OK && !(accessMode & ACCESS_W))
1729 			SET_ERROR(error, B_NOT_ALLOWED);
1730 
1731 		// write the data
1732 		if (error == B_OK)
1733 			error = attribute->WriteAt(pos, buffer, *bufferSize, bufferSize);
1734 
1735 		// notify listeners
1736 		if (error == B_OK) {
1737 			notify_attribute_changed(volume->GetID(), -1, node->GetID(), name,
1738 				B_ATTR_CHANGED);
1739 		}
1740 	} else
1741 		SET_ERROR(error, B_ERROR);
1742 
1743 	RETURN_ERROR(error);
1744 }
1745 
1746 
1747 // ramfs_read_attr_stat
1748 static status_t
1749 ramfs_read_attr_stat(fs_volume* _volume, fs_vnode* _node, void* _cookie,
1750 	struct stat *st)
1751 {
1752 //	FUNCTION_START();
1753 	Volume* volume = (Volume*)_volume->private_volume;
1754 	Node* node = (Node*)_node->private_node;
1755 	AttributeCookie *cookie = (AttributeCookie*)_cookie;
1756 	status_t error = B_OK;
1757 
1758 	if (VolumeReadLocker locker = volume) {
1759 		// find the attribute
1760 		Attribute *attribute = NULL;
1761 		if (error == B_OK)
1762 			error = node->FindAttribute(cookie->GetName(), &attribute);
1763 
1764 		// check permissions
1765 		int accessMode = open_mode_to_access(cookie->GetOpenMode());
1766 		if (error == B_OK && !(accessMode & ACCESS_R))
1767 			SET_ERROR(error, B_NOT_ALLOWED);
1768 
1769 		// read
1770 		if (error == B_OK) {
1771 			st->st_type = attribute->GetType();
1772 			st->st_size = attribute->GetSize();
1773 		}
1774 	} else
1775 		SET_ERROR(error, B_ERROR);
1776 	RETURN_ERROR(error);
1777 }
1778 
1779 
1780 // ramfs_rename_attr
1781 static status_t
1782 ramfs_rename_attr(fs_volume* /*fs*/, fs_vnode* /*_fromNode*/,
1783 	const char */*fromName*/, fs_vnode* /*_toNode*/, const char */*toName*/)
1784 {
1785 	// TODO : ramfs_rename_attr
1786 	return B_BAD_VALUE;
1787 }
1788 
1789 
1790 // ramfs_remove_attr
1791 static status_t
1792 ramfs_remove_attr(fs_volume* _volume, fs_vnode* _node, const char *name)
1793 {
1794 	FUNCTION_START();
1795 	Volume* volume = (Volume*)_volume->private_volume;
1796 	Node* node = (Node*)_node->private_node;
1797 	status_t error = B_OK;
1798 
1799 	if (VolumeWriteLocker locker = volume) {
1800 		NodeMTimeUpdater mTimeUpdater(node);
1801 
1802 		// check permissions
1803 		error = node->CheckPermissions(ACCESS_W);
1804 
1805 		// find the attribute
1806 		Attribute *attribute = NULL;
1807 		if (error == B_OK)
1808 			error = node->FindAttribute(name, &attribute);
1809 
1810 		// delete it
1811 		if (error == B_OK)
1812 			error = node->DeleteAttribute(attribute);
1813 
1814 		// notify listeners
1815 		if (error == B_OK) {
1816 			notify_attribute_changed(volume->GetID(), -1, node->GetID(), name,
1817 				B_ATTR_REMOVED);
1818 		}
1819 	} else
1820 		SET_ERROR(error, B_ERROR);
1821 
1822 	RETURN_ERROR(error);
1823 }
1824 
1825 
1826 // #pragma mark - Indices
1827 
1828 
1829 // IndexDirCookie
1830 class IndexDirCookie {
1831 public:
1832 	IndexDirCookie() : index_index(0) {}
1833 
1834 	int32	index_index;
1835 };
1836 
1837 
1838 // ramfs_open_index_dir
1839 static status_t
1840 ramfs_open_index_dir(fs_volume* _volume, void** _cookie)
1841 {
1842 	FUNCTION_START();
1843 	Volume* volume = (Volume*)_volume->private_volume;
1844 	status_t error = B_OK;
1845 	if (VolumeReadLocker locker = volume) {
1846 		// check whether an index directory exists
1847 		if (volume->GetIndexDirectory()) {
1848 			IndexDirCookie *cookie = new(nothrow) IndexDirCookie;
1849 			if (cookie)
1850 				*_cookie = cookie;
1851 			else
1852 				SET_ERROR(error, B_NO_MEMORY);
1853 		} else
1854 			SET_ERROR(error, B_ENTRY_NOT_FOUND);
1855 	} else
1856 		SET_ERROR(error, B_ERROR);
1857 	RETURN_ERROR(error);
1858 }
1859 
1860 
1861 // ramfs_close_index_dir
1862 static status_t
1863 ramfs_close_index_dir(fs_volume* /*fs*/, void* /*_cookie*/)
1864 {
1865 	FUNCTION_START();
1866 	return B_OK;
1867 }
1868 
1869 
1870 // ramfs_free_index_dir_cookie
1871 static status_t
1872 ramfs_free_index_dir_cookie(fs_volume* /*fs*/, void* _cookie)
1873 {
1874 	FUNCTION_START();
1875 	IndexDirCookie *cookie = (IndexDirCookie*)_cookie;
1876 	delete cookie;
1877 	return B_OK;
1878 }
1879 
1880 
1881 // ramfs_read_index_dir
1882 static status_t
1883 ramfs_read_index_dir(fs_volume* _volume, void* _cookie,
1884 	struct dirent *buffer, size_t bufferSize, uint32 *count)
1885 {
1886 	FUNCTION_START();
1887 	Volume* volume = (Volume*)_volume->private_volume;
1888 	IndexDirCookie *cookie = (IndexDirCookie*)_cookie;
1889 	status_t error = B_OK;
1890 
1891 	if (VolumeReadLocker locker = volume) {
1892 		// get the next index
1893 		Index *index = volume->GetIndexDirectory()->IndexAt(
1894 			cookie->index_index++);
1895 		if (index) {
1896 			const char *name = index->GetName();
1897 			size_t nameLen = strlen(name);
1898 			// check, whether the entry fits into the buffer,
1899 			// and fill it in
1900 			size_t length = (buffer->d_name + nameLen + 1) - (char*)buffer;
1901 			if (length <= bufferSize) {
1902 				buffer->d_dev = volume->GetID();
1903 				buffer->d_ino = -1;	// indices don't have a node ID
1904 				memcpy(buffer->d_name, name, nameLen);
1905 				buffer->d_name[nameLen] = '\0';
1906 				buffer->d_reclen = length;
1907 				*count = 1;
1908 			} else {
1909 				SET_ERROR(error, B_BUFFER_OVERFLOW);
1910 			}
1911 		} else
1912 			*count = 0;
1913 	} else
1914 		SET_ERROR(error, B_ERROR);
1915 
1916 	RETURN_ERROR(error);
1917 }
1918 
1919 
1920 // ramfs_rewind_index_dir
1921 static status_t
1922 ramfs_rewind_index_dir(fs_volume* /*fs*/, void* _cookie)
1923 {
1924 	FUNCTION_START();
1925 	IndexDirCookie *cookie = (IndexDirCookie*)_cookie;
1926 	cookie->index_index = 0;
1927 	return B_OK;
1928 }
1929 
1930 
1931 // ramfs_create_index
1932 static status_t
1933 ramfs_create_index(fs_volume* _volume, const char *name, uint32 type,
1934 	uint32 /*flags*/)
1935 {
1936 	FUNCTION_START();
1937 	Volume* volume = (Volume*)_volume->private_volume;
1938 	status_t error = B_OK;
1939 
1940 	// only root is allowed to manipulate the indices
1941 	if (geteuid() != 0) {
1942 		SET_ERROR(error, B_NOT_ALLOWED);
1943 	} else if (VolumeWriteLocker locker = volume) {
1944 		// get the index directory
1945 		if (IndexDirectory *indexDir = volume->GetIndexDirectory()) {
1946 			// check whether an index with that name does already exist
1947 			if (indexDir->FindIndex(name)) {
1948 				SET_ERROR(error, B_FILE_EXISTS);
1949 			} else {
1950 				// create the index
1951 				AttributeIndex *index;
1952 				error = indexDir->CreateIndex(name, type, &index);
1953 			}
1954 		} else
1955 			SET_ERROR(error, B_ENTRY_NOT_FOUND);
1956 	} else
1957 		SET_ERROR(error, B_ERROR);
1958 
1959 	RETURN_ERROR(error);
1960 }
1961 
1962 
1963 // ramfs_remove_index
1964 static status_t
1965 ramfs_remove_index(fs_volume* _volume, const char *name)
1966 {
1967 	FUNCTION_START();
1968 	Volume* volume = (Volume*)_volume->private_volume;
1969 	status_t error = B_OK;
1970 	// only root is allowed to manipulate the indices
1971 	if (geteuid() != 0) {
1972 		SET_ERROR(error, B_NOT_ALLOWED);
1973 	} else if (VolumeWriteLocker locker = volume) {
1974 		// get the index directory
1975 		if (IndexDirectory *indexDir = volume->GetIndexDirectory()) {
1976 			// check whether an index with that name does exist
1977 			if (Index *index = indexDir->FindIndex(name)) {
1978 				// don't delete a special index
1979 				if (indexDir->IsSpecialIndex(index)) {
1980 					SET_ERROR(error, B_BAD_VALUE);
1981 				} else
1982 					indexDir->DeleteIndex(index);
1983 			} else
1984 				SET_ERROR(error, B_ENTRY_NOT_FOUND);
1985 		} else
1986 			SET_ERROR(error, B_ENTRY_NOT_FOUND);
1987 	} else
1988 		SET_ERROR(error, B_ERROR);
1989 	RETURN_ERROR(error);
1990 }
1991 
1992 
1993 // ramfs_read_index_stat
1994 static status_t
1995 ramfs_read_index_stat(fs_volume* _volume, const char *name, struct stat *st)
1996 {
1997 	FUNCTION_START();
1998 	Volume* volume = (Volume*)_volume->private_volume;
1999 	status_t error = B_OK;
2000 	if (VolumeReadLocker locker = volume) {
2001 		// get the index directory
2002 		if (IndexDirectory *indexDir = volume->GetIndexDirectory()) {
2003 			// find the index
2004 			if (Index *index = indexDir->FindIndex(name)) {
2005 				st->st_type = index->GetType();
2006 				if (index->HasFixedKeyLength())
2007 					st->st_size = index->GetKeyLength();
2008 				else
2009 					st->st_size = kMaxIndexKeyLength;
2010 				st->st_atime = 0;	// TODO: index times
2011 				st->st_mtime = 0;	// ...
2012 				st->st_ctime = 0;	// ...
2013 				st->st_crtime = 0;	// ...
2014 				st->st_uid = 0;		// root owns the indices
2015 				st->st_gid = 0;		//
2016 			} else
2017 				SET_ERROR(error, B_ENTRY_NOT_FOUND);
2018 		} else
2019 			SET_ERROR(error, B_ENTRY_NOT_FOUND);
2020 	} else
2021 		SET_ERROR(error, B_ERROR);
2022 	RETURN_ERROR(error);
2023 }
2024 
2025 
2026 // #pragma mark - Queries
2027 
2028 // Query implementation by Axel Dörfler. Slightly adjusted.
2029 
2030 // ramfs_open_query
2031 static status_t
2032 ramfs_open_query(fs_volume* _volume, const char *queryString, uint32 flags,
2033 	port_id port, uint32 token, void** _cookie)
2034 {
2035 	FUNCTION_START();
2036 	PRINT("query = \"%s\", flags = %lu, port_id = %" B_PRId32 ", token = %" B_PRId32 "\n",
2037 		queryString, flags, port, token);
2038 
2039 	Volume* volume = (Volume*)_volume->private_volume;
2040 
2041 	// lock the volume
2042 	VolumeReadLocker locker(volume);
2043 	if (!locker.IsLocked())
2044 		RETURN_ERROR(B_ERROR);
2045 
2046 	// parse the query expression
2047 	Expression *expression = new Expression((char *)queryString);
2048 	if (expression == NULL)
2049 		RETURN_ERROR(B_NO_MEMORY);
2050 	ObjectDeleter<Expression> expressionDeleter(expression);
2051 
2052 	if (expression->InitCheck() < B_OK) {
2053 		WARN("Could not parse query, stopped at: \"%s\"\n",
2054 			expression->Position());
2055 		RETURN_ERROR(B_BAD_VALUE);
2056 	}
2057 
2058 	// create the query
2059 	Query *query = new Query(volume, expression, flags);
2060 	if (query == NULL)
2061 		RETURN_ERROR(B_NO_MEMORY);
2062 	expressionDeleter.Detach();
2063 	// TODO: The Query references an Index, but nothing prevents the Index
2064 	// from being deleted, while the Query is in existence.
2065 
2066 	if (flags & B_LIVE_QUERY)
2067 		query->SetLiveMode(port, token);
2068 
2069 	*_cookie = (void *)query;
2070 
2071 	return B_OK;
2072 }
2073 
2074 
2075 // ramfs_close_query
2076 static status_t
2077 ramfs_close_query(fs_volume* /*fs*/, void* /*cookie*/)
2078 {
2079 	FUNCTION_START();
2080 	return B_OK;
2081 }
2082 
2083 
2084 // ramfs_free_query_cookie
2085 static status_t
2086 ramfs_free_query_cookie(fs_volume* _volume, void* _cookie)
2087 {
2088 	FUNCTION_START();
2089 
2090 	Volume* volume = (Volume*)_volume->private_volume;
2091 
2092 	// lock the volume
2093 	VolumeReadLocker locker(volume);
2094 	if (!locker.IsLocked())
2095 		RETURN_ERROR(B_ERROR);
2096 
2097 	Query *query = (Query *)_cookie;
2098 	Expression *expression = query->GetExpression();
2099 	delete query;
2100 	delete expression;
2101 
2102 	return B_OK;
2103 }
2104 
2105 
2106 // ramfs_read_query
2107 static status_t
2108 ramfs_read_query(fs_volume* _volume, void* _cookie, struct dirent *buffer,
2109 	size_t bufferSize, uint32 *count)
2110 {
2111 	FUNCTION_START();
2112 	Query *query = (Query *)_cookie;
2113 	Volume* volume = (Volume*)_volume->private_volume;
2114 
2115 	// lock the volume
2116 	VolumeReadLocker locker(volume);
2117 	if (!locker.IsLocked())
2118 		RETURN_ERROR(B_ERROR);
2119 
2120 	status_t status = query->GetNextEntry(buffer, bufferSize);
2121 	if (status == B_OK)
2122 		*count = 1;
2123 	else if (status == B_ENTRY_NOT_FOUND)
2124 		*count = 0;
2125 	else
2126 		return status;
2127 
2128 	return B_OK;
2129 }
2130 
2131 
2132 // TODO: status_t (*rewind_query)(fs_volume fs, void** _cookie);
2133 
2134 
2135 // #pragma mark - Module Interface
2136 
2137 
2138 static status_t
2139 ramfs_std_ops(int32 op, ...)
2140 {
2141 	switch (op) {
2142 		case B_MODULE_INIT:
2143 		{
2144 			init_debugging();
2145 			PRINT("ramfs_std_ops(): B_MODULE_INIT\n");
2146 			return B_OK;
2147 		}
2148 
2149 		case B_MODULE_UNINIT:
2150 			PRINT("ramfs_std_ops(): B_MODULE_UNINIT\n");
2151 			exit_debugging();
2152 			return B_OK;
2153 
2154 		default:
2155 			return B_ERROR;
2156 	}
2157 }
2158 
2159 
2160 fs_volume_ops gRamFSVolumeOps = {
2161 	&ramfs_unmount,
2162 	&ramfs_read_fs_info,
2163 	&ramfs_write_fs_info,
2164 	&ramfs_sync,
2165 	&ramfs_get_vnode,
2166 
2167 	/* index directory & index operations */
2168 	&ramfs_open_index_dir,
2169 	&ramfs_close_index_dir,
2170 	&ramfs_free_index_dir_cookie,
2171 	&ramfs_read_index_dir,
2172 	&ramfs_rewind_index_dir,
2173 
2174 	&ramfs_create_index,
2175 	&ramfs_remove_index,
2176 	&ramfs_read_index_stat,
2177 
2178 	/* query operations */
2179 	&ramfs_open_query,
2180 	&ramfs_close_query,
2181 	&ramfs_free_query_cookie,
2182 	&ramfs_read_query,
2183 	NULL	// rewind_query
2184 };
2185 
2186 
2187 fs_vnode_ops gRamFSVnodeOps = {
2188 	/* vnode operations */
2189 	&ramfs_lookup,			// lookup
2190 	NULL,					// get name
2191 	&ramfs_write_vnode,		// write
2192 	&ramfs_remove_vnode,	// remove
2193 
2194 	/* VM file access */
2195 	NULL,					// can_page
2196 	NULL,					// read pages
2197 	NULL,					// write pages
2198 
2199 	NULL,					// io?
2200 	NULL,					// cancel io
2201 
2202 	NULL,					// get file map
2203 
2204 	&ramfs_ioctl,
2205 	&ramfs_set_flags,
2206 	NULL,   // &ramfs_select,
2207 	NULL,   // &ramfs_deselect,
2208 	&ramfs_fsync,
2209 
2210 	&ramfs_read_symlink,
2211 	&ramfs_create_symlink,
2212 
2213 	&ramfs_link,
2214 	&ramfs_unlink,
2215 	&ramfs_rename,
2216 
2217 	&ramfs_access,
2218 	&ramfs_read_stat,
2219 	&ramfs_write_stat,
2220 	NULL,   // &ramfs_preallocate,
2221 
2222 	/* file operations */
2223 	&ramfs_create,
2224 	&ramfs_open,
2225 	&ramfs_close,
2226 	&ramfs_free_cookie,
2227 	&ramfs_read,
2228 	&ramfs_write,
2229 
2230 	/* directory operations */
2231 	&ramfs_create_dir,
2232 	&ramfs_remove_dir,
2233 	&ramfs_open_dir,
2234 	&ramfs_close_dir,
2235 	&ramfs_free_dir_cookie,
2236 	&ramfs_read_dir,
2237 	&ramfs_rewind_dir,
2238 
2239 	/* attribute directory operations */
2240 	&ramfs_open_attr_dir,
2241 	&ramfs_close_attr_dir,
2242 	&ramfs_free_attr_dir_cookie,
2243 	&ramfs_read_attr_dir,
2244 	&ramfs_rewind_attr_dir,
2245 
2246 	/* attribute operations */
2247 	&ramfs_create_attr,
2248 	&ramfs_open_attr,
2249 	&ramfs_close_attr,
2250 	&ramfs_free_attr_cookie,
2251 	&ramfs_read_attr,
2252 	&ramfs_write_attr,
2253 
2254 	&ramfs_read_attr_stat,
2255 	NULL,   // &ramfs_write_attr_stat,
2256 	&ramfs_rename_attr,
2257 	&ramfs_remove_attr,
2258 
2259 	/* special nodes */
2260 	NULL	// create_special_node
2261 };
2262 
2263 static file_system_module_info sRamFSModuleInfo = {
2264 	{
2265 		"file_systems/ramfs" B_CURRENT_FS_API_VERSION,
2266 		0,
2267 		ramfs_std_ops,
2268 	},
2269 
2270 	"ramfs",				// short_name
2271 	"RAM File System",		// pretty_name
2272 	0						// DDM flags
2273 	| B_DISK_SYSTEM_SUPPORTS_WRITING,
2274 
2275 	// scanning
2276 	NULL,	// identify_partition()
2277 	NULL,	// scan_partition()
2278 	NULL,	// free_identify_partition_cookie()
2279 	NULL,	// free_partition_content_cookie()
2280 
2281 	&ramfs_mount,
2282 
2283 	NULL,	// TODO : &ramfs_get_supported_operations
2284 
2285 	NULL,   // validate_resize
2286 	NULL,   // validate_move
2287 	NULL,   // validate_set_content_name
2288 	NULL,   // validate_set_content_parameters
2289 	NULL,   // validate_initialize,
2290 
2291 	/* shadow partition modification */
2292 	NULL,   // shadow_changed
2293 
2294 	/* writing */
2295 	NULL,   // defragment
2296 	NULL,   // repair
2297 	NULL,   // resize
2298 	NULL,   // move
2299 	NULL,   // set_content_name
2300 	NULL,   // set_content_parameters
2301 	NULL	// bfs_initialize
2302 };
2303 
2304 module_info *modules[] = {
2305 	(module_info *)&sRamFSModuleInfo,
2306 	NULL,
2307 };
2308 
2309