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