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