xref: /haiku/src/system/kernel/fs/vfs.cpp (revision aff60bb217827097c13d643275fdf1f1c66e7f17)
1 /*
2  * Copyright 2002-2005, Axel Dörfler, axeld@pinc-software.de.
3  * Distributed under the terms of the MIT License.
4  *
5  * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
6  * Distributed under the terms of the NewOS License.
7  */
8 
9 /* Virtual File System and File System Interface Layer */
10 
11 #include <OS.h>
12 #include <StorageDefs.h>
13 #include <fs_info.h>
14 #include <fs_interface.h>
15 #include <fs_volume.h>
16 
17 #include <disk_device_manager/KDiskDevice.h>
18 #include <disk_device_manager/KDiskDeviceManager.h>
19 #include <disk_device_manager/KDiskDeviceUtils.h>
20 #include <disk_device_manager/KPartitionVisitor.h>
21 #include <disk_device_manager/KDiskSystem.h>
22 #include <KPath.h>
23 #include <syscalls.h>
24 #include <boot/kernel_args.h>
25 #include <vfs.h>
26 #include <vm.h>
27 #include <vm_cache.h>
28 #include <file_cache.h>
29 #include <block_cache.h>
30 #include <khash.h>
31 #include <lock.h>
32 #include <fd.h>
33 #include <fs/node_monitor.h>
34 #include <util/kernel_cpp.h>
35 
36 #include <string.h>
37 #include <stdio.h>
38 #include <ctype.h>
39 #include <unistd.h>
40 #include <sys/stat.h>
41 #include <sys/resource.h>
42 #include <fcntl.h>
43 #include <limits.h>
44 #include <stddef.h>
45 
46 //#define TRACE_VFS
47 #ifdef TRACE_VFS
48 #	define PRINT(x) dprintf x
49 #	define FUNCTION(x) dprintf x
50 #else
51 #	define PRINT(x) ;
52 #	define FUNCTION(x) ;
53 #endif
54 
55 #define MAX_SYM_LINKS SYMLINKS_MAX
56 
57 const static uint32 kMaxUnusedVnodes = 8192;
58 	// This is the maximum number of unused vnodes that the system
59 	// will keep around.
60 	// It may be chosen with respect to the available memory or enhanced
61 	// by some timestamp/frequency heurism.
62 
63 static struct {
64 	const char *path;
65 	const char *target;
66 } sPredefinedLinks[] = {
67 	{"/system", "/boot/beos/system"},
68 	{"/bin", "/boot/beos/bin"},
69 	{"/etc", "/boot/beos/etc"},
70 	{"/var", "/boot/var"},
71 	{"/tmp", "/boot/var/tmp"},
72 	{NULL}
73 };
74 
75 struct vnode {
76 	struct vnode	*next;
77 	vm_cache_ref	*cache;
78 	mount_id		device;
79 	list_link		mount_link;
80 	list_link		unused_link;
81 	vnode_id		id;
82 	fs_vnode		private_node;
83 	struct fs_mount	*mount;
84 	struct vnode	*covered_by;
85 	int32			ref_count;
86 	uint8			remove : 1;
87 	uint8			busy : 1;
88 	uint8			unpublished : 1;
89 	struct advisory_locking	*advisory_locking;
90 };
91 
92 struct vnode_hash_key {
93 	mount_id	device;
94 	vnode_id	vnode;
95 };
96 
97 #define FS_CALL(vnode, op) (vnode->mount->fs->op)
98 #define FS_MOUNT_CALL(mount, op) (mount->fs->op)
99 
100 struct fs_mount {
101 	struct fs_mount	*next;
102 	file_system_module_info *fs;
103 	mount_id		id;
104 	void			*cookie;
105 	char			*device_name;
106 	char			*fs_name;
107 	recursive_lock	rlock;	// guards the vnodes list
108 	struct vnode	*root_vnode;
109 	struct vnode	*covers_vnode;
110 	KPartition		*partition;
111 	struct list		vnodes;
112 	bool			unmounting;
113 	bool			owns_file_device;
114 };
115 
116 struct advisory_locking {
117 	sem_id			lock;
118 	sem_id			wait_sem;
119 	struct list		locks;
120 };
121 
122 struct advisory_lock {
123 	list_link		link;
124 	team_id			team;
125 	off_t			offset;
126 	off_t			length;
127 	bool			shared;
128 };
129 
130 static mutex sFileSystemsMutex;
131 
132 /**	\brief Guards sMountsTable.
133  *
134  *	The holder is allowed to read/write access the sMountsTable.
135  *	Manipulation of the fs_mount structures themselves
136  *	(and their destruction) requires different locks though.
137  */
138 static mutex sMountMutex;
139 
140 /**	\brief Guards mount/unmount operations.
141  *
142  *	The fs_mount() and fs_unmount() hold the lock during their whole operation.
143  *	That is locking the lock ensures that no FS is mounted/unmounted. In
144  *	particular this means that
145  *	- sMountsTable will not be modified,
146  *	- the fields immutable after initialization of the fs_mount structures in
147  *	  sMountsTable will not be modified,
148  *	- vnode::covered_by of any vnode in sVnodeTable will not be modified,
149  *
150  *	The thread trying to lock the lock must not hold sVnodeMutex or
151  *	sMountMutex.
152  */
153 static recursive_lock sMountOpLock;
154 
155 /**	\brief Guards sVnodeTable.
156  *
157  *	The holder is allowed to read/write access sVnodeTable and to
158  *	to any unbusy vnode in that table, save
159  *	to the immutable fields (device, id, private_node, mount) to which
160  *	only read-only access is allowed, and to the field covered_by, which is
161  *	guarded by sMountOpLock.
162  *
163  *	The thread trying to lock the mutex must not hold sMountMutex.
164  */
165 static mutex sVnodeMutex;
166 
167 #define VNODE_HASH_TABLE_SIZE 1024
168 static hash_table *sVnodeTable;
169 static list sUnusedVnodeList;
170 static uint32 sUnusedVnodes = 0;
171 static struct vnode *sRoot;
172 
173 #define MOUNTS_HASH_TABLE_SIZE 16
174 static hash_table *sMountsTable;
175 static mount_id sNextMountID = 1;
176 
177 mode_t __gUmask = 022;
178 
179 // This can be used by other code to see if there is a boot file system already
180 dev_t gBootDevice = -1;
181 
182 
183 /* function declarations */
184 
185 // file descriptor operation prototypes
186 static status_t file_read(struct file_descriptor *, off_t pos, void *buffer, size_t *);
187 static status_t file_write(struct file_descriptor *, off_t pos, const void *buffer, size_t *);
188 static off_t file_seek(struct file_descriptor *, off_t pos, int seek_type);
189 static void file_free_fd(struct file_descriptor *);
190 static status_t file_close(struct file_descriptor *);
191 static status_t file_select(struct file_descriptor *, uint8 event, uint32 ref,
192 	struct select_sync *sync);
193 static status_t file_deselect(struct file_descriptor *, uint8 event,
194 	struct select_sync *sync);
195 static status_t dir_read(struct file_descriptor *, struct dirent *buffer, size_t bufferSize, uint32 *_count);
196 static status_t dir_read(struct vnode *vnode, fs_cookie cookie, struct dirent *buffer, size_t bufferSize, uint32 *_count);
197 static status_t dir_rewind(struct file_descriptor *);
198 static void dir_free_fd(struct file_descriptor *);
199 static status_t dir_close(struct file_descriptor *);
200 static status_t attr_dir_read(struct file_descriptor *, struct dirent *buffer, size_t bufferSize, uint32 *_count);
201 static status_t attr_dir_rewind(struct file_descriptor *);
202 static void attr_dir_free_fd(struct file_descriptor *);
203 static status_t attr_dir_close(struct file_descriptor *);
204 static status_t attr_read(struct file_descriptor *, off_t pos, void *buffer, size_t *);
205 static status_t attr_write(struct file_descriptor *, off_t pos, const void *buffer, size_t *);
206 static off_t attr_seek(struct file_descriptor *, off_t pos, int seek_type);
207 static void attr_free_fd(struct file_descriptor *);
208 static status_t attr_close(struct file_descriptor *);
209 static status_t attr_read_stat(struct file_descriptor *, struct stat *);
210 static status_t attr_write_stat(struct file_descriptor *, const struct stat *, int statMask);
211 static status_t index_dir_read(struct file_descriptor *, struct dirent *buffer, size_t bufferSize, uint32 *_count);
212 static status_t index_dir_rewind(struct file_descriptor *);
213 static void index_dir_free_fd(struct file_descriptor *);
214 static status_t index_dir_close(struct file_descriptor *);
215 static status_t query_read(struct file_descriptor *, struct dirent *buffer, size_t bufferSize, uint32 *_count);
216 static status_t query_rewind(struct file_descriptor *);
217 static void query_free_fd(struct file_descriptor *);
218 static status_t query_close(struct file_descriptor *);
219 
220 static status_t common_ioctl(struct file_descriptor *, ulong, void *buf, size_t len);
221 static status_t common_read_stat(struct file_descriptor *, struct stat *);
222 static status_t common_write_stat(struct file_descriptor *, const struct stat *, int statMask);
223 
224 static status_t vnode_path_to_vnode(struct vnode *vnode, char *path,
225 	bool traverseLeafLink, int count, struct vnode **_vnode, int *_type);
226 static status_t dir_vnode_to_path(struct vnode *vnode, char *buffer, size_t bufferSize);
227 static status_t fd_and_path_to_vnode(int fd, char *path, bool traverseLeafLink,
228 	struct vnode **_vnode, bool kernel);
229 static void inc_vnode_ref_count(struct vnode *vnode);
230 static status_t dec_vnode_ref_count(struct vnode *vnode, bool reenter);
231 static inline void put_vnode(struct vnode *vnode);
232 
233 static struct fd_ops sFileOps = {
234 	file_read,
235 	file_write,
236 	file_seek,
237 	common_ioctl,
238 	file_select,
239 	file_deselect,
240 	NULL,		// read_dir()
241 	NULL,		// rewind_dir()
242 	common_read_stat,
243 	common_write_stat,
244 	file_close,
245 	file_free_fd
246 };
247 
248 static struct fd_ops sDirectoryOps = {
249 	NULL,		// read()
250 	NULL,		// write()
251 	NULL,		// seek()
252 	common_ioctl,
253 	NULL,		// select()
254 	NULL,		// deselect()
255 	dir_read,
256 	dir_rewind,
257 	common_read_stat,
258 	common_write_stat,
259 	dir_close,
260 	dir_free_fd
261 };
262 
263 static struct fd_ops sAttributeDirectoryOps = {
264 	NULL,		// read()
265 	NULL,		// write()
266 	NULL,		// seek()
267 	common_ioctl,
268 	NULL,		// select()
269 	NULL,		// deselect()
270 	attr_dir_read,
271 	attr_dir_rewind,
272 	common_read_stat,
273 	common_write_stat,
274 	attr_dir_close,
275 	attr_dir_free_fd
276 };
277 
278 static struct fd_ops sAttributeOps = {
279 	attr_read,
280 	attr_write,
281 	attr_seek,
282 	common_ioctl,
283 	NULL,		// select()
284 	NULL,		// deselect()
285 	NULL,		// read_dir()
286 	NULL,		// rewind_dir()
287 	attr_read_stat,
288 	attr_write_stat,
289 	attr_close,
290 	attr_free_fd
291 };
292 
293 static struct fd_ops sIndexDirectoryOps = {
294 	NULL,		// read()
295 	NULL,		// write()
296 	NULL,		// seek()
297 	NULL,		// ioctl()
298 	NULL,		// select()
299 	NULL,		// deselect()
300 	index_dir_read,
301 	index_dir_rewind,
302 	NULL,		// read_stat()
303 	NULL,		// write_stat()
304 	index_dir_close,
305 	index_dir_free_fd
306 };
307 
308 #if 0
309 static struct fd_ops sIndexOps = {
310 	NULL,		// read()
311 	NULL,		// write()
312 	NULL,		// seek()
313 	NULL,		// ioctl()
314 	NULL,		// select()
315 	NULL,		// deselect()
316 	NULL,		// dir_read()
317 	NULL,		// dir_rewind()
318 	index_read_stat,	// read_stat()
319 	NULL,		// write_stat()
320 	NULL,		// dir_close()
321 	NULL		// free_fd()
322 };
323 #endif
324 
325 static struct fd_ops sQueryOps = {
326 	NULL,		// read()
327 	NULL,		// write()
328 	NULL,		// seek()
329 	NULL,		// ioctl()
330 	NULL,		// select()
331 	NULL,		// deselect()
332 	query_read,
333 	query_rewind,
334 	NULL,		// read_stat()
335 	NULL,		// write_stat()
336 	query_close,
337 	query_free_fd
338 };
339 
340 
341 // VNodePutter
342 class VNodePutter {
343 public:
344 	VNodePutter(struct vnode *vnode = NULL) : fVNode(vnode) {}
345 
346 	~VNodePutter()
347 	{
348 		Put();
349 	}
350 
351 	void SetTo(struct vnode *vnode)
352 	{
353 		Put();
354 		fVNode = vnode;
355 	}
356 
357 	void Put()
358 	{
359 		if (fVNode) {
360 			put_vnode(fVNode);
361 			fVNode = NULL;
362 		}
363 	}
364 
365 	struct vnode *Detach()
366 	{
367 		struct vnode *vnode = fVNode;
368 		fVNode = NULL;
369 		return vnode;
370 	}
371 
372 private:
373 	struct vnode *fVNode;
374 };
375 
376 
377 class FDCloser {
378 public:
379 	FDCloser() : fFD(-1), fKernel(true) {}
380 
381 	FDCloser(int fd, bool kernel) : fFD(fd), fKernel(kernel) {}
382 
383 	~FDCloser()
384 	{
385 		Close();
386 	}
387 
388 	void SetTo(int fd, bool kernel)
389 	{
390 		Close();
391 		fFD = fd;
392 		fKernel = kernel;
393 	}
394 
395 	void Close()
396 	{
397 		if (fFD >= 0) {
398 			if (fKernel)
399 				_kern_close(fFD);
400 			else
401 				_user_close(fFD);
402 			fFD = -1;
403 		}
404 	}
405 
406 	int Detach()
407 	{
408 		int fd = fFD;
409 		fFD = -1;
410 		return fd;
411 	}
412 
413 private:
414 	int		fFD;
415 	bool	fKernel;
416 };
417 
418 
419 static int
420 mount_compare(void *_m, const void *_key)
421 {
422 	struct fs_mount *mount = (fs_mount *)_m;
423 	const mount_id *id = (mount_id *)_key;
424 
425 	if (mount->id == *id)
426 		return 0;
427 
428 	return -1;
429 }
430 
431 
432 static uint32
433 mount_hash(void *_m, const void *_key, uint32 range)
434 {
435 	struct fs_mount *mount = (fs_mount *)_m;
436 	const mount_id *id = (mount_id *)_key;
437 
438 	if (mount)
439 		return mount->id % range;
440 
441 	return *id % range;
442 }
443 
444 
445 /** Finds the mounted device (the fs_mount structure) with the given ID.
446  *	Note, you must hold the gMountMutex lock when you call this function.
447  */
448 
449 static struct fs_mount *
450 find_mount(mount_id id)
451 {
452 	ASSERT_LOCKED_MUTEX(&sMountMutex);
453 
454 	return (fs_mount *)hash_lookup(sMountsTable, (void *)&id);
455 }
456 
457 
458 static struct fs_mount *
459 get_mount(mount_id id)
460 {
461 	struct fs_mount *mount;
462 
463 	mutex_lock(&sMountMutex);
464 
465 	mount = find_mount(id);
466 	if (mount) {
467 		// ToDo: the volume is locked (against removal) by locking
468 		//	its root node - investigate if that's a good idea
469 		if (mount->root_vnode)
470 			inc_vnode_ref_count(mount->root_vnode);
471 		else
472 			mount = NULL;
473 	}
474 
475 	mutex_unlock(&sMountMutex);
476 
477 	return mount;
478 }
479 
480 
481 static void
482 put_mount(struct fs_mount *mount)
483 {
484 	if (mount)
485 		put_vnode(mount->root_vnode);
486 }
487 
488 
489 static status_t
490 put_file_system(file_system_module_info *fs)
491 {
492 	return put_module(fs->info.name);
493 }
494 
495 
496 /**	Tries to open the specified file system module.
497  *	Accepts a file system name of the form "bfs" or "file_systems/bfs/v1".
498  *	Returns a pointer to file system module interface, or NULL if it
499  *	could not open the module.
500  */
501 
502 static file_system_module_info *
503 get_file_system(const char *fsName)
504 {
505 	char name[B_FILE_NAME_LENGTH];
506 	if (strncmp(fsName, "file_systems/", strlen("file_systems/"))) {
507 		// construct module name if we didn't get one
508 		// (we currently support only one API)
509 		snprintf(name, sizeof(name), "file_systems/%s/v1", fsName);
510 		fsName = NULL;
511 	}
512 
513 	file_system_module_info *info;
514 	if (get_module(fsName ? fsName : name, (module_info **)&info) != B_OK)
515 		return NULL;
516 
517 	return info;
518 }
519 
520 
521 /**	Accepts a file system name of the form "bfs" or "file_systems/bfs/v1"
522  *	and returns a compatible fs_info.fsh_name name ("bfs" in both cases).
523  *	The name is allocated for you, and you have to free() it when you're
524  *	done with it.
525  *	Returns NULL if the required memory is no available.
526  */
527 
528 static char *
529 get_file_system_name(const char *fsName)
530 {
531 	const size_t length = strlen("file_systems/");
532 
533 	if (strncmp(fsName, "file_systems/", length)) {
534 		// the name already seems to be the module's file name
535 		return strdup(fsName);
536 	}
537 
538 	fsName += length;
539 	const char *end = strchr(fsName, '/');
540 	if (end == NULL) {
541 		// this doesn't seem to be a valid name, but well...
542 		return strdup(fsName);
543 	}
544 
545 	// cut off the trailing /v1
546 
547 	char *name = (char *)malloc(end + 1 - fsName);
548 	if (name == NULL)
549 		return NULL;
550 
551 	strlcpy(name, fsName, end + 1 - fsName);
552 	return name;
553 }
554 
555 
556 static int
557 vnode_compare(void *_vnode, const void *_key)
558 {
559 	struct vnode *vnode = (struct vnode *)_vnode;
560 	const struct vnode_hash_key *key = (vnode_hash_key *)_key;
561 
562 	if (vnode->device == key->device && vnode->id == key->vnode)
563 		return 0;
564 
565 	return -1;
566 }
567 
568 
569 static uint32
570 vnode_hash(void *_vnode, const void *_key, uint32 range)
571 {
572 	struct vnode *vnode = (struct vnode *)_vnode;
573 	const struct vnode_hash_key *key = (vnode_hash_key *)_key;
574 
575 #define VHASH(mountid, vnodeid) (((uint32)((vnodeid) >> 32) + (uint32)(vnodeid)) ^ (uint32)(mountid))
576 
577 	if (vnode != NULL)
578 		return (VHASH(vnode->device, vnode->id) % range);
579 
580 	return (VHASH(key->device, key->vnode) % range);
581 
582 #undef VHASH
583 }
584 
585 
586 static void
587 add_vnode_to_mount_list(struct vnode *vnode, struct fs_mount *mount)
588 {
589 	recursive_lock_lock(&mount->rlock);
590 
591 	list_add_link_to_head(&mount->vnodes, &vnode->mount_link);
592 
593 	recursive_lock_unlock(&mount->rlock);
594 }
595 
596 
597 static void
598 remove_vnode_from_mount_list(struct vnode *vnode, struct fs_mount *mount)
599 {
600 	recursive_lock_lock(&mount->rlock);
601 
602 	list_remove_link(&vnode->mount_link);
603 	vnode->mount_link.next = vnode->mount_link.prev = NULL;
604 
605 	recursive_lock_unlock(&mount->rlock);
606 }
607 
608 
609 static status_t
610 create_new_vnode(struct vnode **_vnode, mount_id mountID, vnode_id vnodeID)
611 {
612 	FUNCTION(("create_new_vnode()\n"));
613 
614 	struct vnode *vnode = (struct vnode *)malloc(sizeof(struct vnode));
615 	if (vnode == NULL)
616 		return B_NO_MEMORY;
617 
618 	// initialize basic values
619 	memset(vnode, 0, sizeof(struct vnode));
620 	vnode->device = mountID;
621 	vnode->id = vnodeID;
622 
623 	// add the vnode to the mount structure
624 	mutex_lock(&sMountMutex);
625 	vnode->mount = find_mount(mountID);
626 	if (!vnode->mount || vnode->mount->unmounting) {
627 		mutex_unlock(&sMountMutex);
628 		free(vnode);
629 		return B_ENTRY_NOT_FOUND;
630 	}
631 
632 	hash_insert(sVnodeTable, vnode);
633 	add_vnode_to_mount_list(vnode, vnode->mount);
634 
635 	mutex_unlock(&sMountMutex);
636 
637 	vnode->ref_count = 1;
638 	*_vnode = vnode;
639 
640 	return B_OK;
641 }
642 
643 
644 /**	Frees the vnode and all resources it has acquired.
645  *	Will also make sure that any cache modifications are written back.
646  */
647 
648 static void
649 free_vnode(struct vnode *vnode, bool reenter)
650 {
651 	ASSERT(vnode->ref_count == 0 && vnode->busy);
652 
653 	// write back any changes in this vnode's cache -- but only
654 	// if the vnode won't be deleted, in which case the changes
655 	// will be discarded
656 
657 	if (vnode->cache && !vnode->remove)
658 		vm_cache_write_modified(vnode->cache);
659 
660 	if (!vnode->unpublished) {
661 		if (vnode->remove)
662 			FS_CALL(vnode, remove_vnode)(vnode->mount->cookie, vnode->private_node, reenter);
663 		else
664 			FS_CALL(vnode, put_vnode)(vnode->mount->cookie, vnode->private_node, reenter);
665 	}
666 
667 	// if we have a vm_cache attached, remove it
668 	if (vnode->cache)
669 		vm_cache_release_ref(vnode->cache);
670 
671 	vnode->cache = NULL;
672 
673 	remove_vnode_from_mount_list(vnode, vnode->mount);
674 
675 	free(vnode);
676 }
677 
678 
679 /**	\brief Decrements the reference counter of the given vnode and deletes it,
680  *	if the counter dropped to 0.
681  *
682  *	The caller must, of course, own a reference to the vnode to call this
683  *	function.
684  *	The caller must not hold the sVnodeMutex or the sMountMutex.
685  *
686  *	\param vnode the vnode.
687  *	\param reenter \c true, if this function is called (indirectly) from within
688  *		   a file system.
689  *	\return \c B_OK, if everything went fine, an error code otherwise.
690  */
691 
692 static status_t
693 dec_vnode_ref_count(struct vnode *vnode, bool reenter)
694 {
695 	int32 oldRefCount;
696 
697 	mutex_lock(&sVnodeMutex);
698 
699 	if (vnode->busy)
700 		panic("dec_vnode_ref_count called on vnode that was busy! vnode %p\n", vnode);
701 
702 	oldRefCount = atomic_add(&vnode->ref_count, -1);
703 
704 	PRINT(("dec_vnode_ref_count: vnode %p, ref now %ld\n", vnode, vnode->ref_count));
705 
706 	if (oldRefCount == 1) {
707 		bool freeNode = false;
708 
709 		// Just insert the vnode into an unused list if we don't need
710 		// to delete it
711 		if (vnode->remove) {
712 			hash_remove(sVnodeTable, vnode);
713 			vnode->busy = true;
714 			freeNode = true;
715 		} else {
716 			list_add_item(&sUnusedVnodeList, vnode);
717 			if (++sUnusedVnodes > kMaxUnusedVnodes) {
718 				// there are too many unused vnodes so we free the oldest one
719 				// ToDo: evaluate this mechanism
720 				vnode = (struct vnode *)list_remove_head_item(&sUnusedVnodeList);
721 				hash_remove(sVnodeTable, vnode);
722 				vnode->busy = true;
723 				freeNode = true;
724 				sUnusedVnodes--;
725 			}
726 		}
727 
728 		mutex_unlock(&sVnodeMutex);
729 
730 		if (freeNode)
731 			free_vnode(vnode, reenter);
732 	} else
733 		mutex_unlock(&sVnodeMutex);
734 
735 	return B_OK;
736 }
737 
738 
739 /**	\brief Increments the reference counter of the given vnode.
740  *
741  *	The caller must either already have a reference to the vnode or hold
742  *	the sVnodeMutex.
743  *
744  *	\param vnode the vnode.
745  */
746 
747 static void
748 inc_vnode_ref_count(struct vnode *vnode)
749 {
750 	atomic_add(&vnode->ref_count, 1);
751 	PRINT(("inc_vnode_ref_count: vnode %p, ref now %ld\n", vnode, vnode->ref_count));
752 }
753 
754 
755 /**	\brief Looks up a vnode by mount and node ID in the sVnodeTable.
756  *
757  *	The caller must hold the sVnodeMutex.
758  *
759  *	\param mountID the mount ID.
760  *	\param vnodeID the node ID.
761  *
762  *	\return The vnode structure, if it was found in the hash table, \c NULL
763  *			otherwise.
764  */
765 
766 static struct vnode *
767 lookup_vnode(mount_id mountID, vnode_id vnodeID)
768 {
769 	struct vnode_hash_key key;
770 
771 	key.device = mountID;
772 	key.vnode = vnodeID;
773 
774 	return (vnode *)hash_lookup(sVnodeTable, &key);
775 }
776 
777 
778 /**	\brief Retrieves a vnode for a given mount ID, node ID pair.
779  *
780  *	If the node is not yet in memory, it will be loaded.
781  *
782  *	The caller must not hold the sVnodeMutex or the sMountMutex.
783  *
784  *	\param mountID the mount ID.
785  *	\param vnodeID the node ID.
786  *	\param _vnode Pointer to a vnode* variable into which the pointer to the
787  *		   retrieved vnode structure shall be written.
788  *	\param reenter \c true, if this function is called (indirectly) from within
789  *		   a file system.
790  *	\return \c B_OK, if everything when fine, an error code otherwise.
791  */
792 
793 static status_t
794 get_vnode(mount_id mountID, vnode_id vnodeID, struct vnode **_vnode, int reenter)
795 {
796 	FUNCTION(("get_vnode: mountid %ld vnid 0x%Lx %p\n", mountID, vnodeID, _vnode));
797 
798 	mutex_lock(&sVnodeMutex);
799 
800 restart:
801 	struct vnode *vnode = lookup_vnode(mountID, vnodeID);
802 	if (vnode && vnode->busy) {
803 		// ToDo: this is an endless loop if the vnode is not
804 		//	becoming unbusy anymore (for whatever reason)
805 		mutex_unlock(&sVnodeMutex);
806 		snooze(10000); // 10 ms
807 		mutex_lock(&sVnodeMutex);
808 		goto restart;
809 	}
810 
811 	PRINT(("get_vnode: tried to lookup vnode, got %p\n", vnode));
812 
813 	status_t status;
814 
815 	if (vnode) {
816 		if (vnode->ref_count == 0) {
817 			// this vnode has been unused before
818 			list_remove_item(&sUnusedVnodeList, vnode);
819 		}
820 		inc_vnode_ref_count(vnode);
821 	} else {
822 		// we need to create a new vnode and read it in
823 		status = create_new_vnode(&vnode, mountID, vnodeID);
824 		if (status < B_OK)
825 			goto err;
826 
827 		vnode->busy = true;
828 		mutex_unlock(&sVnodeMutex);
829 
830 		status = FS_CALL(vnode, get_vnode)(vnode->mount->cookie, vnodeID, &vnode->private_node, reenter);
831 		if (status < B_OK || vnode->private_node == NULL) {
832 			if (status == B_NO_ERROR)
833 				status = B_BAD_VALUE;
834 		}
835 		mutex_lock(&sVnodeMutex);
836 
837 		if (status < B_OK)
838 			goto err1;
839 
840 		vnode->busy = false;
841 	}
842 
843 	mutex_unlock(&sVnodeMutex);
844 
845 	PRINT(("get_vnode: returning %p\n", vnode));
846 
847 	*_vnode = vnode;
848 	return B_OK;
849 
850 err1:
851 	hash_remove(sVnodeTable, vnode);
852 	remove_vnode_from_mount_list(vnode, vnode->mount);
853 err:
854 	mutex_unlock(&sVnodeMutex);
855 	if (vnode)
856 		free(vnode);
857 
858 	return status;
859 }
860 
861 
862 /**	\brief Decrements the reference counter of the given vnode and deletes it,
863  *	if the counter dropped to 0.
864  *
865  *	The caller must, of course, own a reference to the vnode to call this
866  *	function.
867  *	The caller must not hold the sVnodeMutex or the sMountMutex.
868  *
869  *	\param vnode the vnode.
870  */
871 
872 static inline void
873 put_vnode(struct vnode *vnode)
874 {
875 	dec_vnode_ref_count(vnode, false);
876 }
877 
878 
879 static status_t
880 create_advisory_locking(struct vnode *vnode)
881 {
882 	status_t status;
883 
884 	struct advisory_locking *locking = (struct advisory_locking *)malloc(sizeof(struct advisory_locking));
885 	if (locking == NULL)
886 		return B_NO_MEMORY;
887 
888 	locking->wait_sem = create_sem(0, "advisory lock");
889 	if (locking->wait_sem < B_OK) {
890 		status = locking->wait_sem;
891 		goto err1;
892 	}
893 
894 	locking->lock = create_sem(1, "advisory locking");
895 	if (locking->lock < B_OK) {
896 		status = locking->lock;
897 		goto err2;
898 	}
899 
900 	list_init(&locking->locks);
901 	vnode->advisory_locking = locking;
902 	return B_OK;
903 
904 err2:
905 	delete_sem(locking->wait_sem);
906 err1:
907 	free(locking);
908 	return status;
909 }
910 
911 
912 static inline void
913 put_advisory_locking(struct advisory_locking *locking)
914 {
915 	release_sem(locking->lock);
916 }
917 
918 
919 static struct advisory_locking *
920 get_advisory_locking(struct vnode *vnode)
921 {
922 	mutex_lock(&sVnodeMutex);
923 
924 	struct advisory_locking *locking = vnode->advisory_locking;
925 	if (locking != NULL)
926 		acquire_sem(locking->lock);
927 
928 	mutex_unlock(&sVnodeMutex);
929 	return locking;
930 }
931 
932 
933 static status_t
934 get_advisory_lock(struct vnode *vnode, struct flock *flock)
935 {
936 	return B_ERROR;
937 }
938 
939 
940 /**	Removes the specified lock, or all locks of the calling team
941  *	if \a flock is NULL.
942  */
943 
944 static status_t
945 release_advisory_lock(struct vnode *vnode, struct flock *flock)
946 {
947 	FUNCTION(("release_advisory_lock(vnode = %p, flock = %p)\n", vnode, flock));
948 
949 	struct advisory_locking *locking = get_advisory_locking(vnode);
950 	if (locking == NULL)
951 		return flock != NULL ? B_BAD_VALUE : B_OK;
952 
953 	team_id team = team_get_current_team_id();
954 
955 	// find matching lock entry
956 
957 	status_t status = B_BAD_VALUE;
958 	struct advisory_lock *lock = NULL;
959 	while ((lock = (struct advisory_lock *)list_get_next_item(&locking->locks, lock)) != NULL) {
960 		if (lock->team == team && (flock == NULL || (flock != NULL
961 			&& lock->offset == flock->l_start
962 			&& lock->length == flock->l_len))) {
963 			// we found our lock, free it
964 			list_remove_item(&locking->locks, lock);
965 			free(lock);
966 			status = B_OK;
967 			break;
968 		}
969 	}
970 
971 	bool removeLocking = list_is_empty(&locking->locks);
972 	release_sem_etc(locking->wait_sem, 1, B_RELEASE_ALL);
973 
974 	put_advisory_locking(locking);
975 
976 	if (status < B_OK)
977 		return status;
978 
979 	if (removeLocking) {
980 		// we can remove the whole advisory locking structure; it's no longer used
981 		mutex_lock(&sVnodeMutex);
982 		locking = vnode->advisory_locking;
983 		if (locking != NULL)
984 			acquire_sem(locking->lock);
985 
986 		// the locking could have been changed in the mean time
987 		if (list_is_empty(&locking->locks))
988 			vnode->advisory_locking = NULL;
989 		else {
990 			removeLocking = false;
991 			release_sem_etc(locking->lock, 1, B_DO_NOT_RESCHEDULE);
992 		}
993 
994 		mutex_unlock(&sVnodeMutex);
995 	}
996 	if (removeLocking) {
997 		// we've detached the locking from the vnode, so we can safely delete it
998 		delete_sem(locking->lock);
999 		delete_sem(locking->wait_sem);
1000 		free(locking);
1001 	}
1002 
1003 	return B_OK;
1004 }
1005 
1006 
1007 static status_t
1008 acquire_advisory_lock(struct vnode *vnode, struct flock *flock, bool wait)
1009 {
1010 	FUNCTION(("acquire_advisory_lock(vnode = %p, flock = %p, wait = %s)\n",
1011 		vnode, flock, wait ? "yes" : "no"));
1012 
1013 	bool shared = flock->l_type == F_RDLCK;
1014 	status_t status = B_OK;
1015 
1016 restart:
1017 	// if this vnode has an advisory_locking structure attached,
1018 	// lock that one and search for any colliding lock
1019 	struct advisory_locking *locking = get_advisory_locking(vnode);
1020 	sem_id waitForLock = -1;
1021 
1022 	if (locking != NULL) {
1023 		// test for collisions
1024 		struct advisory_lock *lock = NULL;
1025 		while ((lock = (struct advisory_lock *)list_get_next_item(&locking->locks, lock)) != NULL) {
1026 			if (lock->offset <= flock->l_start + flock->l_len
1027 				&& lock->offset + lock->length > flock->l_start) {
1028 				// locks do overlap
1029 				if (!shared || !lock->shared) {
1030 					// we need to wait
1031 					waitForLock = locking->wait_sem;
1032 					break;
1033 				}
1034 			}
1035 		}
1036 
1037 		if (waitForLock < B_OK || !wait)
1038 			put_advisory_locking(locking);
1039 	}
1040 
1041 	// wait for the lock if we have to, or else return immediately
1042 
1043 	if (waitForLock >= B_OK) {
1044 		if (!wait)
1045 			status = B_PERMISSION_DENIED;
1046 		else {
1047 			status = switch_sem_etc(locking->lock, waitForLock, 1, B_CAN_INTERRUPT, 0);
1048 			if (status == B_OK) {
1049 				// see if we're still colliding
1050 				goto restart;
1051 			}
1052 		}
1053 	}
1054 
1055 	if (status < B_OK)
1056 		return status;
1057 
1058 	// install new lock
1059 
1060 	mutex_lock(&sVnodeMutex);
1061 
1062 	locking = vnode->advisory_locking;
1063 	if (locking == NULL) {
1064 		status = create_advisory_locking(vnode);
1065 		locking = vnode->advisory_locking;
1066 	}
1067 
1068 	if (locking != NULL)
1069 		acquire_sem(locking->lock);
1070 
1071 	mutex_unlock(&sVnodeMutex);
1072 
1073 	if (status < B_OK)
1074 		return status;
1075 
1076 	struct advisory_lock *lock = (struct advisory_lock *)malloc(sizeof(struct advisory_lock));
1077 	if (lock == NULL) {
1078 		if (waitForLock >= B_OK)
1079 			release_sem_etc(waitForLock, 1, B_RELEASE_ALL);
1080 		release_sem(locking->lock);
1081 		return B_NO_MEMORY;
1082 	}
1083 
1084 	lock->team = team_get_current_team_id();
1085 	// values must already be normalized when getting here
1086 	lock->offset = flock->l_start;
1087 	lock->length = flock->l_len;
1088 	lock->shared = shared;
1089 
1090 	list_add_item(&locking->locks, lock);
1091 	release_sem(locking->lock);
1092 
1093 	return status;
1094 }
1095 
1096 
1097 static status_t
1098 normalize_flock(struct file_descriptor *descriptor, struct flock *flock)
1099 {
1100 	switch (flock->l_whence) {
1101 		case SEEK_SET:
1102 			break;
1103 		case SEEK_CUR:
1104 			flock->l_start += descriptor->pos;
1105 			break;
1106 		case SEEK_END:
1107 		{
1108 			struct vnode *vnode = descriptor->u.vnode;
1109 			struct stat stat;
1110 			status_t status;
1111 
1112 			if (FS_CALL(vnode, read_stat) == NULL)
1113 				return EOPNOTSUPP;
1114 
1115 			status = FS_CALL(vnode, read_stat)(vnode->mount->cookie, vnode->private_node, &stat);
1116 			if (status < B_OK)
1117 				return status;
1118 
1119 			flock->l_start += stat.st_size;
1120 			break;
1121 		}
1122 		default:
1123 			return B_BAD_VALUE;
1124 	}
1125 
1126 	if (flock->l_start < 0)
1127 		flock->l_start = 0;
1128 	if (flock->l_len == 0)
1129 		flock->l_len = OFF_MAX;
1130 
1131 	// don't let the offset and length overflow
1132 	if (flock->l_start > 0 && OFF_MAX - flock->l_start < flock->l_len)
1133 		flock->l_len = OFF_MAX - flock->l_start;
1134 
1135 	if (flock->l_len < 0) {
1136 		// a negative length reverses the region
1137 		flock->l_start += flock->l_len;
1138 		flock->l_len = -flock->l_len;
1139 	}
1140 
1141 	return B_OK;
1142 }
1143 
1144 
1145 /**	\brief Resolves a mount point vnode to the volume root vnode it is covered
1146  *		   by.
1147  *
1148  *	Given an arbitrary vnode, the function checks, whether the node is covered
1149  *	by the root of a volume. If it is the function obtains a reference to the
1150  *	volume root node and returns it.
1151  *
1152  *	\param vnode The vnode in question.
1153  *	\return The volume root vnode the vnode cover is covered by, if it is
1154  *			indeed a mount point, or \c NULL otherwise.
1155  */
1156 
1157 static struct vnode *
1158 resolve_mount_point_to_volume_root(struct vnode *vnode)
1159 {
1160 	if (!vnode)
1161 		return NULL;
1162 
1163 	struct vnode *volumeRoot = NULL;
1164 
1165 	recursive_lock_lock(&sMountOpLock);
1166 	if (vnode->covered_by) {
1167 		volumeRoot = vnode->covered_by;
1168 		inc_vnode_ref_count(volumeRoot);
1169 	}
1170 	recursive_lock_unlock(&sMountOpLock);
1171 
1172 	return volumeRoot;
1173 }
1174 
1175 
1176 /**	\brief Resolves a mount point vnode to the volume root vnode it is covered
1177  *		   by.
1178  *
1179  *	Given an arbitrary vnode (identified by mount and node ID), the function
1180  *	checks, whether the node is covered by the root of a volume. If it is the
1181  *	function returns the mount and node ID of the volume root node. Otherwise
1182  *	it simply returns the supplied mount and node ID.
1183  *
1184  *	In case of error (e.g. the supplied node could not be found) the variables
1185  *	for storing the resolved mount and node ID remain untouched and an error
1186  *	code is returned.
1187  *
1188  *	\param mountID The mount ID of the vnode in question.
1189  *	\param nodeID The node ID of the vnode in question.
1190  *	\param resolvedMountID Pointer to storage for the resolved mount ID.
1191  *	\param resolvedNodeID Pointer to storage for the resolved node ID.
1192  *	\return
1193  *	- \c B_OK, if everything went fine,
1194  *	- another error code, if something went wrong.
1195  */
1196 
1197 status_t
1198 resolve_mount_point_to_volume_root(mount_id mountID, vnode_id nodeID,
1199 	mount_id *resolvedMountID, vnode_id *resolvedNodeID)
1200 {
1201 	// get the node
1202 	struct vnode *node;
1203 	status_t error = get_vnode(mountID, nodeID, &node, false);
1204 	if (error != B_OK)
1205 		return error;
1206 
1207 
1208 	// resolve the node
1209 	struct vnode *resolvedNode = resolve_mount_point_to_volume_root(node);
1210 	if (resolvedNode) {
1211 		put_vnode(node);
1212 		node = resolvedNode;
1213 	}
1214 
1215 	// set the return values
1216 	*resolvedMountID = node->device;
1217 	*resolvedNodeID = node->id;
1218 
1219 	put_vnode(node);
1220 
1221 	return B_OK;
1222 }
1223 
1224 
1225 /**	\brief Resolves a volume root vnode to the underlying mount point vnode.
1226  *
1227  *	Given an arbitrary vnode, the function checks, whether the node is the
1228  *	root of a volume. If it is (and if it is not "/"), the function obtains
1229  *	a reference to the underlying mount point node and returns it.
1230  *
1231  *	\param vnode The vnode in question.
1232  *	\return The mount point vnode the vnode covers, if it is indeed a volume
1233  *			root and not "/", or \c NULL otherwise.
1234  */
1235 
1236 static struct vnode *
1237 resolve_volume_root_to_mount_point(struct vnode *vnode)
1238 {
1239 	if (!vnode)
1240 		return NULL;
1241 
1242 	struct vnode *mountPoint = NULL;
1243 
1244 	recursive_lock_lock(&sMountOpLock);
1245 	struct fs_mount *mount = vnode->mount;
1246 	if (vnode == mount->root_vnode && mount->covers_vnode) {
1247 		mountPoint = mount->covers_vnode;
1248 		inc_vnode_ref_count(mountPoint);
1249 	}
1250 	recursive_lock_unlock(&sMountOpLock);
1251 
1252 	return mountPoint;
1253 }
1254 
1255 
1256 /**	\brief Gets the directory path and leaf name for a given path.
1257  *
1258  *	The supplied \a path is transformed to refer to the directory part of
1259  *	the entry identified by the original path, and into the buffer \a filename
1260  *	the leaf name of the original entry is written.
1261  *	Neither the returned path nor the leaf name can be expected to be
1262  *	canonical.
1263  *
1264  *	\param path The path to be analyzed. Must be able to store at least one
1265  *		   additional character.
1266  *	\param filename The buffer into which the leaf name will be written.
1267  *		   Must be of size B_FILE_NAME_LENGTH at least.
1268  *	\return \c B_OK, if everything went fine, \c B_NAME_TOO_LONG, if the leaf
1269  *		   name is longer than \c B_FILE_NAME_LENGTH.
1270  */
1271 
1272 static status_t
1273 get_dir_path_and_leaf(char *path, char *filename)
1274 {
1275 	char *p = strrchr(path, '/');
1276 		// '/' are not allowed in file names!
1277 
1278 	FUNCTION(("get_dir_path_and_leaf(path = %s)\n", path));
1279 
1280 	if (!p) {
1281 		// this path is single segment with no '/' in it
1282 		// ex. "foo"
1283 		if (strlcpy(filename, path, B_FILE_NAME_LENGTH) >= B_FILE_NAME_LENGTH)
1284 			return B_NAME_TOO_LONG;
1285 		strcpy(path, ".");
1286 	} else {
1287 		p++;
1288 		if (*p == '\0') {
1289 			// special case: the path ends in '/'
1290 			strcpy(filename, ".");
1291 		} else {
1292 			// normal leaf: replace the leaf portion of the path with a '.'
1293 			if (strlcpy(filename, p, B_FILE_NAME_LENGTH)
1294 				>= B_FILE_NAME_LENGTH) {
1295 				return B_NAME_TOO_LONG;
1296 			}
1297 		}
1298 		p[0] = '.';
1299 		p[1] = '\0';
1300 	}
1301 	return B_OK;
1302 }
1303 
1304 
1305 static status_t
1306 entry_ref_to_vnode(mount_id mountID, vnode_id directoryID, const char *name, struct vnode **_vnode)
1307 {
1308 	char clonedName[B_FILE_NAME_LENGTH + 1];
1309 	if (strlcpy(clonedName, name, B_FILE_NAME_LENGTH) >= B_FILE_NAME_LENGTH)
1310 		return B_NAME_TOO_LONG;
1311 
1312 	// get the directory vnode and let vnode_path_to_vnode() do the rest
1313 	struct vnode *directory;
1314 
1315 	status_t status = get_vnode(mountID, directoryID, &directory, false);
1316 	if (status < 0)
1317 		return status;
1318 
1319 	return vnode_path_to_vnode(directory, clonedName, false, 0, _vnode, NULL);
1320 }
1321 
1322 
1323 /**	Returns the vnode for the relative path starting at the specified \a vnode.
1324  *	\a path must not be NULL.
1325  *	If it returns successfully, \a path contains the name of the last path
1326  *	component.
1327  */
1328 
1329 static status_t
1330 vnode_path_to_vnode(struct vnode *vnode, char *path, bool traverseLeafLink,
1331 	int count, struct vnode **_vnode, int *_type)
1332 {
1333 	status_t status = 0;
1334 	int type = 0;
1335 
1336 	FUNCTION(("vnode_path_to_vnode(vnode = %p, path = %s)\n", vnode, path));
1337 
1338 	if (path == NULL)
1339 		return B_BAD_VALUE;
1340 
1341 	while (true) {
1342 		struct vnode *nextVnode;
1343 		vnode_id vnodeID;
1344 		char *nextPath;
1345 
1346 		PRINT(("vnode_path_to_vnode: top of loop. p = %p, p = '%s'\n", path, path));
1347 
1348 		// done?
1349 		if (path[0] == '\0')
1350 			break;
1351 
1352 		// walk to find the next path component ("path" will point to a single
1353 		// path component), and filter out multiple slashes
1354 		for (nextPath = path + 1; *nextPath != '\0' && *nextPath != '/'; nextPath++);
1355 
1356 		if (*nextPath == '/') {
1357 			*nextPath = '\0';
1358 			do
1359 				nextPath++;
1360 			while (*nextPath == '/');
1361 		}
1362 
1363 		// See if the '..' is at the root of a mount and move to the covered
1364 		// vnode so we pass the '..' path to the underlying filesystem
1365 		if (!strcmp("..", path)
1366 			&& vnode->mount->root_vnode == vnode
1367 			&& vnode->mount->covers_vnode) {
1368 			nextVnode = vnode->mount->covers_vnode;
1369 			inc_vnode_ref_count(nextVnode);
1370 			put_vnode(vnode);
1371 			vnode = nextVnode;
1372 		}
1373 
1374 		// Check if we have the right to search the current directory vnode.
1375 		// If a file system doesn't have the access() function, we assume that
1376 		// searching a directory is always allowed
1377 		if (FS_CALL(vnode, access))
1378 			status = FS_CALL(vnode, access)(vnode->mount->cookie, vnode->private_node, X_OK);
1379 
1380 		// Tell the filesystem to get the vnode of this path component (if we got the
1381 		// permission from the call above)
1382 		if (status >= B_OK)
1383 			status = FS_CALL(vnode, lookup)(vnode->mount->cookie, vnode->private_node, path, &vnodeID, &type);
1384 
1385 		if (status < B_OK) {
1386 			put_vnode(vnode);
1387 			return status;
1388 		}
1389 
1390 		// Lookup the vnode, the call to fs_lookup should have caused a get_vnode to be called
1391 		// from inside the filesystem, thus the vnode would have to be in the list and it's
1392 		// ref count incremented at this point
1393 		mutex_lock(&sVnodeMutex);
1394 		nextVnode = lookup_vnode(vnode->device, vnodeID);
1395 		mutex_unlock(&sVnodeMutex);
1396 
1397 		if (!nextVnode) {
1398 			// pretty screwed up here - the file system found the vnode, but the hash
1399 			// lookup failed, so our internal structures are messed up
1400 			panic("path_to_vnode: could not lookup vnode (mountid 0x%lx vnid 0x%Lx)\n", vnode->device, vnodeID);
1401 			put_vnode(vnode);
1402 			return B_ENTRY_NOT_FOUND;
1403 		}
1404 
1405 		// If the new node is a symbolic link, resolve it (if we've been told to do it)
1406 		if (S_ISLNK(type) && !(!traverseLeafLink && nextPath[0] == '\0')) {
1407 			size_t bufferSize;
1408 			char *buffer;
1409 
1410 			PRINT(("traverse link\n"));
1411 
1412 			// it's not exactly nice style using goto in this way, but hey, it works :-/
1413 			if (count + 1 > MAX_SYM_LINKS) {
1414 				status = B_LINK_LIMIT;
1415 				goto resolve_link_error;
1416 			}
1417 
1418 			buffer = (char *)malloc(bufferSize = B_PATH_NAME_LENGTH);
1419 			if (buffer == NULL) {
1420 				status = B_NO_MEMORY;
1421 				goto resolve_link_error;
1422 			}
1423 
1424 			status = FS_CALL(nextVnode, read_link)(nextVnode->mount->cookie,
1425 				nextVnode->private_node, buffer, &bufferSize);
1426 			if (status < B_OK) {
1427 				free(buffer);
1428 
1429 		resolve_link_error:
1430 				put_vnode(vnode);
1431 				put_vnode(nextVnode);
1432 
1433 				return status;
1434 			}
1435 			put_vnode(nextVnode);
1436 
1437 			// Check if we start from the root directory or the current
1438 			// directory ("vnode" still points to that one).
1439 			// Cut off all leading slashes if it's the root directory
1440 			path = buffer;
1441 			if (path[0] == '/') {
1442 				// we don't need the old directory anymore
1443 				put_vnode(vnode);
1444 
1445 				while (*++path == '/')
1446 					;
1447 				vnode = sRoot;
1448 				inc_vnode_ref_count(vnode);
1449 			}
1450 			inc_vnode_ref_count(vnode);
1451 				// balance the next recursion - we will decrement the ref_count
1452 				// of the vnode, no matter if we succeeded or not
1453 
1454 			status = vnode_path_to_vnode(vnode, path, traverseLeafLink, count + 1, &nextVnode, _type);
1455 
1456 			free(buffer);
1457 
1458 			if (status < B_OK) {
1459 				put_vnode(vnode);
1460 				return status;
1461 			}
1462 		}
1463 
1464 		// decrease the ref count on the old dir we just looked up into
1465 		put_vnode(vnode);
1466 
1467 		path = nextPath;
1468 		vnode = nextVnode;
1469 
1470 		// see if we hit a mount point
1471 		struct vnode *mountPoint = resolve_mount_point_to_volume_root(vnode);
1472 		if (mountPoint) {
1473 			put_vnode(vnode);
1474 			vnode = mountPoint;
1475 		}
1476 	}
1477 
1478 	*_vnode = vnode;
1479 	if (_type)
1480 		*_type = type;
1481 
1482 	return B_OK;
1483 }
1484 
1485 
1486 static status_t
1487 path_to_vnode(char *path, bool traverseLink, struct vnode **_vnode, bool kernel)
1488 {
1489 	struct vnode *start;
1490 
1491 	FUNCTION(("path_to_vnode(path = \"%s\")\n", path));
1492 
1493 	if (!path)
1494 		return B_BAD_VALUE;
1495 
1496 	// figure out if we need to start at root or at cwd
1497 	if (*path == '/') {
1498 		if (sRoot == NULL) {
1499 			// we're a bit early, aren't we?
1500 			return B_ERROR;
1501 		}
1502 
1503 		while (*++path == '/')
1504 			;
1505 		start = sRoot;
1506 		inc_vnode_ref_count(start);
1507 	} else {
1508 		struct io_context *context = get_current_io_context(kernel);
1509 
1510 		mutex_lock(&context->io_mutex);
1511 		start = context->cwd;
1512 		inc_vnode_ref_count(start);
1513 		mutex_unlock(&context->io_mutex);
1514 	}
1515 
1516 	return vnode_path_to_vnode(start, path, traverseLink, 0, _vnode, NULL);
1517 }
1518 
1519 
1520 /** Returns the vnode in the next to last segment of the path, and returns
1521  *	the last portion in filename.
1522  *	The path buffer must be able to store at least one additional character.
1523  */
1524 
1525 static status_t
1526 path_to_dir_vnode(char *path, struct vnode **_vnode, char *filename, bool kernel)
1527 {
1528 	status_t status = get_dir_path_and_leaf(path, filename);
1529 	if (status != B_OK)
1530 		return status;
1531 
1532 	return path_to_vnode(path, true, _vnode, kernel);
1533 }
1534 
1535 
1536 /**	\brief Retrieves the directory vnode and the leaf name of an entry referred
1537  *		   to by a FD + path pair.
1538  *
1539  *	\a path must be given in either case. \a fd might be omitted, in which
1540  *	case \a path is either an absolute path or one relative to the current
1541  *	directory. If both a supplied and \a path is relative it is reckoned off
1542  *	of the directory referred to by \a fd. If \a path is absolute \a fd is
1543  *	ignored.
1544  *
1545  *	The caller has the responsibility to call put_vnode() on the returned
1546  *	directory vnode.
1547  *
1548  *	\param fd The FD. May be < 0.
1549  *	\param path The absolute or relative path. Must not be \c NULL. The buffer
1550  *	       is modified by this function. It must have at least room for a
1551  *	       string one character longer than the path it contains.
1552  *	\param _vnode A pointer to a variable the directory vnode shall be written
1553  *		   into.
1554  *	\param filename A buffer of size B_FILE_NAME_LENGTH or larger into which
1555  *		   the leaf name of the specified entry will be written.
1556  *	\param kernel \c true, if invoked from inside the kernel, \c false if
1557  *		   invoked from userland.
1558  *	\return \c B_OK, if everything went fine, another error code otherwise.
1559  */
1560 
1561 static status_t
1562 fd_and_path_to_dir_vnode(int fd, char *path, struct vnode **_vnode,
1563 	char *filename, bool kernel)
1564 {
1565 	if (!path)
1566 		return B_BAD_VALUE;
1567 	if (fd < 0)
1568 		return path_to_dir_vnode(path, _vnode, filename, kernel);
1569 
1570 	status_t status = get_dir_path_and_leaf(path, filename);
1571 	if (status != B_OK)
1572 		return status;
1573 
1574 	return fd_and_path_to_vnode(fd, path, true, _vnode, kernel);
1575 }
1576 
1577 
1578 static status_t
1579 get_vnode_name(struct vnode *vnode, struct vnode *parent,
1580 	char *name, size_t nameSize)
1581 {
1582 	VNodePutter vnodePutter;
1583 
1584 	// See if vnode is the root of a mount and move to the covered
1585 	// vnode so we get the underlying file system
1586 	if (vnode->mount->root_vnode == vnode && vnode->mount->covers_vnode != NULL) {
1587 		vnode = vnode->mount->covers_vnode;
1588 		inc_vnode_ref_count(vnode);
1589 		vnodePutter.SetTo(vnode);
1590 	}
1591 
1592 	if (FS_CALL(vnode, get_vnode_name)) {
1593 		// The FS supports getting the name of a vnode.
1594 		return FS_CALL(vnode, get_vnode_name)(vnode->mount->cookie,
1595 			vnode->private_node, name, nameSize);
1596 	}
1597 
1598 	// The FS doesn't support getting the name of a vnode. So we search the
1599 	// parent directory for the vnode, if the caller let us.
1600 
1601 	if (parent == NULL)
1602 		return EOPNOTSUPP;
1603 
1604 	fs_cookie cookie;
1605 
1606 	status_t status = FS_CALL(parent, open_dir)(parent->mount->cookie,
1607 		parent->private_node, &cookie);
1608 	if (status >= B_OK) {
1609 		char buffer[sizeof(struct dirent) + B_FILE_NAME_LENGTH];
1610 		struct dirent *dirent = (struct dirent *)buffer;
1611 		while (true) {
1612 			uint32 num = 1;
1613 			status = dir_read(parent, cookie, dirent, sizeof(buffer), &num);
1614 			if (status < B_OK)
1615 				break;
1616 
1617 			if (vnode->id == dirent->d_ino) {
1618 				// found correct entry!
1619 				if (strlcpy(name, dirent->d_name, nameSize) >= nameSize)
1620 					status = B_BUFFER_OVERFLOW;
1621 				break;
1622 			}
1623 		}
1624 		FS_CALL(vnode, close_dir)(vnode->mount->cookie, vnode->private_node, cookie);
1625 	}
1626 	return status;
1627 }
1628 
1629 
1630 /**	Gets the full path to a given directory vnode.
1631  *	It uses the fs_get_vnode_name() call to get the name of a vnode; if a
1632  *	file system doesn't support this call, it will fall back to iterating
1633  *	through the parent directory to get the name of the child.
1634  *
1635  *	To protect against circular loops, it supports a maximum tree depth
1636  *	of 256 levels.
1637  *
1638  *	Note that the path may not be correct the time this function returns!
1639  *	It doesn't use any locking to prevent returning the correct path, as
1640  *	paths aren't safe anyway: the path to a file can change at any time.
1641  *
1642  *	It might be a good idea, though, to check if the returned path exists
1643  *	in the calling function (it's not done here because of efficiency)
1644  */
1645 
1646 static status_t
1647 dir_vnode_to_path(struct vnode *vnode, char *buffer, size_t bufferSize)
1648 {
1649 	FUNCTION(("dir_vnode_to_path(%p, %p, %lu)\n", vnode, buffer, bufferSize));
1650 
1651 	/* this implementation is currently bound to B_PATH_NAME_LENGTH */
1652 	char path[B_PATH_NAME_LENGTH];
1653 	int32 insert = sizeof(path);
1654 	int32 maxLevel = 256;
1655 	int32 length;
1656 	status_t status;
1657 
1658 	if (vnode == NULL || buffer == NULL)
1659 		return EINVAL;
1660 
1661 	// we don't use get_vnode() here because this call is more
1662 	// efficient and does all we need from get_vnode()
1663 	inc_vnode_ref_count(vnode);
1664 
1665 	// resolve a volume root to its mount point
1666 	struct vnode *mountPoint = resolve_volume_root_to_mount_point(vnode);
1667 	if (mountPoint) {
1668 		put_vnode(vnode);
1669 		vnode = mountPoint;
1670 	}
1671 
1672 	path[--insert] = '\0';
1673 
1674 	while (true) {
1675 		// the name buffer is also used for fs_read_dir()
1676 		char nameBuffer[sizeof(struct dirent) + B_FILE_NAME_LENGTH];
1677 		char *name = &((struct dirent *)nameBuffer)->d_name[0];
1678 		struct vnode *parentVnode;
1679 		vnode_id parentID, id;
1680 		int type;
1681 
1682 		// lookup the parent vnode
1683 		status = FS_CALL(vnode, lookup)(vnode->mount->cookie, vnode->private_node, "..", &parentID, &type);
1684 		if (status < B_OK)
1685 			goto out;
1686 
1687 		mutex_lock(&sVnodeMutex);
1688 		parentVnode = lookup_vnode(vnode->device, parentID);
1689 		mutex_unlock(&sVnodeMutex);
1690 
1691 		if (parentVnode == NULL) {
1692 			panic("dir_vnode_to_path: could not lookup vnode (mountid 0x%lx vnid 0x%Lx)\n", vnode->device, parentID);
1693 			status = B_ENTRY_NOT_FOUND;
1694 			goto out;
1695 		}
1696 
1697 		// resolve a volume root to its mount point
1698 		mountPoint = resolve_volume_root_to_mount_point(parentVnode);
1699 		if (mountPoint) {
1700 			put_vnode(parentVnode);
1701 			parentVnode = mountPoint;
1702 			parentID = parentVnode->id;
1703 		}
1704 
1705 		bool hitRoot = (parentVnode == vnode);
1706 
1707 		// Does the file system support getting the name of a vnode?
1708 		// If so, get it here...
1709 		if (status == B_OK && FS_CALL(vnode, get_vnode_name))
1710 			status = FS_CALL(vnode, get_vnode_name)(vnode->mount->cookie, vnode->private_node, name, B_FILE_NAME_LENGTH);
1711 
1712 		// ... if not, find it out later (by iterating through
1713 		// the parent directory, searching for the id)
1714 		id = vnode->id;
1715 
1716 		// release the current vnode, we only need its parent from now on
1717 		put_vnode(vnode);
1718 		vnode = parentVnode;
1719 
1720 		if (status < B_OK)
1721 			goto out;
1722 
1723 		// ToDo: add an explicit check for loops in about 10 levels to do
1724 		// real loop detection
1725 
1726 		// don't go deeper as 'maxLevel' to prevent circular loops
1727 		if (maxLevel-- < 0) {
1728 			status = ELOOP;
1729 			goto out;
1730 		}
1731 
1732 		if (hitRoot) {
1733 			// we have reached "/", which means we have constructed the full
1734 			// path
1735 			break;
1736 		}
1737 
1738 		if (!FS_CALL(vnode, get_vnode_name)) {
1739 			// If we haven't got the vnode's name yet, we have to search for it
1740 			// in the parent directory now
1741 			fs_cookie cookie;
1742 
1743 			status = FS_CALL(vnode, open_dir)(vnode->mount->cookie, vnode->private_node, &cookie);
1744 			if (status >= B_OK) {
1745 				struct dirent *dirent = (struct dirent *)nameBuffer;
1746 				while (true) {
1747 					uint32 num = 1;
1748 					status = dir_read(vnode, cookie, dirent, sizeof(nameBuffer),
1749 						&num);
1750 
1751 					if (status < B_OK)
1752 						break;
1753 
1754 					if (id == dirent->d_ino)
1755 						// found correct entry!
1756 						break;
1757 				}
1758 				FS_CALL(vnode, close_dir)(vnode->mount->cookie, vnode->private_node, cookie);
1759 			}
1760 
1761 			if (status < B_OK)
1762 				goto out;
1763 		}
1764 
1765 		// add the name infront of the current path
1766 		name[B_FILE_NAME_LENGTH - 1] = '\0';
1767 		length = strlen(name);
1768 		insert -= length;
1769 		if (insert <= 0) {
1770 			status = ENOBUFS;
1771 			goto out;
1772 		}
1773 		memcpy(path + insert, name, length);
1774 		path[--insert] = '/';
1775 	}
1776 
1777 	// the root dir will result in an empty path: fix it
1778 	if (path[insert] == '\0')
1779 		path[--insert] = '/';
1780 
1781 	PRINT(("  path is: %s\n", path + insert));
1782 
1783 	// copy the path to the output buffer
1784 	length = sizeof(path) - insert;
1785 	if (length <= (int)bufferSize)
1786 		memcpy(buffer, path + insert, length);
1787 	else
1788 		status = ENOBUFS;
1789 
1790 out:
1791 	put_vnode(vnode);
1792 	return status;
1793 }
1794 
1795 
1796 /**	Checks the length of every path component, and adds a '.'
1797  *	if the path ends in a slash.
1798  *	The given path buffer must be able to store at least one
1799  *	additional character.
1800  */
1801 
1802 static status_t
1803 check_path(char *to)
1804 {
1805 	int32 length = 0;
1806 
1807 	// check length of every path component
1808 
1809 	while (*to) {
1810 		char *begin;
1811 		if (*to == '/')
1812 			to++, length++;
1813 
1814 		begin = to;
1815 		while (*to != '/' && *to)
1816 			to++, length++;
1817 
1818 		if (to - begin > B_FILE_NAME_LENGTH)
1819 			return B_NAME_TOO_LONG;
1820 	}
1821 
1822 	if (length == 0)
1823 		return B_ENTRY_NOT_FOUND;
1824 
1825 	// complete path if there is a slash at the end
1826 
1827 	if (*(to - 1) == '/') {
1828 		if (length > B_PATH_NAME_LENGTH - 2)
1829 			return B_NAME_TOO_LONG;
1830 
1831 		to[0] = '.';
1832 		to[1] = '\0';
1833 	}
1834 
1835 	return B_OK;
1836 }
1837 
1838 
1839 static struct file_descriptor *
1840 get_fd_and_vnode(int fd, struct vnode **_vnode, bool kernel)
1841 {
1842 	struct file_descriptor *descriptor = get_fd(get_current_io_context(kernel), fd);
1843 	if (descriptor == NULL)
1844 		return NULL;
1845 
1846 	if (descriptor->u.vnode == NULL) {
1847 		put_fd(descriptor);
1848 		return NULL;
1849 	}
1850 
1851 	// ToDo: when we can close a file descriptor at any point, investigate
1852 	//	if this is still valid to do (accessing the vnode without ref_count
1853 	//	or locking)
1854 	*_vnode = descriptor->u.vnode;
1855 	return descriptor;
1856 }
1857 
1858 
1859 static struct vnode *
1860 get_vnode_from_fd(int fd, bool kernel)
1861 {
1862 	struct file_descriptor *descriptor;
1863 	struct vnode *vnode;
1864 
1865 	descriptor = get_fd(get_current_io_context(kernel), fd);
1866 	if (descriptor == NULL)
1867 		return NULL;
1868 
1869 	vnode = descriptor->u.vnode;
1870 	if (vnode != NULL)
1871 		inc_vnode_ref_count(vnode);
1872 
1873 	put_fd(descriptor);
1874 	return vnode;
1875 }
1876 
1877 
1878 /**	Gets the vnode from an FD + path combination. If \a fd is lower than zero,
1879  *	only the path will be considered. In this case, the \a path must not be
1880  *	NULL.
1881  *	If \a fd is a valid file descriptor, \a path may be NULL for directories,
1882  *	and should be NULL for files.
1883  */
1884 
1885 static status_t
1886 fd_and_path_to_vnode(int fd, char *path, bool traverseLeafLink, struct vnode **_vnode, bool kernel)
1887 {
1888 	if (fd < 0 && !path)
1889 		return B_BAD_VALUE;
1890 
1891 	status_t status;
1892 	struct vnode *vnode = NULL;
1893 	if (fd < 0 || (path != NULL && path[0] == '/')) {
1894 		// no FD or absolute path
1895 		status = path_to_vnode(path, traverseLeafLink, &vnode, kernel);
1896 	} else {
1897 		// FD only, or FD + relative path
1898 		vnode = get_vnode_from_fd(fd, kernel);
1899 		if (!vnode)
1900 			return B_FILE_ERROR;
1901 
1902 		if (path != NULL) {
1903 			status = vnode_path_to_vnode(vnode, path, traverseLeafLink, 0,
1904 				&vnode, NULL);
1905 		} else
1906 			status = B_OK;
1907 	}
1908 
1909 	if (status == B_OK)
1910 		*_vnode = vnode;
1911 	return status;
1912 }
1913 
1914 
1915 static int
1916 get_new_fd(int type, struct fs_mount *mount, struct vnode *vnode,
1917 	fs_cookie cookie, int openMode, bool kernel)
1918 {
1919 	struct file_descriptor *descriptor;
1920 	int fd;
1921 
1922 	descriptor = alloc_fd();
1923 	if (!descriptor)
1924 		return B_NO_MEMORY;
1925 
1926 	if (vnode)
1927 		descriptor->u.vnode = vnode;
1928 	else
1929 		descriptor->u.mount = mount;
1930 	descriptor->cookie = cookie;
1931 
1932 	switch (type) {
1933 		case FDTYPE_FILE:
1934 			descriptor->ops = &sFileOps;
1935 			break;
1936 		case FDTYPE_DIR:
1937 			descriptor->ops = &sDirectoryOps;
1938 			break;
1939 		case FDTYPE_ATTR:
1940 			descriptor->ops = &sAttributeOps;
1941 			break;
1942 		case FDTYPE_ATTR_DIR:
1943 			descriptor->ops = &sAttributeDirectoryOps;
1944 			break;
1945 		case FDTYPE_INDEX_DIR:
1946 			descriptor->ops = &sIndexDirectoryOps;
1947 			break;
1948 		case FDTYPE_QUERY:
1949 			descriptor->ops = &sQueryOps;
1950 			break;
1951 		default:
1952 			panic("get_new_fd() called with unknown type %d\n", type);
1953 			break;
1954 	}
1955 	descriptor->type = type;
1956 	descriptor->open_mode = openMode;
1957 
1958 	fd = new_fd(get_current_io_context(kernel), descriptor);
1959 	if (fd < 0) {
1960 		free(descriptor);
1961 		return B_NO_MORE_FDS;
1962 	}
1963 
1964 	return fd;
1965 }
1966 
1967 
1968 //	#pragma mark -
1969 //	Public VFS API
1970 
1971 
1972 extern "C" status_t
1973 new_vnode(mount_id mountID, vnode_id vnodeID, fs_vnode privateNode)
1974 {
1975 	FUNCTION(("new_vnode()\n"));
1976 
1977 	if (privateNode == NULL)
1978 		return B_BAD_VALUE;
1979 
1980 	mutex_lock(&sVnodeMutex);
1981 
1982 	// file system integrity check:
1983 	// test if the vnode already exists and bail out if this is the case!
1984 
1985 	// ToDo: the R5 implementation obviously checks for a different cookie
1986 	//	and doesn't panic if they are equal
1987 
1988 	struct vnode *vnode = lookup_vnode(mountID, vnodeID);
1989 	if (vnode != NULL)
1990 		panic("vnode %ld:%Ld already exists (node = %p, vnode->node = %p)!", mountID, vnodeID, privateNode, vnode->private_node);
1991 
1992 	status_t status = create_new_vnode(&vnode, mountID, vnodeID);
1993 	if (status == B_OK) {
1994 		vnode->private_node = privateNode;
1995 		vnode->busy = true;
1996 		vnode->unpublished = true;
1997 	}
1998 
1999 	PRINT(("returns: %s\n", strerror(status)));
2000 
2001 	mutex_unlock(&sVnodeMutex);
2002 	return status;
2003 }
2004 
2005 
2006 extern "C" status_t
2007 publish_vnode(mount_id mountID, vnode_id vnodeID, fs_vnode privateNode)
2008 {
2009 	FUNCTION(("publish_vnode()\n"));
2010 
2011 	mutex_lock(&sVnodeMutex);
2012 
2013 	struct vnode *vnode = lookup_vnode(mountID, vnodeID);
2014 	status_t status = B_OK;
2015 
2016 	if (vnode != NULL && vnode->busy && vnode->unpublished
2017 		&& vnode->private_node == privateNode) {
2018 		vnode->busy = false;
2019 		vnode->unpublished = false;
2020 	} else if (vnode == NULL && privateNode != NULL) {
2021 		status = create_new_vnode(&vnode, mountID, vnodeID);
2022 		if (status == B_OK)
2023 			vnode->private_node = privateNode;
2024 	} else
2025 		status = B_BAD_VALUE;
2026 
2027 	PRINT(("returns: %s\n", strerror(status)));
2028 
2029 	mutex_unlock(&sVnodeMutex);
2030 	return status;
2031 }
2032 
2033 
2034 extern "C" status_t
2035 get_vnode(mount_id mountID, vnode_id vnodeID, fs_vnode *_fsNode)
2036 {
2037 	struct vnode *vnode;
2038 
2039 	status_t status = get_vnode(mountID, vnodeID, &vnode, true);
2040 	if (status < B_OK)
2041 		return status;
2042 
2043 	*_fsNode = vnode->private_node;
2044 	return B_OK;
2045 }
2046 
2047 
2048 extern "C" status_t
2049 put_vnode(mount_id mountID, vnode_id vnodeID)
2050 {
2051 	struct vnode *vnode;
2052 
2053 	mutex_lock(&sVnodeMutex);
2054 	vnode = lookup_vnode(mountID, vnodeID);
2055 	mutex_unlock(&sVnodeMutex);
2056 
2057 	if (vnode)
2058 		dec_vnode_ref_count(vnode, true);
2059 
2060 	return B_OK;
2061 }
2062 
2063 
2064 extern "C" status_t
2065 remove_vnode(mount_id mountID, vnode_id vnodeID)
2066 {
2067 	struct vnode *vnode;
2068 
2069 	mutex_lock(&sVnodeMutex);
2070 
2071 	vnode = lookup_vnode(mountID, vnodeID);
2072 	if (vnode != NULL) {
2073 		vnode->remove = true;
2074 		if (vnode->unpublished) {
2075 			// if the vnode hasn't been published yet, we delete it here
2076 			atomic_add(&vnode->ref_count, -1);
2077 			free_vnode(vnode, true);
2078 		}
2079 	}
2080 
2081 	mutex_unlock(&sVnodeMutex);
2082 	return B_OK;
2083 }
2084 
2085 
2086 extern "C" status_t
2087 unremove_vnode(mount_id mountID, vnode_id vnodeID)
2088 {
2089 	struct vnode *vnode;
2090 
2091 	mutex_lock(&sVnodeMutex);
2092 
2093 	vnode = lookup_vnode(mountID, vnodeID);
2094 	if (vnode)
2095 		vnode->remove = false;
2096 
2097 	mutex_unlock(&sVnodeMutex);
2098 	return B_OK;
2099 }
2100 
2101 
2102 //	#pragma mark -
2103 //	Functions the VFS exports for other parts of the kernel
2104 
2105 
2106 void
2107 vfs_vnode_acquire_ref(void *vnode)
2108 {
2109 	FUNCTION(("vfs_vnode_acquire_ref: vnode 0x%p\n", vnode));
2110 	inc_vnode_ref_count((struct vnode *)vnode);
2111 }
2112 
2113 
2114 void
2115 vfs_vnode_release_ref(void *vnode)
2116 {
2117 	FUNCTION(("vfs_vnode_release_ref: vnode 0x%p\n", vnode));
2118 	dec_vnode_ref_count((struct vnode *)vnode, false);
2119 }
2120 
2121 
2122 /** This is currently called from file_cache_create() only.
2123  *	It's probably a temporary solution as long as devfs requires that
2124  *	fs_read_pages()/fs_write_pages() are called with the standard
2125  *	open cookie and not with a device cookie.
2126  *	If that's done differently, remove this call; it has no other
2127  *	purpose.
2128  */
2129 
2130 extern "C" status_t
2131 vfs_get_cookie_from_fd(int fd, void **_cookie)
2132 {
2133 	struct file_descriptor *descriptor;
2134 
2135 	descriptor = get_fd(get_current_io_context(true), fd);
2136 	if (descriptor == NULL)
2137 		return B_FILE_ERROR;
2138 
2139 	*_cookie = descriptor->cookie;
2140 	return B_OK;
2141 }
2142 
2143 
2144 extern "C" int
2145 vfs_get_vnode_from_fd(int fd, bool kernel, void **vnode)
2146 {
2147 	*vnode = get_vnode_from_fd(fd, kernel);
2148 
2149 	if (*vnode == NULL)
2150 		return B_FILE_ERROR;
2151 
2152 	return B_NO_ERROR;
2153 }
2154 
2155 
2156 extern "C" status_t
2157 vfs_get_vnode_from_path(const char *path, bool kernel, void **_vnode)
2158 {
2159 	struct vnode *vnode;
2160 	status_t status;
2161 	char buffer[B_PATH_NAME_LENGTH + 1];
2162 
2163 	PRINT(("vfs_get_vnode_from_path: entry. path = '%s', kernel %d\n", path, kernel));
2164 
2165 	strlcpy(buffer, path, sizeof(buffer));
2166 
2167 	status = path_to_vnode(buffer, true, &vnode, kernel);
2168 	if (status < B_OK)
2169 		return status;
2170 
2171 	*_vnode = vnode;
2172 	return B_OK;
2173 }
2174 
2175 
2176 extern "C" status_t
2177 vfs_get_vnode(mount_id mountID, vnode_id vnodeID, void **_vnode)
2178 {
2179 	struct vnode *vnode;
2180 
2181 	status_t status = get_vnode(mountID, vnodeID, &vnode, false);
2182 	if (status < B_OK)
2183 		return status;
2184 
2185 	*_vnode = vnode;
2186 	return B_OK;
2187 }
2188 
2189 
2190 extern "C" status_t
2191 vfs_lookup_vnode(mount_id mountID, vnode_id vnodeID, void **_vnode)
2192 {
2193 	// ToDo: this currently doesn't use the sVnodeMutex lock - that's
2194 	//	because it's only called from file_cache_create() with that
2195 	//	lock held anyway (as it should be called from fs_read_vnode()).
2196 	//	Find a better solution!
2197 	struct vnode *vnode = lookup_vnode(mountID, vnodeID);
2198 	if (vnode == NULL)
2199 		return B_ERROR;
2200 
2201 	*_vnode = vnode;
2202 	return B_OK;
2203 	//return get_vnode(mountID, vnodeID, (struct vnode **)_vnode, true);
2204 }
2205 
2206 
2207 extern "C" status_t
2208 vfs_get_fs_node_from_path(mount_id mountID, const char *path, bool kernel, void **_node)
2209 {
2210 	char buffer[B_PATH_NAME_LENGTH + 1];
2211 	struct vnode *vnode;
2212 	status_t status;
2213 
2214 	PRINT(("vfs_get_fs_node_from_path(mountID = %ld, path = \"%s\", kernel %d)\n", mountID, path, kernel));
2215 
2216 	strlcpy(buffer, path, sizeof(buffer));
2217 	status = path_to_vnode(buffer, true, &vnode, kernel);
2218 	if (status < B_OK)
2219 		return status;
2220 
2221 	if (vnode->device != mountID) {
2222 		// wrong mount ID - must not gain access on foreign file system nodes
2223 		put_vnode(vnode);
2224 		return B_BAD_VALUE;
2225 	}
2226 
2227 	*_node = vnode->private_node;
2228 	return B_OK;
2229 }
2230 
2231 
2232 /**	Finds the full path to the file that contains the module \a moduleName,
2233  *	puts it into \a pathBuffer, and returns B_OK for success.
2234  *	If \a pathBuffer was too small, it returns \c B_BUFFER_OVERFLOW,
2235  *	\c B_ENTRY_NOT_FOUNT if no file could be found.
2236  *	\a pathBuffer is clobbered in any case and must not be relied on if this
2237  *	functions returns unsuccessfully.
2238  */
2239 
2240 status_t
2241 vfs_get_module_path(const char *basePath, const char *moduleName, char *pathBuffer,
2242 	size_t bufferSize)
2243 {
2244 	struct vnode *dir, *file;
2245 	status_t status;
2246 	size_t length;
2247 	char *path;
2248 
2249 	if (bufferSize == 0 || strlcpy(pathBuffer, basePath, bufferSize) >= bufferSize)
2250 		return B_BUFFER_OVERFLOW;
2251 
2252 	status = path_to_vnode(pathBuffer, true, &dir, true);
2253 	if (status < B_OK)
2254 		return status;
2255 
2256 	// the path buffer had been clobbered by the above call
2257 	length = strlcpy(pathBuffer, basePath, bufferSize);
2258 	if (pathBuffer[length - 1] != '/')
2259 		pathBuffer[length++] = '/';
2260 
2261 	path = pathBuffer + length;
2262 	bufferSize -= length;
2263 
2264 	while (moduleName) {
2265 		int type;
2266 
2267 		char *nextPath = strchr(moduleName, '/');
2268 		if (nextPath == NULL)
2269 			length = strlen(moduleName);
2270 		else {
2271 			length = nextPath - moduleName;
2272 			nextPath++;
2273 		}
2274 
2275 		if (length + 1 >= bufferSize) {
2276 			status = B_BUFFER_OVERFLOW;
2277 			goto err;
2278 		}
2279 
2280 		memcpy(path, moduleName, length);
2281 		path[length] = '\0';
2282 		moduleName = nextPath;
2283 
2284 		status = vnode_path_to_vnode(dir, path, true, 0, &file, &type);
2285 		if (status < B_OK)
2286 			goto err;
2287 
2288 		put_vnode(dir);
2289 
2290 		if (S_ISDIR(type)) {
2291 			// goto the next directory
2292 			path[length] = '/';
2293 			path[length + 1] = '\0';
2294 			path += length + 1;
2295 			bufferSize -= length + 1;
2296 
2297 			dir = file;
2298 		} else if (S_ISREG(type)) {
2299 			// it's a file so it should be what we've searched for
2300 			put_vnode(file);
2301 
2302 			return B_OK;
2303 		} else {
2304 			PRINT(("vfs_get_module_path(): something is strange here: %d...\n", type));
2305 			status = B_ERROR;
2306 			goto err;
2307 		}
2308 	}
2309 
2310 	// if we got here, the moduleName just pointed to a directory, not to
2311 	// a real module - what should we do in this case?
2312 	status = B_ENTRY_NOT_FOUND;
2313 
2314 err:
2315 	put_vnode(dir);
2316 	return status;
2317 }
2318 
2319 
2320 /**	\brief Normalizes a given path.
2321  *
2322  *	The path must refer to an existing or non-existing entry in an existing
2323  *	directory, that is chopping off the leaf component the remaining path must
2324  *	refer to an existing directory.
2325  *
2326  *	The returned will be canonical in that it will be absolute, will not
2327  *	contain any "." or ".." components or duplicate occurrences of '/'s,
2328  *	and none of the directory components will by symbolic links.
2329  *
2330  *	Any two paths referring to the same entry, will result in the same
2331  *	normalized path (well, that is pretty much the definition of `normalized',
2332  *	isn't it :-).
2333  *
2334  *	\param path The path to be normalized.
2335  *	\param buffer The buffer into which the normalized path will be written.
2336  *	\param bufferSize The size of \a buffer.
2337  *	\param kernel \c true, if the IO context of the kernel shall be used,
2338  *		   otherwise that of the team this thread belongs to. Only relevant,
2339  *		   if the path is relative (to get the CWD).
2340  *	\return \c B_OK if everything went fine, another error code otherwise.
2341  */
2342 
2343 status_t
2344 vfs_normalize_path(const char *path, char *buffer, size_t bufferSize,
2345 	bool kernel)
2346 {
2347 	if (!path || !buffer || bufferSize < 1)
2348 		return B_BAD_VALUE;
2349 
2350 	PRINT(("vfs_normalize_path(`%s')\n", path));
2351 
2352 	// copy the supplied path to the stack, so it can be modified
2353 	char mutablePath[B_PATH_NAME_LENGTH + 1];
2354 	if (strlcpy(mutablePath, path, B_PATH_NAME_LENGTH) >= B_PATH_NAME_LENGTH)
2355 		return B_NAME_TOO_LONG;
2356 
2357 	// get the dir vnode and the leaf name
2358 	struct vnode *dirNode;
2359 	char leaf[B_FILE_NAME_LENGTH];
2360 	status_t error = path_to_dir_vnode(mutablePath, &dirNode, leaf, kernel);
2361 	if (error != B_OK) {
2362 		PRINT(("vfs_normalize_path(): failed to get dir vnode: %s\n", strerror(error)));
2363 		return error;
2364 	}
2365 
2366 	// if the leaf is "." or "..", we directly get the correct directory
2367 	// vnode and ignore the leaf later
2368 	bool isDir = (strcmp(leaf, ".") == 0 || strcmp(leaf, "..") == 0);
2369 	if (isDir)
2370 		error = vnode_path_to_vnode(dirNode, leaf, false, 0, &dirNode, NULL);
2371 	if (error != B_OK) {
2372 		PRINT(("vfs_normalize_path(): failed to get dir vnode for \".\" or \"..\": %s\n", strerror(error)));
2373 		return error;
2374 	}
2375 
2376 	// get the directory path
2377 	error = dir_vnode_to_path(dirNode, buffer, bufferSize);
2378 	put_vnode(dirNode);
2379 	if (error < B_OK) {
2380 		PRINT(("vfs_normalize_path(): failed to get dir path: %s\n", strerror(error)));
2381 		return error;
2382 	}
2383 
2384 	// append the leaf name
2385 	if (!isDir) {
2386 		// insert a directory separator only if this is not the file system root
2387 		if ((strcmp(buffer, "/") != 0
2388 			 && strlcat(buffer, "/", bufferSize) >= bufferSize)
2389 			|| strlcat(buffer, leaf, bufferSize) >= bufferSize) {
2390 			return B_NAME_TOO_LONG;
2391 		}
2392 	}
2393 
2394 	PRINT(("vfs_normalize_path() -> `%s'\n", buffer));
2395 	return B_OK;
2396 }
2397 
2398 
2399 int
2400 vfs_put_vnode_ptr(void *_vnode)
2401 {
2402 	struct vnode *vnode = (struct vnode *)_vnode;
2403 
2404 	put_vnode(vnode);
2405 	return 0;
2406 }
2407 
2408 
2409 extern "C" bool
2410 vfs_can_page(void *_vnode, void *cookie)
2411 {
2412 	struct vnode *vnode = (struct vnode *)_vnode;
2413 
2414 	FUNCTION(("vfs_canpage: vnode 0x%p\n", vnode));
2415 
2416 	if (FS_CALL(vnode, can_page))
2417 		return FS_CALL(vnode, can_page)(vnode->mount->cookie, vnode->private_node, cookie);
2418 
2419 	return false;
2420 }
2421 
2422 
2423 extern "C" status_t
2424 vfs_read_pages(void *_vnode, void *cookie, off_t pos, const iovec *vecs, size_t count, size_t *_numBytes)
2425 {
2426 	struct vnode *vnode = (struct vnode *)_vnode;
2427 
2428 	FUNCTION(("vfs_read_pages: vnode %p, vecs %p, pos %Ld\n", vnode, vecs, pos));
2429 
2430 	return FS_CALL(vnode, read_pages)(vnode->mount->cookie, vnode->private_node, cookie, pos, vecs, count, _numBytes);
2431 }
2432 
2433 
2434 extern "C" status_t
2435 vfs_write_pages(void *_vnode, void *cookie, off_t pos, const iovec *vecs, size_t count, size_t *_numBytes)
2436 {
2437 	struct vnode *vnode = (struct vnode *)_vnode;
2438 
2439 	FUNCTION(("vfs_write_pages: vnode %p, vecs %p, pos %Ld\n", vnode, vecs, pos));
2440 
2441 	return FS_CALL(vnode, write_pages)(vnode->mount->cookie, vnode->private_node, cookie, pos, vecs, count, _numBytes);
2442 }
2443 
2444 
2445 extern "C" status_t
2446 vfs_get_vnode_cache(void *_vnode, vm_cache_ref **_cache)
2447 {
2448 	struct vnode *vnode = (struct vnode *)_vnode;
2449 
2450 	if (vnode->cache != NULL) {
2451 		*_cache = vnode->cache;
2452 		return B_OK;
2453 	}
2454 
2455 	mutex_lock(&sVnodeMutex);
2456 
2457 	status_t status = B_OK;
2458 	// The cache could have been created in the meantime
2459 	if (vnode->cache == NULL)
2460 		status = vm_create_vnode_cache(vnode, &vnode->cache);
2461 
2462 	if (status == B_OK)
2463 		*_cache = vnode->cache;
2464 
2465 	mutex_unlock(&sVnodeMutex);
2466 	return status;
2467 }
2468 
2469 
2470 status_t
2471 vfs_get_file_map(void *_vnode, off_t offset, size_t size, file_io_vec *vecs, size_t *_count)
2472 {
2473 	struct vnode *vnode = (struct vnode *)_vnode;
2474 
2475 	FUNCTION(("vfs_get_file_map: vnode %p, vecs %p, offset %Ld, size = %lu\n", vnode, vecs, offset, size));
2476 
2477 	return FS_CALL(vnode, get_file_map)(vnode->mount->cookie, vnode->private_node, offset, size, vecs, _count);
2478 }
2479 
2480 
2481 status_t
2482 vfs_stat_vnode(void *_vnode, struct stat *stat)
2483 {
2484 	struct vnode *vnode = (struct vnode *)_vnode;
2485 
2486 	status_t status = FS_CALL(vnode, read_stat)(vnode->mount->cookie,
2487 		vnode->private_node, stat);
2488 
2489 	// fill in the st_dev and st_ino fields
2490 	if (status == B_OK) {
2491 		stat->st_dev = vnode->device;
2492 		stat->st_ino = vnode->id;
2493 	}
2494 
2495 	return status;
2496 }
2497 
2498 
2499 status_t
2500 vfs_get_vnode_name(void *_vnode, char *name, size_t nameSize)
2501 {
2502 	return get_vnode_name((struct vnode *)_vnode, NULL, name, nameSize);
2503 }
2504 
2505 
2506 /**	Closes all file descriptors of the specified I/O context that
2507  *	don't have the O_CLOEXEC flag set.
2508  */
2509 
2510 void
2511 vfs_exec_io_context(void *_context)
2512 {
2513 	struct io_context *context = (struct io_context *)_context;
2514 	uint32 i;
2515 
2516 
2517 	for (i = 0; i < context->table_size; i++) {
2518 		mutex_lock(&context->io_mutex);
2519 
2520 		struct file_descriptor *descriptor = context->fds[i];
2521 		bool remove = false;
2522 
2523 		if (descriptor != NULL && (descriptor->open_mode & O_CLOEXEC) != 0) {
2524 			context->fds[i] = NULL;
2525 			context->num_used_fds--;
2526 
2527 			remove = true;
2528 		}
2529 
2530 		mutex_unlock(&context->io_mutex);
2531 
2532 		if (remove) {
2533 			close_fd(descriptor);
2534 			put_fd(descriptor);
2535 		}
2536 	}
2537 }
2538 
2539 
2540 /** Sets up a new io_control structure, and inherits the properties
2541  *	of the parent io_control if it is given.
2542  */
2543 
2544 void *
2545 vfs_new_io_context(void *_parentContext)
2546 {
2547 	size_t tableSize;
2548 	struct io_context *context;
2549 	struct io_context *parentContext;
2550 
2551 	context = (io_context *)malloc(sizeof(struct io_context));
2552 	if (context == NULL)
2553 		return NULL;
2554 
2555 	memset(context, 0, sizeof(struct io_context));
2556 
2557 	parentContext = (struct io_context *)_parentContext;
2558 	if (parentContext)
2559 		tableSize = parentContext->table_size;
2560 	else
2561 		tableSize = DEFAULT_FD_TABLE_SIZE;
2562 
2563 	context->fds = (file_descriptor **)malloc(sizeof(struct file_descriptor *) * tableSize);
2564 	if (context->fds == NULL) {
2565 		free(context);
2566 		return NULL;
2567 	}
2568 
2569 	memset(context->fds, 0, sizeof(struct file_descriptor *) * tableSize);
2570 
2571 	if (mutex_init(&context->io_mutex, "I/O context") < 0) {
2572 		free(context->fds);
2573 		free(context);
2574 		return NULL;
2575 	}
2576 
2577 	// Copy all parent files which don't have the O_CLOEXEC flag set
2578 
2579 	if (parentContext) {
2580 		size_t i;
2581 
2582 		mutex_lock(&parentContext->io_mutex);
2583 
2584 		context->cwd = parentContext->cwd;
2585 		if (context->cwd)
2586 			inc_vnode_ref_count(context->cwd);
2587 
2588 		for (i = 0; i < tableSize; i++) {
2589 			struct file_descriptor *descriptor = parentContext->fds[i];
2590 
2591 			if (descriptor != NULL && (descriptor->open_mode & O_CLOEXEC) == 0) {
2592 				context->fds[i] = descriptor;
2593 				atomic_add(&descriptor->ref_count, 1);
2594 				atomic_add(&descriptor->open_count, 1);
2595 			}
2596 		}
2597 
2598 		mutex_unlock(&parentContext->io_mutex);
2599 	} else {
2600 		context->cwd = sRoot;
2601 
2602 		if (context->cwd)
2603 			inc_vnode_ref_count(context->cwd);
2604 	}
2605 
2606 	context->table_size = tableSize;
2607 
2608 	list_init(&context->node_monitors);
2609 	context->max_monitors = MAX_NODE_MONITORS;
2610 
2611 	return context;
2612 }
2613 
2614 
2615 status_t
2616 vfs_free_io_context(void *_ioContext)
2617 {
2618 	struct io_context *context = (struct io_context *)_ioContext;
2619 	uint32 i;
2620 
2621 	if (context->cwd)
2622 		dec_vnode_ref_count(context->cwd, false);
2623 
2624 	mutex_lock(&context->io_mutex);
2625 
2626 	for (i = 0; i < context->table_size; i++) {
2627 		if (struct file_descriptor *descriptor = context->fds[i]) {
2628 			close_fd(descriptor);
2629 			put_fd(descriptor);
2630 		}
2631 	}
2632 
2633 	mutex_unlock(&context->io_mutex);
2634 
2635 	mutex_destroy(&context->io_mutex);
2636 
2637 	remove_node_monitors(context);
2638 	free(context->fds);
2639 	free(context);
2640 
2641 	return B_OK;
2642 }
2643 
2644 
2645 static status_t
2646 vfs_resize_fd_table(struct io_context *context, const int newSize)
2647 {
2648 	void *fds;
2649 	int	status = B_OK;
2650 
2651 	if (newSize <= 0 || newSize > MAX_FD_TABLE_SIZE)
2652 		return EINVAL;
2653 
2654 	mutex_lock(&context->io_mutex);
2655 
2656 	if ((size_t)newSize < context->table_size) {
2657 		// shrink the fd table
2658 		int i;
2659 
2660 		// Make sure none of the fds being dropped are in use
2661 		for(i = context->table_size; i-- > newSize;) {
2662 			if (context->fds[i]) {
2663 				status = EBUSY;
2664 				goto out;
2665 			}
2666 		}
2667 
2668 		fds = malloc(sizeof(struct file_descriptor *) * newSize);
2669 		if (fds == NULL) {
2670 			status = ENOMEM;
2671 			goto out;
2672 		}
2673 
2674 		memcpy(fds, context->fds, sizeof(struct file_descriptor *) * newSize);
2675 	} else {
2676 		// enlarge the fd table
2677 
2678 		fds = malloc(sizeof(struct file_descriptor *) * newSize);
2679 		if (fds == NULL) {
2680 			status = ENOMEM;
2681 			goto out;
2682 		}
2683 
2684 		// copy the fd array, and zero the additional slots
2685 		memcpy(fds, context->fds, sizeof(void *) * context->table_size);
2686 		memset((char *)fds + (sizeof(void *) * context->table_size), 0,
2687 			sizeof(void *) * (newSize - context->table_size));
2688 	}
2689 
2690 	free(context->fds);
2691 	context->fds = (file_descriptor **)fds;
2692 	context->table_size = newSize;
2693 
2694 out:
2695 	mutex_unlock(&context->io_mutex);
2696 	return status;
2697 }
2698 
2699 
2700 int
2701 vfs_getrlimit(int resource, struct rlimit * rlp)
2702 {
2703 	if (!rlp)
2704 		return -1;
2705 
2706 	switch (resource) {
2707 		case RLIMIT_NOFILE:
2708 		{
2709 			struct io_context *ioctx = get_current_io_context(false);
2710 
2711 			mutex_lock(&ioctx->io_mutex);
2712 
2713 			rlp->rlim_cur = ioctx->table_size;
2714 			rlp->rlim_max = MAX_FD_TABLE_SIZE;
2715 
2716 			mutex_unlock(&ioctx->io_mutex);
2717 
2718 			return 0;
2719 		}
2720 
2721 		default:
2722 			return -1;
2723 	}
2724 }
2725 
2726 
2727 int
2728 vfs_setrlimit(int resource, const struct rlimit * rlp)
2729 {
2730 	if (!rlp)
2731 		return -1;
2732 
2733 	switch (resource) {
2734 		case RLIMIT_NOFILE:
2735 			return vfs_resize_fd_table(get_current_io_context(false), rlp->rlim_cur);
2736 
2737 		default:
2738 			return -1;
2739 	}
2740 }
2741 
2742 
2743 status_t
2744 vfs_bootstrap_file_systems(void)
2745 {
2746 	status_t status;
2747 
2748 	// bootstrap the root filesystem
2749 	status = _kern_mount("/", NULL, "rootfs", 0, NULL);
2750 	if (status < B_OK)
2751 		panic("error mounting rootfs!\n");
2752 
2753 	_kern_setcwd(-1, "/");
2754 
2755 	// bootstrap the devfs
2756 	_kern_create_dir(-1, "/dev", 0755);
2757 	status = _kern_mount("/dev", NULL, "devfs", 0, NULL);
2758 	if (status < B_OK)
2759 		panic("error mounting devfs\n");
2760 
2761 	// bootstrap the pipefs
2762 	_kern_create_dir(-1, "/pipe", 0755);
2763 	status = _kern_mount("/pipe", NULL, "pipefs", 0, NULL);
2764 	if (status < B_OK)
2765 		panic("error mounting pipefs\n");
2766 
2767 	// bootstrap the bootfs (if possible)
2768 	_kern_create_dir(-1, "/boot", 0755);
2769 	status = _kern_mount("/boot", NULL, "bootfs", 0, NULL);
2770 	if (status < B_OK) {
2771 		// this is no fatal exception at this point, as we may mount
2772 		// a real on disk file system later
2773 		dprintf("error mounting bootfs\n");
2774 	}
2775 
2776 	// create some standard links on the rootfs
2777 
2778 	for (int32 i = 0; sPredefinedLinks[i].path != NULL; i++) {
2779 		_kern_create_symlink(-1, sPredefinedLinks[i].path,
2780 			sPredefinedLinks[i].target, 0);
2781 			// we don't care if it will succeed or not
2782 	}
2783 
2784 	return B_OK;
2785 }
2786 
2787 
2788 status_t
2789 vfs_mount_boot_file_system(kernel_args *args)
2790 {
2791 	// make the boot partition (and probably others) available
2792 	KDiskDeviceManager::CreateDefault();
2793 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
2794 
2795 	status_t status = manager->InitialDeviceScan();
2796 	if (status == B_OK) {
2797 		// ToDo: do this for real... (no hacks allowed :))
2798 		for (;;) {
2799 			snooze(500000);
2800 			if (manager->CountJobs() == 0)
2801 				break;
2802 		}
2803 	} else
2804 		dprintf("KDiskDeviceManager::InitialDeviceScan() failed: %s\n", strerror(status));
2805 
2806 	file_system_module_info *bootfs;
2807 	if ((bootfs = get_file_system("bootfs")) == NULL) {
2808 		// no bootfs there, yet
2809 
2810 		// ToDo: do this for real! It will currently only use the partition offset;
2811 		//	it does not yet use the disk_identifier information.
2812 
2813 		KPartition *bootPartition = NULL;
2814 
2815 		struct BootPartitionVisitor : KPartitionVisitor {
2816 			BootPartitionVisitor(off_t offset) : fOffset(offset) {}
2817 
2818 			virtual bool VisitPre(KPartition *partition)
2819 			{
2820 				return (partition->ContainsFileSystem()
2821 						&& partition->Offset() == fOffset);
2822 			}
2823 			private:
2824 				off_t	fOffset;
2825 		} visitor(args->boot_disk.partition_offset);
2826 
2827 		KDiskDevice *device;
2828 		int32 cookie = 0;
2829 		while ((device = manager->NextDevice(&cookie)) != NULL) {
2830 			bootPartition = device->VisitEachDescendant(&visitor);
2831 			if (bootPartition)
2832 				break;
2833 		}
2834 
2835 		KPath path;
2836 		if (bootPartition == NULL
2837 			|| bootPartition->GetPath(&path) != B_OK
2838 			|| _kern_mount("/boot", path.Path(), "bfs", 0, NULL) < B_OK)
2839 			panic("could not get boot device!\n");
2840 	} else
2841 		put_file_system(bootfs);
2842 
2843 	gBootDevice = sNextMountID - 1;
2844 
2845 	// create link for the name of the boot device
2846 
2847 	fs_info info;
2848 	if (_kern_read_fs_info(gBootDevice, &info) == B_OK) {
2849 		char path[B_FILE_NAME_LENGTH + 1];
2850 		snprintf(path, sizeof(path), "/%s", info.volume_name);
2851 
2852 		_kern_create_symlink(-1, path, "/boot", 0);
2853 	}
2854 
2855 	return B_OK;
2856 }
2857 
2858 
2859 status_t
2860 vfs_init(kernel_args *args)
2861 {
2862 	sVnodeTable = hash_init(VNODE_HASH_TABLE_SIZE, offsetof(struct vnode, next),
2863 		&vnode_compare, &vnode_hash);
2864 	if (sVnodeTable == NULL)
2865 		panic("vfs_init: error creating vnode hash table\n");
2866 
2867 	list_init_etc(&sUnusedVnodeList, offsetof(struct vnode, unused_link));
2868 
2869 	sMountsTable = hash_init(MOUNTS_HASH_TABLE_SIZE, offsetof(struct fs_mount, next),
2870 		&mount_compare, &mount_hash);
2871 	if (sMountsTable == NULL)
2872 		panic("vfs_init: error creating mounts hash table\n");
2873 
2874 	node_monitor_init();
2875 
2876 	sRoot = NULL;
2877 
2878 	if (mutex_init(&sFileSystemsMutex, "vfs_lock") < 0)
2879 		panic("vfs_init: error allocating file systems lock\n");
2880 
2881 	if (recursive_lock_init(&sMountOpLock, "vfs_mount_op_lock") < 0)
2882 		panic("vfs_init: error allocating mount op lock\n");
2883 
2884 	if (mutex_init(&sMountMutex, "vfs_mount_lock") < 0)
2885 		panic("vfs_init: error allocating mount lock\n");
2886 
2887 	if (mutex_init(&sVnodeMutex, "vfs_vnode_lock") < 0)
2888 		panic("vfs_init: error allocating vnode lock\n");
2889 
2890 	if (block_cache_init() != B_OK)
2891 		return B_ERROR;
2892 
2893 	return file_cache_init();
2894 }
2895 
2896 
2897 //	#pragma mark -
2898 //	The filetype-dependent implementations (fd_ops + open/create/rename/remove, ...)
2899 
2900 
2901 /** Calls fs_open() on the given vnode and returns a new
2902  *	file descriptor for it
2903  */
2904 
2905 static int
2906 create_vnode(struct vnode *directory, const char *name, int openMode, int perms, bool kernel)
2907 {
2908 	struct vnode *vnode;
2909 	fs_cookie cookie;
2910 	vnode_id newID;
2911 	int status;
2912 
2913 	if (FS_CALL(directory, create) == NULL)
2914 		return EROFS;
2915 
2916 	status = FS_CALL(directory, create)(directory->mount->cookie, directory->private_node, name, openMode, perms, &cookie, &newID);
2917 	if (status < B_OK)
2918 		return status;
2919 
2920 	mutex_lock(&sVnodeMutex);
2921 	vnode = lookup_vnode(directory->device, newID);
2922 	mutex_unlock(&sVnodeMutex);
2923 
2924 	if (vnode == NULL) {
2925 		dprintf("vfs: fs_create() returned success but there is no vnode!");
2926 		return EINVAL;
2927 	}
2928 
2929 	if ((status = get_new_fd(FDTYPE_FILE, NULL, vnode, cookie, openMode, kernel)) >= 0)
2930 		return status;
2931 
2932 	// something went wrong, clean up
2933 
2934 	FS_CALL(vnode, close)(vnode->mount->cookie, vnode->private_node, cookie);
2935 	FS_CALL(vnode, free_cookie)(vnode->mount->cookie, vnode->private_node, cookie);
2936 	put_vnode(vnode);
2937 
2938 	FS_CALL(directory, unlink)(directory->mount->cookie, directory->private_node, name);
2939 
2940 	return status;
2941 }
2942 
2943 
2944 /** Calls fs_open() on the given vnode and returns a new
2945  *	file descriptor for it
2946  */
2947 
2948 static int
2949 open_vnode(struct vnode *vnode, int openMode, bool kernel)
2950 {
2951 	fs_cookie cookie;
2952 	int status;
2953 
2954 	status = FS_CALL(vnode, open)(vnode->mount->cookie, vnode->private_node, openMode, &cookie);
2955 	if (status < 0)
2956 		return status;
2957 
2958 	status = get_new_fd(FDTYPE_FILE, NULL, vnode, cookie, openMode, kernel);
2959 	if (status < 0) {
2960 		FS_CALL(vnode, close)(vnode->mount->cookie, vnode->private_node, cookie);
2961 		FS_CALL(vnode, free_cookie)(vnode->mount->cookie, vnode->private_node, cookie);
2962 	}
2963 	return status;
2964 }
2965 
2966 
2967 /** Calls fs open_dir() on the given vnode and returns a new
2968  *	file descriptor for it
2969  */
2970 
2971 static int
2972 open_dir_vnode(struct vnode *vnode, bool kernel)
2973 {
2974 	fs_cookie cookie;
2975 	int status;
2976 
2977 	status = FS_CALL(vnode, open_dir)(vnode->mount->cookie, vnode->private_node, &cookie);
2978 	if (status < B_OK)
2979 		return status;
2980 
2981 	// file is opened, create a fd
2982 	status = get_new_fd(FDTYPE_DIR, NULL, vnode, cookie, 0, kernel);
2983 	if (status >= 0)
2984 		return status;
2985 
2986 	FS_CALL(vnode, close_dir)(vnode->mount->cookie, vnode->private_node, cookie);
2987 	FS_CALL(vnode, free_dir_cookie)(vnode->mount->cookie, vnode->private_node, cookie);
2988 
2989 	return status;
2990 }
2991 
2992 
2993 /** Calls fs open_attr_dir() on the given vnode and returns a new
2994  *	file descriptor for it.
2995  *	Used by attr_dir_open(), and attr_dir_open_fd().
2996  */
2997 
2998 static int
2999 open_attr_dir_vnode(struct vnode *vnode, bool kernel)
3000 {
3001 	fs_cookie cookie;
3002 	int status;
3003 
3004 	if (FS_CALL(vnode, open_attr_dir) == NULL)
3005 		return EOPNOTSUPP;
3006 
3007 	status = FS_CALL(vnode, open_attr_dir)(vnode->mount->cookie, vnode->private_node, &cookie);
3008 	if (status < 0)
3009 		return status;
3010 
3011 	// file is opened, create a fd
3012 	status = get_new_fd(FDTYPE_ATTR_DIR, NULL, vnode, cookie, 0, kernel);
3013 	if (status >= 0)
3014 		return status;
3015 
3016 	FS_CALL(vnode, close_attr_dir)(vnode->mount->cookie, vnode->private_node, cookie);
3017 	FS_CALL(vnode, free_attr_dir_cookie)(vnode->mount->cookie, vnode->private_node, cookie);
3018 
3019 	return status;
3020 }
3021 
3022 
3023 static int
3024 file_create_entry_ref(mount_id mountID, vnode_id directoryID, const char *name, int openMode, int perms, bool kernel)
3025 {
3026 	struct vnode *directory;
3027 	int status;
3028 
3029 	FUNCTION(("file_create_entry_ref: name = '%s', omode %x, perms %d, kernel %d\n", name, openMode, perms, kernel));
3030 
3031 	// get directory to put the new file in
3032 	status = get_vnode(mountID, directoryID, &directory, false);
3033 	if (status < B_OK)
3034 		return status;
3035 
3036 	status = create_vnode(directory, name, openMode, perms, kernel);
3037 	put_vnode(directory);
3038 
3039 	return status;
3040 }
3041 
3042 
3043 static int
3044 file_create(int fd, char *path, int openMode, int perms, bool kernel)
3045 {
3046 	char name[B_FILE_NAME_LENGTH];
3047 	struct vnode *directory;
3048 	int status;
3049 
3050 	FUNCTION(("file_create: path '%s', omode %x, perms %d, kernel %d\n", path, openMode, perms, kernel));
3051 
3052 	// get directory to put the new file in
3053 	status = fd_and_path_to_dir_vnode(fd, path, &directory, name, kernel);
3054 	if (status < 0)
3055 		return status;
3056 
3057 	status = create_vnode(directory, name, openMode, perms, kernel);
3058 
3059 	put_vnode(directory);
3060 	return status;
3061 }
3062 
3063 
3064 static int
3065 file_open_entry_ref(mount_id mountID, vnode_id directoryID, const char *name, int openMode, bool kernel)
3066 {
3067 	struct vnode *vnode;
3068 	int status;
3069 
3070 	if (name == NULL || *name == '\0')
3071 		return B_BAD_VALUE;
3072 
3073 	FUNCTION(("file_open_entry_ref()\n"));
3074 
3075 	// get the vnode matching the entry_ref
3076 	status = entry_ref_to_vnode(mountID, directoryID, name, &vnode);
3077 	if (status < B_OK)
3078 		return status;
3079 
3080 	status = open_vnode(vnode, openMode, kernel);
3081 	if (status < B_OK)
3082 		put_vnode(vnode);
3083 
3084 	cache_node_opened(vnode, FDTYPE_FILE, vnode->cache, mountID, directoryID, vnode->id, name);
3085 	return status;
3086 }
3087 
3088 
3089 static int
3090 file_open(int fd, char *path, int openMode, bool kernel)
3091 {
3092 	int status = B_OK;
3093 	bool traverse = ((openMode & O_NOTRAVERSE) == 0);
3094 
3095 	FUNCTION(("file_open: fd: %d, entry path = '%s', omode %d, kernel %d\n",
3096 		fd, path, openMode, kernel));
3097 
3098 	// get the vnode matching the vnode + path combination
3099 	struct vnode *vnode = NULL;
3100 	status = fd_and_path_to_vnode(fd, path, traverse, &vnode, kernel);
3101 	if (status != B_OK)
3102 		return status;
3103 
3104 	// open the vnode
3105 	status = open_vnode(vnode, openMode, kernel);
3106 	// put only on error -- otherwise our reference was transferred to the FD
3107 	if (status < B_OK)
3108 		put_vnode(vnode);
3109 
3110 	cache_node_opened(vnode, FDTYPE_FILE, vnode->cache, vnode->device, -1, vnode->id, NULL);
3111 	return status;
3112 }
3113 
3114 
3115 static status_t
3116 file_close(struct file_descriptor *descriptor)
3117 {
3118 	struct vnode *vnode = descriptor->u.vnode;
3119 	status_t status = B_OK;
3120 
3121 	FUNCTION(("file_close(descriptor = %p)\n", descriptor));
3122 
3123 	cache_node_closed(vnode, FDTYPE_FILE, vnode->cache, vnode->device, vnode->id);
3124 	if (FS_CALL(vnode, close))
3125 		status = FS_CALL(vnode, close)(vnode->mount->cookie, vnode->private_node, descriptor->cookie);
3126 
3127 	if (status == B_OK) {
3128 		// remove all outstanding locks for this team
3129 		release_advisory_lock(vnode, NULL);
3130 	}
3131 	return status;
3132 }
3133 
3134 
3135 static void
3136 file_free_fd(struct file_descriptor *descriptor)
3137 {
3138 	struct vnode *vnode = descriptor->u.vnode;
3139 
3140 	if (vnode != NULL) {
3141 		FS_CALL(vnode, free_cookie)(vnode->mount->cookie, vnode->private_node, descriptor->cookie);
3142 		put_vnode(vnode);
3143 	}
3144 }
3145 
3146 
3147 static status_t
3148 file_read(struct file_descriptor *descriptor, off_t pos, void *buffer, size_t *length)
3149 {
3150 	struct vnode *vnode = descriptor->u.vnode;
3151 
3152 	FUNCTION(("file_read: buf %p, pos %Ld, len %p = %ld\n", buffer, pos, length, *length));
3153 	return FS_CALL(vnode, read)(vnode->mount->cookie, vnode->private_node, descriptor->cookie, pos, buffer, length);
3154 }
3155 
3156 
3157 static status_t
3158 file_write(struct file_descriptor *descriptor, off_t pos, const void *buffer, size_t *length)
3159 {
3160 	struct vnode *vnode = descriptor->u.vnode;
3161 
3162 	FUNCTION(("file_write: buf %p, pos %Ld, len %p\n", buffer, pos, length));
3163 	return FS_CALL(vnode, write)(vnode->mount->cookie, vnode->private_node, descriptor->cookie, pos, buffer, length);
3164 }
3165 
3166 
3167 static off_t
3168 file_seek(struct file_descriptor *descriptor, off_t pos, int seekType)
3169 {
3170 	off_t offset;
3171 
3172 	FUNCTION(("file_seek(pos = %Ld, seekType = %d)\n", pos, seekType));
3173 	// ToDo: seek should fail for pipes and FIFOs...
3174 
3175 	switch (seekType) {
3176 		case SEEK_SET:
3177 			offset = 0;
3178 			break;
3179 		case SEEK_CUR:
3180 			offset = descriptor->pos;
3181 			break;
3182 		case SEEK_END:
3183 		{
3184 			struct vnode *vnode = descriptor->u.vnode;
3185 			struct stat stat;
3186 			status_t status;
3187 
3188 			if (FS_CALL(vnode, read_stat) == NULL)
3189 				return EOPNOTSUPP;
3190 
3191 			status = FS_CALL(vnode, read_stat)(vnode->mount->cookie, vnode->private_node, &stat);
3192 			if (status < B_OK)
3193 				return status;
3194 
3195 			offset = stat.st_size;
3196 			break;
3197 		}
3198 		default:
3199 			return B_BAD_VALUE;
3200 	}
3201 
3202 	// assumes off_t is 64 bits wide
3203 	if (offset > 0 && LONGLONG_MAX - offset < pos)
3204 		return EOVERFLOW;
3205 
3206 	pos += offset;
3207 	if (pos < 0)
3208 		return B_BAD_VALUE;
3209 
3210 	return descriptor->pos = pos;
3211 }
3212 
3213 
3214 static status_t
3215 file_select(struct file_descriptor *descriptor, uint8 event, uint32 ref,
3216 	struct select_sync *sync)
3217 {
3218 	FUNCTION(("file_select(%p, %u, %lu, %p)\n", descriptor, event, ref, sync));
3219 
3220 	struct vnode *vnode = descriptor->u.vnode;
3221 
3222 	// If the FS has no select() hook, notify select() now.
3223 	if (FS_CALL(vnode, select) == NULL)
3224 		return notify_select_event((selectsync*)sync, ref, event);
3225 
3226 	return FS_CALL(vnode, select)(vnode->mount->cookie, vnode->private_node,
3227 		descriptor->cookie, event, ref, (selectsync*)sync);
3228 }
3229 
3230 
3231 static status_t
3232 file_deselect(struct file_descriptor *descriptor, uint8 event,
3233 	struct select_sync *sync)
3234 {
3235 	struct vnode *vnode = descriptor->u.vnode;
3236 
3237 	if (FS_CALL(vnode, deselect) == NULL)
3238 		return B_OK;
3239 
3240 	return FS_CALL(vnode, deselect)(vnode->mount->cookie, vnode->private_node,
3241 		descriptor->cookie, event, (selectsync*)sync);
3242 }
3243 
3244 
3245 static status_t
3246 dir_create_entry_ref(mount_id mountID, vnode_id parentID, const char *name, int perms, bool kernel)
3247 {
3248 	struct vnode *vnode;
3249 	vnode_id newID;
3250 	status_t status;
3251 
3252 	if (name == NULL || *name == '\0')
3253 		return B_BAD_VALUE;
3254 
3255 	FUNCTION(("dir_create_entry_ref(dev = %ld, ino = %Ld, name = '%s', perms = %d)\n", mountID, parentID, name, perms));
3256 
3257 	status = get_vnode(mountID, parentID, &vnode, kernel);
3258 	if (status < B_OK)
3259 		return status;
3260 
3261 	if (FS_CALL(vnode, create_dir))
3262 		status = FS_CALL(vnode, create_dir)(vnode->mount->cookie, vnode->private_node, name, perms, &newID);
3263 	else
3264 		status = EROFS;
3265 
3266 	put_vnode(vnode);
3267 	return status;
3268 }
3269 
3270 
3271 static status_t
3272 dir_create(int fd, char *path, int perms, bool kernel)
3273 {
3274 	char filename[B_FILE_NAME_LENGTH];
3275 	struct vnode *vnode;
3276 	vnode_id newID;
3277 	status_t status;
3278 
3279 	FUNCTION(("dir_create: path '%s', perms %d, kernel %d\n", path, perms, kernel));
3280 
3281 	status = fd_and_path_to_dir_vnode(fd, path, &vnode, filename, kernel);
3282 	if (status < 0)
3283 		return status;
3284 
3285 	if (FS_CALL(vnode, create_dir))
3286 		status = FS_CALL(vnode, create_dir)(vnode->mount->cookie, vnode->private_node, filename, perms, &newID);
3287 	else
3288 		status = EROFS;
3289 
3290 	put_vnode(vnode);
3291 	return status;
3292 }
3293 
3294 
3295 static int
3296 dir_open_entry_ref(mount_id mountID, vnode_id parentID, const char *name, bool kernel)
3297 {
3298 	struct vnode *vnode;
3299 	int status;
3300 
3301 	FUNCTION(("dir_open_entry_ref()\n"));
3302 
3303 	if (name && *name == '\0')
3304 		return B_BAD_VALUE;
3305 
3306 	// get the vnode matching the entry_ref/node_ref
3307 	if (name)
3308 		status = entry_ref_to_vnode(mountID, parentID, name, &vnode);
3309 	else
3310 		status = get_vnode(mountID, parentID, &vnode, false);
3311 	if (status < B_OK)
3312 		return status;
3313 
3314 	status = open_dir_vnode(vnode, kernel);
3315 	if (status < B_OK)
3316 		put_vnode(vnode);
3317 
3318 	cache_node_opened(vnode, FDTYPE_DIR, vnode->cache, mountID, parentID, vnode->id, name);
3319 	return status;
3320 }
3321 
3322 
3323 static int
3324 dir_open(int fd, char *path, bool kernel)
3325 {
3326 	int status = B_OK;
3327 
3328 	FUNCTION(("dir_open: fd: %d, entry path = '%s', kernel %d\n", fd, path, kernel));
3329 
3330 	// get the vnode matching the vnode + path combination
3331 	struct vnode *vnode = NULL;
3332 	status = fd_and_path_to_vnode(fd, path, true, &vnode, kernel);
3333 	if (status != B_OK)
3334 		return status;
3335 
3336 	// open the dir
3337 	status = open_dir_vnode(vnode, kernel);
3338 	if (status < B_OK)
3339 		put_vnode(vnode);
3340 
3341 	cache_node_opened(vnode, FDTYPE_DIR, vnode->cache, vnode->device, -1, vnode->id, NULL);
3342 	return status;
3343 }
3344 
3345 
3346 static status_t
3347 dir_close(struct file_descriptor *descriptor)
3348 {
3349 	struct vnode *vnode = descriptor->u.vnode;
3350 
3351 	FUNCTION(("dir_close(descriptor = %p)\n", descriptor));
3352 
3353 	cache_node_closed(vnode, FDTYPE_DIR, vnode->cache, vnode->device, vnode->id);
3354 	if (FS_CALL(vnode, close_dir))
3355 		return FS_CALL(vnode, close_dir)(vnode->mount->cookie, vnode->private_node, descriptor->cookie);
3356 
3357 	return B_OK;
3358 }
3359 
3360 
3361 static void
3362 dir_free_fd(struct file_descriptor *descriptor)
3363 {
3364 	struct vnode *vnode = descriptor->u.vnode;
3365 
3366 	if (vnode != NULL) {
3367 		FS_CALL(vnode, free_dir_cookie)(vnode->mount->cookie, vnode->private_node, descriptor->cookie);
3368 		put_vnode(vnode);
3369 	}
3370 }
3371 
3372 
3373 static status_t
3374 dir_read(struct file_descriptor *descriptor, struct dirent *buffer, size_t bufferSize, uint32 *_count)
3375 {
3376 	return dir_read(descriptor->u.vnode, descriptor->cookie, buffer, bufferSize, _count);
3377 }
3378 
3379 
3380 static void
3381 fix_dirent(struct vnode *parent, struct dirent *entry)
3382 {
3383 	// set d_pdev and d_pino
3384 	entry->d_pdev = parent->device;
3385 	entry->d_pino = parent->id;
3386 
3387 	// If this is the ".." entry and the directory is the root of a FS,
3388 	// we need to replace d_dev and d_ino with the actual values.
3389 	if (strcmp(entry->d_name, "..") == 0
3390 		&& parent->mount->root_vnode == parent
3391 		&& parent->mount->covers_vnode) {
3392 
3393 		inc_vnode_ref_count(parent);	// vnode_path_to_vnode() puts the node
3394 
3395 		struct vnode *vnode;
3396 		status_t status = vnode_path_to_vnode(parent, "..", false, 0, &vnode,
3397 			NULL);
3398 
3399 		if (status == B_OK) {
3400 			entry->d_dev = vnode->device;
3401 			entry->d_ino = vnode->id;
3402 		}
3403 	} else {
3404 		// resolve mount points
3405 		struct vnode *vnode = NULL;
3406 		status_t status = get_vnode(entry->d_dev, entry->d_ino, &vnode, false);
3407 		if (status != B_OK)
3408 			return;
3409 
3410 		recursive_lock_lock(&sMountOpLock);
3411 		if (vnode->covered_by) {
3412 			entry->d_dev = vnode->covered_by->device;
3413 			entry->d_ino = vnode->covered_by->id;
3414 		}
3415 		recursive_lock_unlock(&sMountOpLock);
3416 
3417 		put_vnode(vnode);
3418 	}
3419 }
3420 
3421 
3422 static status_t
3423 dir_read(struct vnode *vnode, fs_cookie cookie, struct dirent *buffer, size_t bufferSize, uint32 *_count)
3424 {
3425 	if (!FS_CALL(vnode, read_dir))
3426 		return EOPNOTSUPP;
3427 
3428 	status_t error = FS_CALL(vnode, read_dir)(vnode->mount->cookie,vnode->private_node,cookie,buffer,bufferSize,_count);
3429 	if (error != B_OK)
3430 		return error;
3431 
3432 	// we need to adjust the read dirents
3433 	if (*_count > 0) {
3434 		// XXX: Currently reading only one dirent is supported. Make this a loop!
3435 		fix_dirent(vnode, buffer);
3436 	}
3437 
3438 	return error;
3439 }
3440 
3441 
3442 static status_t
3443 dir_rewind(struct file_descriptor *descriptor)
3444 {
3445 	struct vnode *vnode = descriptor->u.vnode;
3446 
3447 	if (FS_CALL(vnode, rewind_dir))
3448 		return FS_CALL(vnode, rewind_dir)(vnode->mount->cookie,vnode->private_node,descriptor->cookie);
3449 
3450 	return EOPNOTSUPP;
3451 }
3452 
3453 
3454 static status_t
3455 dir_remove(char *path, bool kernel)
3456 {
3457 	char name[B_FILE_NAME_LENGTH];
3458 	struct vnode *directory;
3459 	status_t status;
3460 
3461 	status = path_to_dir_vnode(path, &directory, name, kernel);
3462 	if (status < B_OK)
3463 		return status;
3464 
3465 	if (FS_CALL(directory, remove_dir))
3466 		status = FS_CALL(directory, remove_dir)(directory->mount->cookie, directory->private_node, name);
3467 	else
3468 		status = EROFS;
3469 
3470 	put_vnode(directory);
3471 	return status;
3472 }
3473 
3474 
3475 static status_t
3476 common_ioctl(struct file_descriptor *descriptor, ulong op, void *buffer, size_t length)
3477 {
3478 	struct vnode *vnode = descriptor->u.vnode;
3479 
3480 	if (FS_CALL(vnode, ioctl)) {
3481 		return FS_CALL(vnode, ioctl)(vnode->mount->cookie, vnode->private_node,
3482 			descriptor->cookie, op, buffer, length);
3483 	}
3484 
3485 	return EOPNOTSUPP;
3486 }
3487 
3488 
3489 static status_t
3490 common_fcntl(int fd, int op, uint32 argument, bool kernel)
3491 {
3492 	struct file_descriptor *descriptor;
3493 	struct vnode *vnode;
3494 	struct flock flock;
3495 	status_t status;
3496 
3497 	FUNCTION(("common_fcntl(fd = %d, op = %d, argument = %lx, %s)\n",
3498 		fd, op, argument, kernel ? "kernel" : "user"));
3499 
3500 	descriptor = get_fd_and_vnode(fd, &vnode, kernel);
3501 	if (descriptor == NULL)
3502 		return B_FILE_ERROR;
3503 
3504 	if (op == F_SETLK || op == F_SETLKW || op == F_GETLK) {
3505 		if (descriptor->type != FDTYPE_FILE)
3506 			return B_BAD_VALUE;
3507 		if (user_memcpy(&flock, (struct flock *)argument, sizeof(struct flock)) < B_OK)
3508 			return B_BAD_ADDRESS;
3509 	}
3510 
3511 	switch (op) {
3512 		case F_SETFD:
3513 			// Set file descriptor flags
3514 
3515 			// O_CLOEXEC is the only flag available at this time
3516 			if (argument == FD_CLOEXEC)
3517 				atomic_or(&descriptor->open_mode, O_CLOEXEC);
3518 			else
3519 				atomic_and(&descriptor->open_mode, O_CLOEXEC);
3520 
3521 			status = B_OK;
3522 			break;
3523 
3524 		case F_GETFD:
3525 			// Get file descriptor flags
3526 			status = (descriptor->open_mode & O_CLOEXEC) ? FD_CLOEXEC : 0;
3527 			break;
3528 
3529 		case F_SETFL:
3530 			// Set file descriptor open mode
3531 			if (FS_CALL(vnode, set_flags)) {
3532 				// we only accept changes to O_APPEND and O_NONBLOCK
3533 				argument &= O_APPEND | O_NONBLOCK;
3534 
3535 				status = FS_CALL(vnode, set_flags)(vnode->mount->cookie, vnode->private_node, descriptor->cookie, (int)argument);
3536 				if (status == B_OK) {
3537 					// update this descriptor's open_mode field
3538 					descriptor->open_mode = (descriptor->open_mode & ~(O_APPEND | O_NONBLOCK)) | argument;
3539 				}
3540 			} else
3541 				status = EOPNOTSUPP;
3542 			break;
3543 
3544 		case F_GETFL:
3545 			// Get file descriptor open mode
3546 			status = descriptor->open_mode;
3547 			break;
3548 
3549 		case F_DUPFD:
3550 			status = new_fd_etc(get_current_io_context(kernel), descriptor, (int)argument);
3551 			if (status >= 0)
3552 				atomic_add(&descriptor->ref_count, 1);
3553 			break;
3554 
3555 		case F_GETLK:
3556 			status = get_advisory_lock(descriptor->u.vnode, &flock);
3557 			if (status == B_OK) {
3558 				// copy back flock structure
3559 				status = user_memcpy((struct flock *)argument, &flock, sizeof(struct flock));
3560 			}
3561 			break;
3562 
3563 		case F_SETLK:
3564 		case F_SETLKW:
3565 			status = normalize_flock(descriptor, &flock);
3566 			if (status < B_OK)
3567 				break;
3568 
3569 			if (flock.l_type == F_UNLCK)
3570 				status = release_advisory_lock(descriptor->u.vnode, &flock);
3571 			else {
3572 				// the open mode must match the lock type
3573 				if ((descriptor->open_mode & O_RWMASK) == O_RDONLY && flock.l_type == F_WRLCK
3574 					|| (descriptor->open_mode & O_RWMASK) == O_WRONLY && flock.l_type == F_RDLCK)
3575 					status = B_FILE_ERROR;
3576 				else
3577 					status = acquire_advisory_lock(descriptor->u.vnode, &flock, op == F_SETLKW);
3578 			}
3579 			break;
3580 
3581 		// ToDo: add support for more ops?
3582 
3583 		default:
3584 			status = B_BAD_VALUE;
3585 	}
3586 
3587 	put_fd(descriptor);
3588 	return status;
3589 }
3590 
3591 
3592 static status_t
3593 common_sync(int fd, bool kernel)
3594 {
3595 	struct file_descriptor *descriptor;
3596 	struct vnode *vnode;
3597 	status_t status;
3598 
3599 	FUNCTION(("common_fsync: entry. fd %d kernel %d\n", fd, kernel));
3600 
3601 	descriptor = get_fd_and_vnode(fd, &vnode, kernel);
3602 	if (descriptor == NULL)
3603 		return B_FILE_ERROR;
3604 
3605 	if (FS_CALL(vnode, fsync) != NULL)
3606 		status = FS_CALL(vnode, fsync)(vnode->mount->cookie, vnode->private_node);
3607 	else
3608 		status = EOPNOTSUPP;
3609 
3610 	put_fd(descriptor);
3611 	return status;
3612 }
3613 
3614 
3615 static status_t
3616 common_lock_node(int fd, bool kernel)
3617 {
3618 	// TODO: Implement!
3619 	return EOPNOTSUPP;
3620 }
3621 
3622 
3623 static status_t
3624 common_unlock_node(int fd, bool kernel)
3625 {
3626 	// TODO: Implement!
3627 	return EOPNOTSUPP;
3628 }
3629 
3630 
3631 static status_t
3632 common_read_link(int fd, char *path, char *buffer, size_t *_bufferSize,
3633 	bool kernel)
3634 {
3635 	struct vnode *vnode;
3636 	int status;
3637 
3638 	status = fd_and_path_to_vnode(fd, path, false, &vnode, kernel);
3639 	if (status < B_OK)
3640 		return status;
3641 
3642 	if (FS_CALL(vnode, read_link) != NULL) {
3643 		status = FS_CALL(vnode, read_link)(vnode->mount->cookie,
3644 			vnode->private_node, buffer, _bufferSize);
3645 	} else
3646 		status = B_BAD_VALUE;
3647 
3648 	put_vnode(vnode);
3649 	return status;
3650 }
3651 
3652 
3653 static status_t
3654 common_write_link(char *path, char *toPath, bool kernel)
3655 {
3656 	struct vnode *vnode;
3657 	int status;
3658 
3659 	status = path_to_vnode(path, false, &vnode, kernel);
3660 	if (status < B_OK)
3661 		return status;
3662 
3663 	if (FS_CALL(vnode, write_link) != NULL)
3664 		status = FS_CALL(vnode, write_link)(vnode->mount->cookie, vnode->private_node, toPath);
3665 	else
3666 		status = EOPNOTSUPP;
3667 
3668 	put_vnode(vnode);
3669 
3670 	return status;
3671 }
3672 
3673 
3674 static status_t
3675 common_create_symlink(int fd, char *path, const char *toPath, int mode,
3676 	bool kernel)
3677 {
3678 	// path validity checks have to be in the calling function!
3679 	char name[B_FILE_NAME_LENGTH];
3680 	struct vnode *vnode;
3681 	int status;
3682 
3683 	FUNCTION(("common_create_symlink(fd = %d, path = %s, toPath = %s, mode = %d, kernel = %d)\n", fd, path, toPath, mode, kernel));
3684 
3685 	status = fd_and_path_to_dir_vnode(fd, path, &vnode, name, kernel);
3686 	if (status < B_OK)
3687 		return status;
3688 
3689 	if (FS_CALL(vnode, create_symlink) != NULL)
3690 		status = FS_CALL(vnode, create_symlink)(vnode->mount->cookie, vnode->private_node, name, toPath, mode);
3691 	else
3692 		status = EROFS;
3693 
3694 	put_vnode(vnode);
3695 
3696 	return status;
3697 }
3698 
3699 
3700 static status_t
3701 common_create_link(char *path, char *toPath, bool kernel)
3702 {
3703 	// path validity checks have to be in the calling function!
3704 	char name[B_FILE_NAME_LENGTH];
3705 	struct vnode *directory, *vnode;
3706 	int status;
3707 
3708 	FUNCTION(("common_create_link(path = %s, toPath = %s, kernel = %d)\n", path, toPath, kernel));
3709 
3710 	status = path_to_dir_vnode(path, &directory, name, kernel);
3711 	if (status < B_OK)
3712 		return status;
3713 
3714 	status = path_to_vnode(toPath, true, &vnode, kernel);
3715 	if (status < B_OK)
3716 		goto err;
3717 
3718 	if (directory->mount != vnode->mount) {
3719 		status = B_CROSS_DEVICE_LINK;
3720 		goto err1;
3721 	}
3722 
3723 	if (FS_CALL(vnode, link) != NULL)
3724 		status = FS_CALL(vnode, link)(directory->mount->cookie, directory->private_node, name, vnode->private_node);
3725 	else
3726 		status = EROFS;
3727 
3728 err1:
3729 	put_vnode(vnode);
3730 err:
3731 	put_vnode(directory);
3732 
3733 	return status;
3734 }
3735 
3736 
3737 static status_t
3738 common_unlink(int fd, char *path, bool kernel)
3739 {
3740 	char filename[B_FILE_NAME_LENGTH];
3741 	struct vnode *vnode;
3742 	int status;
3743 
3744 	FUNCTION(("common_unlink: fd: %d, path '%s', kernel %d\n", fd, path, kernel));
3745 
3746 	status = fd_and_path_to_dir_vnode(fd, path, &vnode, filename, kernel);
3747 	if (status < 0)
3748 		return status;
3749 
3750 	if (FS_CALL(vnode, unlink) != NULL)
3751 		status = FS_CALL(vnode, unlink)(vnode->mount->cookie, vnode->private_node, filename);
3752 	else
3753 		status = EROFS;
3754 
3755 	put_vnode(vnode);
3756 
3757 	return status;
3758 }
3759 
3760 
3761 static status_t
3762 common_access(char *path, int mode, bool kernel)
3763 {
3764 	struct vnode *vnode;
3765 	int status;
3766 
3767 	status = path_to_vnode(path, true, &vnode, kernel);
3768 	if (status < B_OK)
3769 		return status;
3770 
3771 	if (FS_CALL(vnode, access) != NULL)
3772 		status = FS_CALL(vnode, access)(vnode->mount->cookie, vnode->private_node, mode);
3773 	else
3774 		status = EOPNOTSUPP;
3775 
3776 	put_vnode(vnode);
3777 
3778 	return status;
3779 }
3780 
3781 
3782 static status_t
3783 common_rename(int fd, char *path, int newFD, char *newPath, bool kernel)
3784 {
3785 	struct vnode *fromVnode, *toVnode;
3786 	char fromName[B_FILE_NAME_LENGTH];
3787 	char toName[B_FILE_NAME_LENGTH];
3788 	int status;
3789 
3790 	FUNCTION(("common_rename(fd = %d, path = %s, newFD = %d, newPath = %s, kernel = %d)\n", fd, path, newFD, newPath, kernel));
3791 
3792 	status = fd_and_path_to_dir_vnode(fd, path, &fromVnode, fromName, kernel);
3793 	if (status < 0)
3794 		return status;
3795 
3796 	status = fd_and_path_to_dir_vnode(newFD, newPath, &toVnode, toName, kernel);
3797 	if (status < 0)
3798 		goto err;
3799 
3800 	if (fromVnode->device != toVnode->device) {
3801 		status = B_CROSS_DEVICE_LINK;
3802 		goto err1;
3803 	}
3804 
3805 	if (FS_CALL(fromVnode, rename) != NULL)
3806 		status = FS_CALL(fromVnode, rename)(fromVnode->mount->cookie, fromVnode->private_node, fromName, toVnode->private_node, toName);
3807 	else
3808 		status = EROFS;
3809 
3810 err1:
3811 	put_vnode(toVnode);
3812 err:
3813 	put_vnode(fromVnode);
3814 
3815 	return status;
3816 }
3817 
3818 
3819 static status_t
3820 common_read_stat(struct file_descriptor *descriptor, struct stat *stat)
3821 {
3822 	struct vnode *vnode = descriptor->u.vnode;
3823 
3824 	FUNCTION(("common_read_stat: stat %p\n", stat));
3825 
3826 	status_t status = FS_CALL(vnode, read_stat)(vnode->mount->cookie,
3827 		vnode->private_node, stat);
3828 
3829 	// fill in the st_dev and st_ino fields
3830 	if (status == B_OK) {
3831 		stat->st_dev = vnode->device;
3832 		stat->st_ino = vnode->id;
3833 	}
3834 
3835 	return status;
3836 }
3837 
3838 
3839 static status_t
3840 common_write_stat(struct file_descriptor *descriptor, const struct stat *stat, int statMask)
3841 {
3842 	struct vnode *vnode = descriptor->u.vnode;
3843 
3844 	FUNCTION(("common_write_stat(vnode = %p, stat = %p, statMask = %d)\n", vnode, stat, statMask));
3845 	if (!FS_CALL(vnode, write_stat))
3846 		return EROFS;
3847 
3848 	return FS_CALL(vnode, write_stat)(vnode->mount->cookie, vnode->private_node, stat, statMask);
3849 }
3850 
3851 
3852 static status_t
3853 common_path_read_stat(int fd, char *path, bool traverseLeafLink,
3854 	struct stat *stat, bool kernel)
3855 {
3856 	struct vnode *vnode;
3857 	status_t status;
3858 
3859 	FUNCTION(("common_path_read_stat: fd: %d, path '%s', stat %p,\n", fd, path, stat));
3860 
3861 	status = fd_and_path_to_vnode(fd, path, traverseLeafLink, &vnode, kernel);
3862 	if (status < 0)
3863 		return status;
3864 
3865 	status = FS_CALL(vnode, read_stat)(vnode->mount->cookie, vnode->private_node, stat);
3866 
3867 	// fill in the st_dev and st_ino fields
3868 	if (status == B_OK) {
3869 		stat->st_dev = vnode->device;
3870 		stat->st_ino = vnode->id;
3871 	}
3872 
3873 	put_vnode(vnode);
3874 	return status;
3875 }
3876 
3877 
3878 static status_t
3879 common_path_write_stat(int fd, char *path, bool traverseLeafLink,
3880 	const struct stat *stat, int statMask, bool kernel)
3881 {
3882 	struct vnode *vnode;
3883 	int status;
3884 
3885 	FUNCTION(("common_write_stat: fd: %d, path '%s', stat %p, stat_mask %d, kernel %d\n", fd, path, stat, statMask, kernel));
3886 
3887 	status = fd_and_path_to_vnode(fd, path, traverseLeafLink, &vnode, kernel);
3888 	if (status < 0)
3889 		return status;
3890 
3891 	if (FS_CALL(vnode, write_stat))
3892 		status = FS_CALL(vnode, write_stat)(vnode->mount->cookie, vnode->private_node, stat, statMask);
3893 	else
3894 		status = EROFS;
3895 
3896 	put_vnode(vnode);
3897 
3898 	return status;
3899 }
3900 
3901 
3902 static int
3903 attr_dir_open(int fd, char *path, bool kernel)
3904 {
3905 	struct vnode *vnode;
3906 	int status;
3907 
3908 	FUNCTION(("attr_dir_open(fd = %d, path = '%s', kernel = %d)\n", fd, path, kernel));
3909 
3910 	status = fd_and_path_to_vnode(fd, path, true, &vnode, kernel);
3911 	if (status < B_OK)
3912 		return status;
3913 
3914 	status = open_attr_dir_vnode(vnode, kernel);
3915 	if (status < 0)
3916 		put_vnode(vnode);
3917 
3918 	return status;
3919 }
3920 
3921 
3922 static status_t
3923 attr_dir_close(struct file_descriptor *descriptor)
3924 {
3925 	struct vnode *vnode = descriptor->u.vnode;
3926 
3927 	FUNCTION(("attr_dir_close(descriptor = %p)\n", descriptor));
3928 
3929 	if (FS_CALL(vnode, close_attr_dir))
3930 		return FS_CALL(vnode, close_attr_dir)(vnode->mount->cookie, vnode->private_node, descriptor->cookie);
3931 
3932 	return B_OK;
3933 }
3934 
3935 
3936 static void
3937 attr_dir_free_fd(struct file_descriptor *descriptor)
3938 {
3939 	struct vnode *vnode = descriptor->u.vnode;
3940 
3941 	if (vnode != NULL) {
3942 		FS_CALL(vnode, free_attr_dir_cookie)(vnode->mount->cookie, vnode->private_node, descriptor->cookie);
3943 		put_vnode(vnode);
3944 	}
3945 }
3946 
3947 
3948 static status_t
3949 attr_dir_read(struct file_descriptor *descriptor, struct dirent *buffer, size_t bufferSize, uint32 *_count)
3950 {
3951 	struct vnode *vnode = descriptor->u.vnode;
3952 
3953 	FUNCTION(("attr_dir_read(descriptor = %p)\n", descriptor));
3954 
3955 	if (FS_CALL(vnode, read_attr_dir))
3956 		return FS_CALL(vnode, read_attr_dir)(vnode->mount->cookie, vnode->private_node, descriptor->cookie, buffer, bufferSize, _count);
3957 
3958 	return EOPNOTSUPP;
3959 }
3960 
3961 
3962 static status_t
3963 attr_dir_rewind(struct file_descriptor *descriptor)
3964 {
3965 	struct vnode *vnode = descriptor->u.vnode;
3966 
3967 	FUNCTION(("attr_dir_rewind(descriptor = %p)\n", descriptor));
3968 
3969 	if (FS_CALL(vnode, rewind_attr_dir))
3970 		return FS_CALL(vnode, rewind_attr_dir)(vnode->mount->cookie, vnode->private_node, descriptor->cookie);
3971 
3972 	return EOPNOTSUPP;
3973 }
3974 
3975 
3976 static int
3977 attr_create(int fd, const char *name, uint32 type, int openMode, bool kernel)
3978 {
3979 	struct vnode *vnode;
3980 	fs_cookie cookie;
3981 	int status;
3982 
3983 	if (name == NULL || *name == '\0')
3984 		return B_BAD_VALUE;
3985 
3986 	vnode = get_vnode_from_fd(fd, kernel);
3987 	if (vnode == NULL)
3988 		return B_FILE_ERROR;
3989 
3990 	if (FS_CALL(vnode, create_attr) == NULL) {
3991 		status = EROFS;
3992 		goto err;
3993 	}
3994 
3995 	status = FS_CALL(vnode, create_attr)(vnode->mount->cookie, vnode->private_node, name, type, openMode, &cookie);
3996 	if (status < B_OK)
3997 		goto err;
3998 
3999 	if ((status = get_new_fd(FDTYPE_ATTR, NULL, vnode, cookie, openMode, kernel)) >= 0)
4000 		return status;
4001 
4002 	FS_CALL(vnode, close_attr)(vnode->mount->cookie, vnode->private_node, cookie);
4003 	FS_CALL(vnode, free_attr_cookie)(vnode->mount->cookie, vnode->private_node, cookie);
4004 
4005 	FS_CALL(vnode, remove_attr)(vnode->mount->cookie, vnode->private_node, name);
4006 
4007 err:
4008 	put_vnode(vnode);
4009 
4010 	return status;
4011 }
4012 
4013 
4014 static int
4015 attr_open(int fd, const char *name, int openMode, bool kernel)
4016 {
4017 	struct vnode *vnode;
4018 	fs_cookie cookie;
4019 	int status;
4020 
4021 	if (name == NULL || *name == '\0')
4022 		return B_BAD_VALUE;
4023 
4024 	vnode = get_vnode_from_fd(fd, kernel);
4025 	if (vnode == NULL)
4026 		return B_FILE_ERROR;
4027 
4028 	if (FS_CALL(vnode, open_attr) == NULL) {
4029 		status = EOPNOTSUPP;
4030 		goto err;
4031 	}
4032 
4033 	status = FS_CALL(vnode, open_attr)(vnode->mount->cookie, vnode->private_node, name, openMode, &cookie);
4034 	if (status < B_OK)
4035 		goto err;
4036 
4037 	// now we only need a file descriptor for this attribute and we're done
4038 	if ((status = get_new_fd(FDTYPE_ATTR, NULL, vnode, cookie, openMode, kernel)) >= 0)
4039 		return status;
4040 
4041 	FS_CALL(vnode, close_attr)(vnode->mount->cookie, vnode->private_node, cookie);
4042 	FS_CALL(vnode, free_attr_cookie)(vnode->mount->cookie, vnode->private_node, cookie);
4043 
4044 err:
4045 	put_vnode(vnode);
4046 
4047 	return status;
4048 }
4049 
4050 
4051 static status_t
4052 attr_close(struct file_descriptor *descriptor)
4053 {
4054 	struct vnode *vnode = descriptor->u.vnode;
4055 
4056 	FUNCTION(("attr_close(descriptor = %p)\n", descriptor));
4057 
4058 	if (FS_CALL(vnode, close_attr))
4059 		return FS_CALL(vnode, close_attr)(vnode->mount->cookie, vnode->private_node, descriptor->cookie);
4060 
4061 	return B_OK;
4062 }
4063 
4064 
4065 static void
4066 attr_free_fd(struct file_descriptor *descriptor)
4067 {
4068 	struct vnode *vnode = descriptor->u.vnode;
4069 
4070 	if (vnode != NULL) {
4071 		FS_CALL(vnode, free_attr_cookie)(vnode->mount->cookie, vnode->private_node, descriptor->cookie);
4072 		put_vnode(vnode);
4073 	}
4074 }
4075 
4076 
4077 static status_t
4078 attr_read(struct file_descriptor *descriptor, off_t pos, void *buffer, size_t *length)
4079 {
4080 	struct vnode *vnode = descriptor->u.vnode;
4081 
4082 	FUNCTION(("attr_read: buf %p, pos %Ld, len %p = %ld\n", buffer, pos, length, *length));
4083 	if (!FS_CALL(vnode, read_attr))
4084 		return EOPNOTSUPP;
4085 
4086 	return FS_CALL(vnode, read_attr)(vnode->mount->cookie, vnode->private_node, descriptor->cookie, pos, buffer, length);
4087 }
4088 
4089 
4090 static status_t
4091 attr_write(struct file_descriptor *descriptor, off_t pos, const void *buffer, size_t *length)
4092 {
4093 	struct vnode *vnode = descriptor->u.vnode;
4094 
4095 	FUNCTION(("attr_write: buf %p, pos %Ld, len %p\n", buffer, pos, length));
4096 	if (!FS_CALL(vnode, write_attr))
4097 		return EOPNOTSUPP;
4098 
4099 	return FS_CALL(vnode, write_attr)(vnode->mount->cookie, vnode->private_node, descriptor->cookie, pos, buffer, length);
4100 }
4101 
4102 
4103 static off_t
4104 attr_seek(struct file_descriptor *descriptor, off_t pos, int seekType)
4105 {
4106 	off_t offset;
4107 
4108 	switch (seekType) {
4109 		case SEEK_SET:
4110 			offset = 0;
4111 			break;
4112 		case SEEK_CUR:
4113 			offset = descriptor->pos;
4114 			break;
4115 		case SEEK_END:
4116 		{
4117 			struct vnode *vnode = descriptor->u.vnode;
4118 			struct stat stat;
4119 			status_t status;
4120 
4121 			if (FS_CALL(vnode, read_stat) == NULL)
4122 				return EOPNOTSUPP;
4123 
4124 			status = FS_CALL(vnode, read_attr_stat)(vnode->mount->cookie, vnode->private_node, descriptor->cookie, &stat);
4125 			if (status < B_OK)
4126 				return status;
4127 
4128 			offset = stat.st_size;
4129 			break;
4130 		}
4131 		default:
4132 			return B_BAD_VALUE;
4133 	}
4134 
4135 	// assumes off_t is 64 bits wide
4136 	if (offset > 0 && LONGLONG_MAX - offset < pos)
4137 		return EOVERFLOW;
4138 
4139 	pos += offset;
4140 	if (pos < 0)
4141 		return B_BAD_VALUE;
4142 
4143 	return descriptor->pos = pos;
4144 }
4145 
4146 
4147 static status_t
4148 attr_read_stat(struct file_descriptor *descriptor, struct stat *stat)
4149 {
4150 	struct vnode *vnode = descriptor->u.vnode;
4151 
4152 	FUNCTION(("attr_read_stat: stat 0x%p\n", stat));
4153 
4154 	if (!FS_CALL(vnode, read_attr_stat))
4155 		return EOPNOTSUPP;
4156 
4157 	return FS_CALL(vnode, read_attr_stat)(vnode->mount->cookie, vnode->private_node, descriptor->cookie, stat);
4158 }
4159 
4160 
4161 static status_t
4162 attr_write_stat(struct file_descriptor *descriptor, const struct stat *stat, int statMask)
4163 {
4164 	struct vnode *vnode = descriptor->u.vnode;
4165 
4166 	FUNCTION(("attr_write_stat: stat = %p, statMask %d\n", stat, statMask));
4167 
4168 	if (!FS_CALL(vnode, write_attr_stat))
4169 		return EROFS;
4170 
4171 	return FS_CALL(vnode, write_attr_stat)(vnode->mount->cookie, vnode->private_node, descriptor->cookie, stat, statMask);
4172 }
4173 
4174 
4175 static status_t
4176 attr_remove(int fd, const char *name, bool kernel)
4177 {
4178 	struct file_descriptor *descriptor;
4179 	struct vnode *vnode;
4180 	int status;
4181 
4182 	if (name == NULL || *name == '\0')
4183 		return B_BAD_VALUE;
4184 
4185 	FUNCTION(("attr_remove: fd = %d, name = \"%s\", kernel %d\n", fd, name, kernel));
4186 
4187 	descriptor = get_fd_and_vnode(fd, &vnode, kernel);
4188 	if (descriptor == NULL)
4189 		return B_FILE_ERROR;
4190 
4191 	if (FS_CALL(vnode, remove_attr))
4192 		status = FS_CALL(vnode, remove_attr)(vnode->mount->cookie, vnode->private_node, name);
4193 	else
4194 		status = EROFS;
4195 
4196 	put_fd(descriptor);
4197 
4198 	return status;
4199 }
4200 
4201 
4202 static status_t
4203 attr_rename(int fromfd, const char *fromName, int tofd, const char *toName, bool kernel)
4204 {
4205 	struct file_descriptor *fromDescriptor, *toDescriptor;
4206 	struct vnode *fromVnode, *toVnode;
4207 	int status;
4208 
4209 	if (fromName == NULL || *fromName == '\0' || toName == NULL || *toName == '\0')
4210 		return B_BAD_VALUE;
4211 
4212 	FUNCTION(("attr_rename: from fd = %d, from name = \"%s\", to fd = %d, to name = \"%s\", kernel %d\n", fromfd, fromName, tofd, toName, kernel));
4213 
4214 	fromDescriptor = get_fd_and_vnode(fromfd, &fromVnode, kernel);
4215 	if (fromDescriptor == NULL)
4216 		return B_FILE_ERROR;
4217 
4218 	toDescriptor = get_fd_and_vnode(tofd, &toVnode, kernel);
4219 	if (toDescriptor == NULL) {
4220 		status = B_FILE_ERROR;
4221 		goto err;
4222 	}
4223 
4224 	// are the files on the same volume?
4225 	if (fromVnode->device != toVnode->device) {
4226 		status = B_CROSS_DEVICE_LINK;
4227 		goto err1;
4228 	}
4229 
4230 	if (FS_CALL(fromVnode, rename_attr))
4231 		status = FS_CALL(fromVnode, rename_attr)(fromVnode->mount->cookie, fromVnode->private_node, fromName, toVnode->private_node, toName);
4232 	else
4233 		status = EROFS;
4234 
4235 err1:
4236 	put_fd(toDescriptor);
4237 err:
4238 	put_fd(fromDescriptor);
4239 
4240 	return status;
4241 }
4242 
4243 
4244 static status_t
4245 index_dir_open(mount_id mountID, bool kernel)
4246 {
4247 	struct fs_mount *mount;
4248 	fs_cookie cookie;
4249 	status_t status;
4250 
4251 	FUNCTION(("index_dir_open(mountID = %ld, kernel = %d)\n", mountID, kernel));
4252 
4253 	mount = get_mount(mountID);
4254 	if (mount == NULL)
4255 		return B_BAD_VALUE;
4256 
4257 	if (FS_MOUNT_CALL(mount, open_index_dir) == NULL) {
4258 		status = EOPNOTSUPP;
4259 		goto out;
4260 	}
4261 
4262 	status = FS_MOUNT_CALL(mount, open_index_dir)(mount->cookie, &cookie);
4263 	if (status < B_OK)
4264 		goto out;
4265 
4266 	// get fd for the index directory
4267 	status = get_new_fd(FDTYPE_INDEX_DIR, mount, NULL, cookie, 0, kernel);
4268 	if (status >= 0)
4269 		goto out;
4270 
4271 	// something went wrong
4272 	FS_MOUNT_CALL(mount, close_index_dir)(mount->cookie, cookie);
4273 	FS_MOUNT_CALL(mount, free_index_dir_cookie)(mount->cookie, cookie);
4274 
4275 out:
4276 	put_mount(mount);
4277 	return status;
4278 }
4279 
4280 
4281 static status_t
4282 index_dir_close(struct file_descriptor *descriptor)
4283 {
4284 	struct fs_mount *mount = descriptor->u.mount;
4285 
4286 	FUNCTION(("index_dir_close(descriptor = %p)\n", descriptor));
4287 
4288 	if (FS_MOUNT_CALL(mount, close_index_dir))
4289 		return FS_MOUNT_CALL(mount, close_index_dir)(mount->cookie, descriptor->cookie);
4290 
4291 	return B_OK;
4292 }
4293 
4294 
4295 static void
4296 index_dir_free_fd(struct file_descriptor *descriptor)
4297 {
4298 	struct fs_mount *mount = descriptor->u.mount;
4299 
4300 	if (mount != NULL) {
4301 		FS_MOUNT_CALL(mount, free_index_dir_cookie)(mount->cookie, descriptor->cookie);
4302 		// ToDo: find a replacement ref_count object - perhaps the root dir?
4303 		//put_vnode(vnode);
4304 	}
4305 }
4306 
4307 
4308 static status_t
4309 index_dir_read(struct file_descriptor *descriptor, struct dirent *buffer, size_t bufferSize, uint32 *_count)
4310 {
4311 	struct fs_mount *mount = descriptor->u.mount;
4312 
4313 	if (FS_MOUNT_CALL(mount, read_index_dir))
4314 		return FS_MOUNT_CALL(mount, read_index_dir)(mount->cookie, descriptor->cookie, buffer, bufferSize, _count);
4315 
4316 	return EOPNOTSUPP;
4317 }
4318 
4319 
4320 static status_t
4321 index_dir_rewind(struct file_descriptor *descriptor)
4322 {
4323 	struct fs_mount *mount = descriptor->u.mount;
4324 
4325 	if (FS_MOUNT_CALL(mount, rewind_index_dir))
4326 		return FS_MOUNT_CALL(mount, rewind_index_dir)(mount->cookie, descriptor->cookie);
4327 
4328 	return EOPNOTSUPP;
4329 }
4330 
4331 
4332 static status_t
4333 index_create(mount_id mountID, const char *name, uint32 type, uint32 flags, bool kernel)
4334 {
4335 	struct fs_mount *mount;
4336 	status_t status;
4337 
4338 	FUNCTION(("index_create(mountID = %ld, name = %s, kernel = %d)\n", mountID, name, kernel));
4339 
4340 	mount = get_mount(mountID);
4341 	if (mount == NULL)
4342 		return B_BAD_VALUE;
4343 
4344 	if (FS_MOUNT_CALL(mount, create_index) == NULL) {
4345 		status = EROFS;
4346 		goto out;
4347 	}
4348 
4349 	status = FS_MOUNT_CALL(mount, create_index)(mount->cookie, name, type, flags);
4350 
4351 out:
4352 	put_mount(mount);
4353 	return status;
4354 }
4355 
4356 
4357 #if 0
4358 static status_t
4359 index_read_stat(struct file_descriptor *descriptor, struct stat *stat)
4360 {
4361 	struct vnode *vnode = descriptor->u.vnode;
4362 
4363 	// ToDo: currently unused!
4364 	FUNCTION(("index_read_stat: stat 0x%p\n", stat));
4365 	if (!FS_CALL(vnode, read_index_stat))
4366 		return EOPNOTSUPP;
4367 
4368 	return EOPNOTSUPP;
4369 	//return FS_CALL(vnode, read_index_stat)(vnode->mount->cookie, vnode->private_node, descriptor->cookie, stat);
4370 }
4371 
4372 
4373 static void
4374 index_free_fd(struct file_descriptor *descriptor)
4375 {
4376 	struct vnode *vnode = descriptor->u.vnode;
4377 
4378 	if (vnode != NULL) {
4379 		FS_CALL(vnode, free_index_cookie)(vnode->mount->cookie, vnode->private_node, descriptor->cookie);
4380 		put_vnode(vnode);
4381 	}
4382 }
4383 #endif
4384 
4385 
4386 static status_t
4387 index_name_read_stat(mount_id mountID, const char *name, struct stat *stat, bool kernel)
4388 {
4389 	struct fs_mount *mount;
4390 	status_t status;
4391 
4392 	FUNCTION(("index_remove(mountID = %ld, name = %s, kernel = %d)\n", mountID, name, kernel));
4393 
4394 	mount = get_mount(mountID);
4395 	if (mount == NULL)
4396 		return B_BAD_VALUE;
4397 
4398 	if (FS_MOUNT_CALL(mount, read_index_stat) == NULL) {
4399 		status = EOPNOTSUPP;
4400 		goto out;
4401 	}
4402 
4403 	status = FS_MOUNT_CALL(mount, read_index_stat)(mount->cookie, name, stat);
4404 
4405 out:
4406 	put_mount(mount);
4407 	return status;
4408 }
4409 
4410 
4411 static status_t
4412 index_remove(mount_id mountID, const char *name, bool kernel)
4413 {
4414 	struct fs_mount *mount;
4415 	status_t status;
4416 
4417 	FUNCTION(("index_remove(mountID = %ld, name = %s, kernel = %d)\n", mountID, name, kernel));
4418 
4419 	mount = get_mount(mountID);
4420 	if (mount == NULL)
4421 		return B_BAD_VALUE;
4422 
4423 	if (FS_MOUNT_CALL(mount, remove_index) == NULL) {
4424 		status = EROFS;
4425 		goto out;
4426 	}
4427 
4428 	status = FS_MOUNT_CALL(mount, remove_index)(mount->cookie, name);
4429 
4430 out:
4431 	put_mount(mount);
4432 	return status;
4433 }
4434 
4435 
4436 /**	ToDo: the query FS API is still the pretty much the same as in R5.
4437  *		It would be nice if the FS would find some more kernel support
4438  *		for them.
4439  *		For example, query parsing should be moved into the kernel.
4440  */
4441 
4442 static int
4443 query_open(dev_t device, const char *query, uint32 flags,
4444 	port_id port, int32 token, bool kernel)
4445 {
4446 	struct fs_mount *mount;
4447 	fs_cookie cookie;
4448 	status_t status;
4449 
4450 	FUNCTION(("query_open(device = %ld, query = \"%s\", kernel = %d)\n", device, query, kernel));
4451 
4452 	mount = get_mount(device);
4453 	if (mount == NULL)
4454 		return B_BAD_VALUE;
4455 
4456 	if (FS_MOUNT_CALL(mount, open_query) == NULL) {
4457 		status = EOPNOTSUPP;
4458 		goto out;
4459 	}
4460 
4461 	status = FS_MOUNT_CALL(mount, open_query)(mount->cookie, query, flags, port, token, &cookie);
4462 	if (status < B_OK)
4463 		goto out;
4464 
4465 	// get fd for the index directory
4466 	status = get_new_fd(FDTYPE_QUERY, mount, NULL, cookie, 0, kernel);
4467 	if (status >= 0)
4468 		goto out;
4469 
4470 	// something went wrong
4471 	FS_MOUNT_CALL(mount, close_query)(mount->cookie, cookie);
4472 	FS_MOUNT_CALL(mount, free_query_cookie)(mount->cookie, cookie);
4473 
4474 out:
4475 	put_mount(mount);
4476 	return status;
4477 }
4478 
4479 
4480 static status_t
4481 query_close(struct file_descriptor *descriptor)
4482 {
4483 	struct fs_mount *mount = descriptor->u.mount;
4484 
4485 	FUNCTION(("query_close(descriptor = %p)\n", descriptor));
4486 
4487 	if (FS_MOUNT_CALL(mount, close_query))
4488 		return FS_MOUNT_CALL(mount, close_query)(mount->cookie, descriptor->cookie);
4489 
4490 	return B_OK;
4491 }
4492 
4493 
4494 static void
4495 query_free_fd(struct file_descriptor *descriptor)
4496 {
4497 	struct fs_mount *mount = descriptor->u.mount;
4498 
4499 	if (mount != NULL) {
4500 		FS_MOUNT_CALL(mount, free_query_cookie)(mount->cookie, descriptor->cookie);
4501 		// ToDo: find a replacement ref_count object - perhaps the root dir?
4502 		//put_vnode(vnode);
4503 	}
4504 }
4505 
4506 
4507 static status_t
4508 query_read(struct file_descriptor *descriptor, struct dirent *buffer, size_t bufferSize, uint32 *_count)
4509 {
4510 	struct fs_mount *mount = descriptor->u.mount;
4511 
4512 	if (FS_MOUNT_CALL(mount, read_query))
4513 		return FS_MOUNT_CALL(mount, read_query)(mount->cookie, descriptor->cookie, buffer, bufferSize, _count);
4514 
4515 	return EOPNOTSUPP;
4516 }
4517 
4518 
4519 static status_t
4520 query_rewind(struct file_descriptor *descriptor)
4521 {
4522 	struct fs_mount *mount = descriptor->u.mount;
4523 
4524 	if (FS_MOUNT_CALL(mount, rewind_query))
4525 		return FS_MOUNT_CALL(mount, rewind_query)(mount->cookie, descriptor->cookie);
4526 
4527 	return EOPNOTSUPP;
4528 }
4529 
4530 
4531 //	#pragma mark -
4532 //	General File System functions
4533 
4534 
4535 static status_t
4536 fs_mount(char *path, const char *device, const char *fsName, uint32 flags,
4537 	const char *args, bool kernel)
4538 {
4539 	struct fs_mount *mount;
4540 	struct vnode *covered_vnode = NULL;
4541 	vnode_id root_id;
4542 	int err = 0;
4543 
4544 	FUNCTION(("fs_mount: entry. path = '%s', fs_name = '%s'\n", path, fsName));
4545 
4546 	// The path is always safe, we just have to make sure that fsName is
4547 	// almost valid - we can't make any assumptions about args, though.
4548 	// A NULL fsName is OK, if a device was given and the FS is not virtual.
4549 	// We'll get it from the DDM later.
4550 	if (fsName == NULL) {
4551 		if (!device || flags & B_MOUNT_VIRTUAL_DEVICE)
4552 			return B_BAD_VALUE;
4553 	} else if (fsName[0] == '\0')
4554 		return B_BAD_VALUE;
4555 
4556 	RecursiveLocker mountOpLocker(sMountOpLock);
4557 
4558 	// Helper to delete a newly created file device on failure.
4559 	// Not exactly beautiful, but helps to keep the code below cleaner.
4560 	struct FileDeviceDeleter {
4561 		FileDeviceDeleter() : id(-1) {}
4562 		~FileDeviceDeleter()
4563 		{
4564 			KDiskDeviceManager::Default()->DeleteFileDevice(id);
4565 		}
4566 
4567 		partition_id id;
4568 	} fileDeviceDeleter;
4569 
4570 	// If the file system is not a "virtual" one, the device argument should
4571 	// point to a real file/device (if given at all).
4572 	// get the partition
4573 	KDiskDeviceManager *ddm = KDiskDeviceManager::Default();
4574 	KPartition *partition = NULL;
4575 	bool newlyCreatedFileDevice = false;
4576 	if (!(flags & B_MOUNT_VIRTUAL_DEVICE) && device) {
4577 		// normalize the device path
4578 		KPath normalizedDevice;
4579 		err = normalizedDevice.SetTo(device, true);
4580 		if (err != B_OK)
4581 			return err;
4582 
4583 		// get a corresponding partition from the DDM
4584 		partition = ddm->RegisterPartition(normalizedDevice.Path(), true);
4585 
4586 		if (!partition) {
4587 			// Partition not found: This either means, the user supplied
4588 			// an invalid path, or the path refers to an image file. We try
4589 			// to let the DDM create a file device for the path.
4590 			partition_id deviceID = ddm->CreateFileDevice(
4591 				normalizedDevice.Path(), &newlyCreatedFileDevice);
4592 			if (deviceID >= 0) {
4593 				partition = ddm->RegisterPartition(deviceID, true);
4594 				if (newlyCreatedFileDevice)
4595 					fileDeviceDeleter.id = deviceID;
4596 // TODO: We must wait here, until the partition scan job is done.
4597 			}
4598 		}
4599 
4600 		if (!partition) {
4601 			PRINT(("fs_mount(): Partition `%s' not found.\n",
4602 				normalizedDevice.Path()));
4603 			return B_ENTRY_NOT_FOUND;
4604 		}
4605 	}
4606 	PartitionRegistrar partitionRegistrar(partition, true);
4607 
4608 	// Write lock the partition's device. For the time being, we keep the lock
4609 	// until we're done mounting -- not nice, but ensure, that no-one is
4610 	// interfering.
4611 	// TODO: Find a better solution.
4612 	KDiskDevice *diskDevice = NULL;
4613 	if (partition) {
4614 		diskDevice = ddm->WriteLockDevice(partition->Device()->ID());
4615 		if (!diskDevice) {
4616 			PRINT(("fs_mount(): Failed to lock disk device!\n"));
4617 			return B_ERROR;
4618 		}
4619 	}
4620 	DeviceWriteLocker writeLocker(diskDevice, true);
4621 
4622 	if (partition) {
4623 		// make sure, that the partition is not busy
4624 		if (partition->IsBusy() || partition->IsDescendantBusy()) {
4625 			PRINT(("fs_mount(): Partition is busy.\n"));
4626 			return B_BUSY;
4627 		}
4628 
4629 		// if no FS name had been supplied, we get it from the partition
4630 		if (!fsName) {
4631 			KDiskSystem *diskSystem = partition->DiskSystem();
4632 			if (!diskSystem) {
4633 				PRINT(("fs_mount(): No FS name was given, and the DDM didn't "
4634 					"recognize it.\n"));
4635 				return B_BAD_VALUE;
4636 			}
4637 
4638 			if (!diskSystem->IsFileSystem()) {
4639 				PRINT(("fs_mount(): No FS name was given, and the DDM found a "
4640 					"partitioning system.\n"));
4641 				return B_BAD_VALUE;
4642 			}
4643 
4644 			// The disk system name will not change, and the KDiskSystem
4645 			// object will not go away while the disk device is locked (and
4646 			// the partition has a reference to it), so this is safe.
4647 			fsName = diskSystem->Name();
4648 		}
4649 	}
4650 
4651 	mount = (struct fs_mount *)malloc(sizeof(struct fs_mount));
4652 	if (mount == NULL)
4653 		return B_NO_MEMORY;
4654 
4655 	list_init_etc(&mount->vnodes, offsetof(struct vnode, mount_link));
4656 
4657 	mount->fs_name = get_file_system_name(fsName);
4658 	if (mount->fs_name == NULL) {
4659 		err = B_NO_MEMORY;
4660 		goto err1;
4661 	}
4662 
4663 	mount->device_name = strdup(device);
4664 		// "device" can be NULL
4665 
4666 	mount->fs = get_file_system(fsName);
4667 	if (mount->fs == NULL) {
4668 		err = ENODEV;
4669 		goto err3;
4670 	}
4671 
4672 	err = recursive_lock_init(&mount->rlock, "mount rlock");
4673 	if (err < B_OK)
4674 		goto err4;
4675 
4676 	mount->id = sNextMountID++;
4677 	mount->partition = NULL;
4678 	mount->unmounting = false;
4679 	mount->owns_file_device = false;
4680 
4681 	mutex_lock(&sMountMutex);
4682 
4683 	// insert mount struct into list before we call fs mount()
4684 	hash_insert(sMountsTable, mount);
4685 
4686 	mutex_unlock(&sMountMutex);
4687 
4688 	if (!sRoot) {
4689 		// we haven't mounted anything yet
4690 		if (strcmp(path, "/") != 0) {
4691 			err = B_ERROR;
4692 			goto err5;
4693 		}
4694 
4695 		err = FS_MOUNT_CALL(mount, mount)(mount->id, device, flags, args, &mount->cookie, &root_id);
4696 		if (err < 0) {
4697 			// ToDo: why should we hide the error code from the file system here?
4698 			//err = ERR_VFS_GENERAL;
4699 			goto err5;
4700 		}
4701 
4702 		mount->covers_vnode = NULL; // this is the root mount
4703 	} else {
4704 		err = path_to_vnode(path, true, &covered_vnode, kernel);
4705 		if (err < 0)
4706 			goto err5;
4707 
4708 		if (!covered_vnode) {
4709 			err = B_ERROR;
4710 			goto err5;
4711 		}
4712 
4713 		// make sure covered_vnode is a DIR
4714 		struct stat coveredNodeStat;
4715 		err = FS_CALL(covered_vnode, read_stat)(covered_vnode->mount->cookie,
4716 			covered_vnode->private_node, &coveredNodeStat);
4717 		if (err < 0)
4718 			goto err5;
4719 
4720 		if (!S_ISDIR(coveredNodeStat.st_mode)) {
4721 			err = B_NOT_A_DIRECTORY;
4722 			goto err5;
4723 		}
4724 
4725 		if (covered_vnode->mount->root_vnode == covered_vnode) {
4726 			err = B_BUSY;
4727 			goto err5;
4728 		}
4729 
4730 		mount->covers_vnode = covered_vnode;
4731 
4732 		// mount it
4733 		err = FS_MOUNT_CALL(mount, mount)(mount->id, device, flags, args, &mount->cookie, &root_id);
4734 		if (err < 0)
4735 			goto err6;
4736 	}
4737 
4738 	err = get_vnode(mount->id, root_id, &mount->root_vnode, 0);
4739 	if (err < 0)
4740 		goto err7;
4741 
4742 	// No race here, since fs_mount() is the only function changing
4743 	// covers_vnode (and holds sMountOpLock at that time).
4744 	if (mount->covers_vnode)
4745 		mount->covers_vnode->covered_by = mount->root_vnode;
4746 
4747 	if (!sRoot)
4748 		sRoot = mount->root_vnode;
4749 
4750 	// supply the partition (if any) with the mount cookie and mark it mounted
4751 	if (partition) {
4752 		partition->SetMountCookie(mount->cookie);
4753 		partition->SetVolumeID(mount->id);
4754 
4755 		// keep a partition reference as long as the partition is mounted
4756 		partitionRegistrar.Detach();
4757 		mount->partition = partition;
4758 		mount->owns_file_device = newlyCreatedFileDevice;
4759 		fileDeviceDeleter.id = -1;
4760 	}
4761 
4762 	return B_OK;
4763 
4764 err7:
4765 	FS_MOUNT_CALL(mount, unmount)(mount->cookie);
4766 err6:
4767 	if (mount->covers_vnode)
4768 		put_vnode(mount->covers_vnode);
4769 err5:
4770 	mutex_lock(&sMountMutex);
4771 	hash_remove(sMountsTable, mount);
4772 	mutex_unlock(&sMountMutex);
4773 
4774 	recursive_lock_destroy(&mount->rlock);
4775 err4:
4776 	put_file_system(mount->fs);
4777 	free(mount->device_name);
4778 err3:
4779 	free(mount->fs_name);
4780 err1:
4781 	free(mount);
4782 
4783 	return err;
4784 }
4785 
4786 
4787 static status_t
4788 fs_unmount(char *path, uint32 flags, bool kernel)
4789 {
4790 	struct fs_mount *mount;
4791 	struct vnode *vnode;
4792 	status_t err;
4793 
4794 	FUNCTION(("vfs_unmount: entry. path = '%s', kernel %d\n", path, kernel));
4795 
4796 	err = path_to_vnode(path, true, &vnode, kernel);
4797 	if (err < 0)
4798 		return B_ENTRY_NOT_FOUND;
4799 
4800 	RecursiveLocker mountOpLocker(sMountOpLock);
4801 
4802 	mount = find_mount(vnode->device);
4803 	if (!mount)
4804 		panic("vfs_unmount: find_mount() failed on root vnode @%p of mount\n", vnode);
4805 
4806 	if (mount->root_vnode != vnode) {
4807 		// not mountpoint
4808 		put_vnode(vnode);
4809 		return B_BAD_VALUE;
4810 	}
4811 
4812 	// if the volume is associated with a partition, lock the device of the
4813 	// partition as long as we are unmounting
4814 	KDiskDeviceManager* ddm = KDiskDeviceManager::Default();
4815 	KPartition *partition = mount->partition;
4816 	KDiskDevice *diskDevice = NULL;
4817 	if (partition) {
4818 		diskDevice = ddm->WriteLockDevice(partition->Device()->ID());
4819 		if (!diskDevice) {
4820 			PRINT(("fs_unmount(): Failed to lock disk device!\n"));
4821 			return B_ERROR;
4822 		}
4823 	}
4824 	DeviceWriteLocker writeLocker(diskDevice, true);
4825 
4826 	// make sure, that the partition is not busy
4827 	if (partition) {
4828 		if (partition->IsBusy() || partition->IsDescendantBusy()) {
4829 			PRINT(("fs_unmount(): Partition is busy.\n"));
4830 			return B_BUSY;
4831 		}
4832 	}
4833 
4834 	// grab the vnode master mutex to keep someone from creating
4835 	// a vnode while we're figuring out if we can continue
4836 	mutex_lock(&sVnodeMutex);
4837 
4838 	// simplify the loop below: we decrement the root vnode ref_count
4839 	// by the known number of references: one for the fs_mount, one
4840 	// from the path_to_vnode() call above
4841 	mount->root_vnode->ref_count -= 2;
4842 
4843 	// cycle through the list of vnodes associated with this mount and
4844 	// make sure all of them are not busy or have refs on them
4845 	vnode = NULL;
4846 	while ((vnode = (struct vnode *)list_get_next_item(&mount->vnodes, vnode)) != NULL) {
4847 		if (vnode->busy || vnode->ref_count != 0) {
4848 			// there are still vnodes in use on this mount, so we cannot unmount yet
4849 			// ToDo: cut read/write access file descriptors, depending on the B_FORCE_UNMOUNT flag
4850 			mount->root_vnode->ref_count += 2;
4851 			mutex_unlock(&sVnodeMutex);
4852 			put_vnode(mount->root_vnode);
4853 
4854 			return B_BUSY;
4855 		}
4856 	}
4857 
4858 	// we can safely continue, mark all of the vnodes busy and this mount
4859 	// structure in unmounting state
4860 	mount->unmounting = true;
4861 
4862 	while ((vnode = (struct vnode *)list_get_next_item(&mount->vnodes, vnode)) != NULL) {
4863 		vnode->busy = true;
4864 		hash_remove(sVnodeTable, vnode);
4865 	}
4866 
4867 	mutex_unlock(&sVnodeMutex);
4868 
4869 	mount->covers_vnode->covered_by = NULL;
4870 	put_vnode(mount->covers_vnode);
4871 
4872 	// Free all vnodes associated with this mount.
4873 	// They will be removed from the mount list by free_vnode(), so
4874 	// we don't have to do this.
4875 	while ((vnode = (struct vnode *)list_get_next_item(&mount->vnodes, NULL)) != NULL) {
4876 		free_vnode(vnode, false);
4877 	}
4878 
4879 	// remove the mount structure from the hash table
4880 	mutex_lock(&sMountMutex);
4881 	hash_remove(sMountsTable, mount);
4882 	mutex_unlock(&sMountMutex);
4883 
4884 	mountOpLocker.Unlock();
4885 
4886 	FS_MOUNT_CALL(mount, unmount)(mount->cookie);
4887 
4888 	// release the file system
4889 	put_file_system(mount->fs);
4890 
4891 	// dereference the partition
4892 	if (partition) {
4893 		if (mount->owns_file_device)
4894 			KDiskDeviceManager::Default()->DeleteFileDevice(partition->ID());
4895 		partition->Unregister();
4896 	}
4897 
4898 	free(mount->device_name);
4899 	free(mount->fs_name);
4900 	free(mount);
4901 
4902 	return B_OK;
4903 }
4904 
4905 
4906 static status_t
4907 fs_sync(dev_t device)
4908 {
4909 	struct fs_mount *mount;
4910 
4911 	mount = get_mount(device);
4912 	if (mount == NULL)
4913 		return B_BAD_VALUE;
4914 
4915 	mutex_lock(&sMountMutex);
4916 
4917 	status_t status = B_OK;
4918 	if (FS_MOUNT_CALL(mount, sync))
4919 		status = FS_MOUNT_CALL(mount, sync)(mount->cookie);
4920 
4921 	mutex_unlock(&sMountMutex);
4922 
4923 	// synchronize all vnodes
4924 	recursive_lock_lock(&mount->rlock);
4925 
4926 	struct vnode *vnode = NULL;
4927 	while ((vnode = (struct vnode *)list_get_next_item(&mount->vnodes, vnode)) != NULL) {
4928 		if (vnode->cache)
4929 			vm_cache_write_modified(vnode->cache);
4930 	}
4931 
4932 	recursive_lock_unlock(&mount->rlock);
4933 	put_mount(mount);
4934 	return status;
4935 }
4936 
4937 
4938 static status_t
4939 fs_read_info(dev_t device, struct fs_info *info)
4940 {
4941 	struct fs_mount *mount;
4942 	status_t status = B_OK;
4943 
4944 	mount = get_mount(device);
4945 	if (mount == NULL)
4946 		return B_BAD_VALUE;
4947 
4948 	// fill in info the file system doesn't (have to) know about
4949 	memset(info, 0, sizeof(struct fs_info));
4950 	info->dev = mount->id;
4951 	info->root = mount->root_vnode->id;
4952 	strlcpy(info->fsh_name, mount->fs_name, sizeof(info->fsh_name));
4953 	if (mount->device_name != NULL)
4954 		strlcpy(info->device_name, mount->device_name, sizeof(info->device_name));
4955 
4956 	if (FS_MOUNT_CALL(mount, read_fs_info))
4957 		status = FS_MOUNT_CALL(mount, read_fs_info)(mount->cookie, info);
4958 
4959 	// if the call is not supported by the file system, there are still
4960 	// the parts that we filled out ourselves
4961 
4962 	put_mount(mount);
4963 	return status;
4964 }
4965 
4966 
4967 static status_t
4968 fs_write_info(dev_t device, const struct fs_info *info, int mask)
4969 {
4970 	struct fs_mount *mount;
4971 	status_t status;
4972 
4973 	mount = get_mount(device);
4974 	if (mount == NULL)
4975 		return B_BAD_VALUE;
4976 
4977 	if (FS_MOUNT_CALL(mount, write_fs_info))
4978 		status = FS_MOUNT_CALL(mount, write_fs_info)(mount->cookie, info, mask);
4979 	else
4980 		status = EROFS;
4981 
4982 	put_mount(mount);
4983 	return status;
4984 }
4985 
4986 
4987 static dev_t
4988 fs_next_device(int32 *_cookie)
4989 {
4990 	struct fs_mount *mount = NULL;
4991 	dev_t device = *_cookie;
4992 
4993 	mutex_lock(&sMountMutex);
4994 
4995 	// Since device IDs are assigned sequentially, this algorithm
4996 	// does work good enough. It makes sure that the device list
4997 	// returned is sorted, and that no device is skipped when an
4998 	// already visited device got unmounted.
4999 
5000 	while (device < sNextMountID) {
5001 		mount = find_mount(device++);
5002 		if (mount != NULL)
5003 			break;
5004 	}
5005 
5006 	*_cookie = device;
5007 
5008 	if (mount != NULL)
5009 		device = mount->id;
5010 	else
5011 		device = B_BAD_VALUE;
5012 
5013 	mutex_unlock(&sMountMutex);
5014 
5015 	return device;
5016 }
5017 
5018 
5019 static status_t
5020 get_cwd(char *buffer, size_t size, bool kernel)
5021 {
5022 	// Get current working directory from io context
5023 	struct io_context *context = get_current_io_context(kernel);
5024 	int status;
5025 
5026 	FUNCTION(("vfs_get_cwd: buf %p, size %ld\n", buffer, size));
5027 
5028 	mutex_lock(&context->io_mutex);
5029 
5030 	if (context->cwd)
5031 		status = dir_vnode_to_path(context->cwd, buffer, size);
5032 	else
5033 		status = B_ERROR;
5034 
5035 	mutex_unlock(&context->io_mutex);
5036 	return status;
5037 }
5038 
5039 
5040 static status_t
5041 set_cwd(int fd, char *path, bool kernel)
5042 {
5043 	struct io_context *context;
5044 	struct vnode *vnode = NULL;
5045 	struct vnode *oldDirectory;
5046 	struct stat stat;
5047 	int rc;
5048 
5049 	FUNCTION(("set_cwd: path = \'%s\'\n", path));
5050 
5051 	// Get vnode for passed path, and bail if it failed
5052 	rc = fd_and_path_to_vnode(fd, path, true, &vnode, kernel);
5053 	if (rc < 0)
5054 		return rc;
5055 
5056 	rc = FS_CALL(vnode, read_stat)(vnode->mount->cookie, vnode->private_node, &stat);
5057 	if (rc < 0)
5058 		goto err;
5059 
5060 	if (!S_ISDIR(stat.st_mode)) {
5061 		// nope, can't cwd to here
5062 		rc = B_NOT_A_DIRECTORY;
5063 		goto err;
5064 	}
5065 
5066 	// Get current io context and lock
5067 	context = get_current_io_context(kernel);
5068 	mutex_lock(&context->io_mutex);
5069 
5070 	// save the old current working directory first
5071 	oldDirectory = context->cwd;
5072 	context->cwd = vnode;
5073 
5074 	mutex_unlock(&context->io_mutex);
5075 
5076 	if (oldDirectory)
5077 		put_vnode(oldDirectory);
5078 
5079 	return B_NO_ERROR;
5080 
5081 err:
5082 	put_vnode(vnode);
5083 	return rc;
5084 }
5085 
5086 
5087 //	#pragma mark -
5088 //	Calls from within the kernel
5089 
5090 
5091 status_t
5092 _kern_mount(const char *path, const char *device, const char *fsName,
5093 	uint32 flags, const char *args)
5094 {
5095 	KPath pathBuffer(path, false, B_PATH_NAME_LENGTH + 1);
5096 	if (pathBuffer.InitCheck() != B_OK)
5097 		return B_NO_MEMORY;
5098 
5099 	return fs_mount(pathBuffer.LockBuffer(), device, fsName, flags, args, true);
5100 }
5101 
5102 
5103 status_t
5104 _kern_unmount(const char *path, uint32 flags)
5105 {
5106 	KPath pathBuffer(path, false, B_PATH_NAME_LENGTH + 1);
5107 	if (pathBuffer.InitCheck() != B_OK)
5108 		return B_NO_MEMORY;
5109 
5110 	return fs_unmount(pathBuffer.LockBuffer(), flags, true);
5111 }
5112 
5113 
5114 status_t
5115 _kern_read_fs_info(dev_t device, struct fs_info *info)
5116 {
5117 	if (info == NULL)
5118 		return B_BAD_VALUE;
5119 
5120 	return fs_read_info(device, info);
5121 }
5122 
5123 
5124 status_t
5125 _kern_write_fs_info(dev_t device, const struct fs_info *info, int mask)
5126 {
5127 	if (info == NULL)
5128 		return B_BAD_VALUE;
5129 
5130 	return fs_write_info(device, info, mask);
5131 }
5132 
5133 
5134 status_t
5135 _kern_sync(void)
5136 {
5137 	// Note: _kern_sync() is also called from _user_sync()
5138 	int32 cookie = 0;
5139 	dev_t device;
5140 	while ((device = next_dev(&cookie)) >= 0) {
5141 		status_t status = fs_sync(device);
5142 		if (status != B_OK && status != B_BAD_VALUE)
5143 			dprintf("sync: device %ld couldn't sync: %s\n", device, strerror(status));
5144 	}
5145 
5146 	return B_OK;
5147 }
5148 
5149 
5150 dev_t
5151 _kern_next_device(int32 *_cookie)
5152 {
5153 	return fs_next_device(_cookie);
5154 }
5155 
5156 
5157 int
5158 _kern_open_entry_ref(dev_t device, ino_t inode, const char *name, int openMode, int perms)
5159 {
5160 	if (openMode & O_CREAT)
5161 		return file_create_entry_ref(device, inode, name, openMode, perms, true);
5162 
5163 	return file_open_entry_ref(device, inode, name, openMode, true);
5164 }
5165 
5166 
5167 /**	\brief Opens a node specified by a FD + path pair.
5168  *
5169  *	At least one of \a fd and \a path must be specified.
5170  *	If only \a fd is given, the function opens the node identified by this
5171  *	FD. If only a path is given, this path is opened. If both are given and
5172  *	the path is absolute, \a fd is ignored; a relative path is reckoned off
5173  *	of the directory (!) identified by \a fd.
5174  *
5175  *	\param fd The FD. May be < 0.
5176  *	\param path The absolute or relative path. May be \c NULL.
5177  *	\param openMode The open mode.
5178  *	\return A FD referring to the newly opened node, or an error code,
5179  *			if an error occurs.
5180  */
5181 
5182 int
5183 _kern_open(int fd, const char *path, int openMode, int perms)
5184 {
5185 	KPath pathBuffer(path, false, B_PATH_NAME_LENGTH + 1);
5186 	if (pathBuffer.InitCheck() != B_OK)
5187 		return B_NO_MEMORY;
5188 
5189 	if (openMode & O_CREAT)
5190 		return file_create(fd, pathBuffer.LockBuffer(), openMode, perms, true);
5191 
5192 	return file_open(fd, pathBuffer.LockBuffer(), openMode, true);
5193 }
5194 
5195 
5196 /**	\brief Opens a directory specified by entry_ref or node_ref.
5197  *
5198  *	The supplied name may be \c NULL, in which case directory identified
5199  *	by \a device and \a inode will be opened. Otherwise \a device and
5200  *	\a inode identify the parent directory of the directory to be opened
5201  *	and \a name its entry name.
5202  *
5203  *	\param device If \a name is specified the ID of the device the parent
5204  *		   directory of the directory to be opened resides on, otherwise
5205  *		   the device of the directory itself.
5206  *	\param inode If \a name is specified the node ID of the parent
5207  *		   directory of the directory to be opened, otherwise node ID of the
5208  *		   directory itself.
5209  *	\param name The entry name of the directory to be opened. If \c NULL,
5210  *		   the \a device + \a inode pair identify the node to be opened.
5211  *	\return The FD of the newly opened directory or an error code, if
5212  *			something went wrong.
5213  */
5214 
5215 int
5216 _kern_open_dir_entry_ref(dev_t device, ino_t inode, const char *name)
5217 {
5218 	return dir_open_entry_ref(device, inode, name, true);
5219 }
5220 
5221 
5222 /**	\brief Opens a directory specified by a FD + path pair.
5223  *
5224  *	At least one of \a fd and \a path must be specified.
5225  *	If only \a fd is given, the function opens the directory identified by this
5226  *	FD. If only a path is given, this path is opened. If both are given and
5227  *	the path is absolute, \a fd is ignored; a relative path is reckoned off
5228  *	of the directory (!) identified by \a fd.
5229  *
5230  *	\param fd The FD. May be < 0.
5231  *	\param path The absolute or relative path. May be \c NULL.
5232  *	\return A FD referring to the newly opened directory, or an error code,
5233  *			if an error occurs.
5234  */
5235 
5236 int
5237 _kern_open_dir(int fd, const char *path)
5238 {
5239 	KPath pathBuffer(path, false, B_PATH_NAME_LENGTH + 1);
5240 	if (pathBuffer.InitCheck() != B_OK)
5241 		return B_NO_MEMORY;
5242 
5243 	return dir_open(fd, pathBuffer.LockBuffer(), true);
5244 }
5245 
5246 
5247 status_t
5248 _kern_fcntl(int fd, int op, uint32 argument)
5249 {
5250 	return common_fcntl(fd, op, argument, true);
5251 }
5252 
5253 
5254 status_t
5255 _kern_fsync(int fd)
5256 {
5257 	return common_sync(fd, true);
5258 }
5259 
5260 
5261 status_t
5262 _kern_lock_node(int fd)
5263 {
5264 	return common_lock_node(fd, true);
5265 }
5266 
5267 
5268 status_t
5269 _kern_unlock_node(int fd)
5270 {
5271 	return common_unlock_node(fd, true);
5272 }
5273 
5274 
5275 status_t
5276 _kern_create_dir_entry_ref(dev_t device, ino_t inode, const char *name, int perms)
5277 {
5278 	return dir_create_entry_ref(device, inode, name, perms, true);
5279 }
5280 
5281 
5282 /**	\brief Creates a directory specified by a FD + path pair.
5283  *
5284  *	\a path must always be specified (it contains the name of the new directory
5285  *	at least). If only a path is given, this path identifies the location at
5286  *	which the directory shall be created. If both \a fd and \a path are given and
5287  *	the path is absolute, \a fd is ignored; a relative path is reckoned off
5288  *	of the directory (!) identified by \a fd.
5289  *
5290  *	\param fd The FD. May be < 0.
5291  *	\param path The absolute or relative path. Must not be \c NULL.
5292  *	\param perms The access permissions the new directory shall have.
5293  *	\return \c B_OK, if the directory has been created successfully, another
5294  *			error code otherwise.
5295  */
5296 
5297 status_t
5298 _kern_create_dir(int fd, const char *path, int perms)
5299 {
5300 	KPath pathBuffer(path, false, B_PATH_NAME_LENGTH + 1);
5301 	if (pathBuffer.InitCheck() != B_OK)
5302 		return B_NO_MEMORY;
5303 
5304 	return dir_create(fd, pathBuffer.LockBuffer(), perms, true);
5305 }
5306 
5307 
5308 status_t
5309 _kern_remove_dir(const char *path)
5310 {
5311 	KPath pathBuffer(path, false, B_PATH_NAME_LENGTH + 1);
5312 	if (pathBuffer.InitCheck() != B_OK)
5313 		return B_NO_MEMORY;
5314 
5315 	return dir_remove(pathBuffer.LockBuffer(), true);
5316 }
5317 
5318 
5319 /**	\brief Reads the contents of a symlink referred to by a FD + path pair.
5320  *
5321  *	At least one of \a fd and \a path must be specified.
5322  *	If only \a fd is given, the function the symlink to be read is the node
5323  *	identified by this FD. If only a path is given, this path identifies the
5324  *	symlink to be read. If both are given and the path is absolute, \a fd is
5325  *	ignored; a relative path is reckoned off of the directory (!) identified
5326  *	by \a fd.
5327  *	If this function fails with B_BUFFER_OVERFLOW, the \a _bufferSize pointer
5328  *	will still be updated to reflect the required buffer size.
5329  *
5330  *	\param fd The FD. May be < 0.
5331  *	\param path The absolute or relative path. May be \c NULL.
5332  *	\param buffer The buffer into which the contents of the symlink shall be
5333  *		   written.
5334  *	\param _bufferSize A pointer to the size of the supplied buffer.
5335  *	\return The length of the link on success or an appropriate error code
5336  */
5337 
5338 status_t
5339 _kern_read_link(int fd, const char *path, char *buffer, size_t *_bufferSize)
5340 {
5341 	status_t status;
5342 
5343 	if (path) {
5344 		KPath pathBuffer(path, false, B_PATH_NAME_LENGTH + 1);
5345 		if (pathBuffer.InitCheck() != B_OK)
5346 			return B_NO_MEMORY;
5347 
5348 		return common_read_link(fd, pathBuffer.LockBuffer(),
5349 			buffer, _bufferSize, true);
5350 	}
5351 
5352 	return common_read_link(fd, NULL, buffer, _bufferSize, true);
5353 }
5354 
5355 
5356 status_t
5357 _kern_write_link(const char *path, const char *toPath)
5358 {
5359 	KPath pathBuffer(path, false, B_PATH_NAME_LENGTH + 1);
5360 	KPath toPathBuffer(toPath, false, B_PATH_NAME_LENGTH + 1);
5361 	if (pathBuffer.InitCheck() != B_OK || toPathBuffer.InitCheck() != B_OK)
5362 		return B_NO_MEMORY;
5363 
5364 	char *toBuffer = toPathBuffer.LockBuffer();
5365 
5366 	status_t status = check_path(toBuffer);
5367 	if (status < B_OK)
5368 		return status;
5369 
5370 	return common_write_link(pathBuffer.LockBuffer(), toBuffer, true);
5371 }
5372 
5373 
5374 /**	\brief Creates a symlink specified by a FD + path pair.
5375  *
5376  *	\a path must always be specified (it contains the name of the new symlink
5377  *	at least). If only a path is given, this path identifies the location at
5378  *	which the symlink shall be created. If both \a fd and \a path are given and
5379  *	the path is absolute, \a fd is ignored; a relative path is reckoned off
5380  *	of the directory (!) identified by \a fd.
5381  *
5382  *	\param fd The FD. May be < 0.
5383  *	\param toPath The absolute or relative path. Must not be \c NULL.
5384  *	\param mode The access permissions the new symlink shall have.
5385  *	\return \c B_OK, if the symlink has been created successfully, another
5386  *			error code otherwise.
5387  */
5388 
5389 status_t
5390 _kern_create_symlink(int fd, const char *path, const char *toPath, int mode)
5391 {
5392 	KPath pathBuffer(path, false, B_PATH_NAME_LENGTH + 1);
5393 	KPath toPathBuffer(toPath, false, B_PATH_NAME_LENGTH + 1);
5394 	if (pathBuffer.InitCheck() != B_OK || toPathBuffer.InitCheck() != B_OK)
5395 		return B_NO_MEMORY;
5396 
5397 	char *toBuffer = toPathBuffer.LockBuffer();
5398 
5399 	status_t status = check_path(toBuffer);
5400 	if (status < B_OK)
5401 		return status;
5402 
5403 	return common_create_symlink(fd, pathBuffer.LockBuffer(),
5404 		toBuffer, mode, true);
5405 }
5406 
5407 
5408 status_t
5409 _kern_create_link(const char *path, const char *toPath)
5410 {
5411 	KPath pathBuffer(path, false, B_PATH_NAME_LENGTH + 1);
5412 	KPath toPathBuffer(toPath, false, B_PATH_NAME_LENGTH + 1);
5413 	if (pathBuffer.InitCheck() != B_OK || toPathBuffer.InitCheck() != B_OK)
5414 		return B_NO_MEMORY;
5415 
5416 	return common_create_link(pathBuffer.LockBuffer(),
5417 		toPathBuffer.LockBuffer(), true);
5418 }
5419 
5420 
5421 /**	\brief Removes an entry specified by a FD + path pair from its directory.
5422  *
5423  *	\a path must always be specified (it contains at least the name of the entry
5424  *	to be deleted). If only a path is given, this path identifies the entry
5425  *	directly. If both \a fd and \a path are given and the path is absolute,
5426  *	\a fd is ignored; a relative path is reckoned off of the directory (!)
5427  *	identified by \a fd.
5428  *
5429  *	\param fd The FD. May be < 0.
5430  *	\param path The absolute or relative path. Must not be \c NULL.
5431  *	\return \c B_OK, if the entry has been removed successfully, another
5432  *			error code otherwise.
5433  */
5434 
5435 status_t
5436 _kern_unlink(int fd, const char *path)
5437 {
5438 	KPath pathBuffer(path, false, B_PATH_NAME_LENGTH + 1);
5439 	if (pathBuffer.InitCheck() != B_OK)
5440 		return B_NO_MEMORY;
5441 
5442 	return common_unlink(fd, pathBuffer.LockBuffer(), true);
5443 }
5444 
5445 
5446 /**	\brief Moves an entry specified by a FD + path pair to a an entry specified
5447  *		   by another FD + path pair.
5448  *
5449  *	\a oldPath and \a newPath must always be specified (they contain at least
5450  *	the name of the entry). If only a path is given, this path identifies the
5451  *	entry directly. If both a FD and a path are given and the path is absolute,
5452  *	the FD is ignored; a relative path is reckoned off of the directory (!)
5453  *	identified by the respective FD.
5454  *
5455  *	\param oldFD The FD of the old location. May be < 0.
5456  *	\param oldPath The absolute or relative path of the old location. Must not
5457  *		   be \c NULL.
5458  *	\param newFD The FD of the new location. May be < 0.
5459  *	\param newPath The absolute or relative path of the new location. Must not
5460  *		   be \c NULL.
5461  *	\return \c B_OK, if the entry has been moved successfully, another
5462  *			error code otherwise.
5463  */
5464 
5465 status_t
5466 _kern_rename(int oldFD, const char *oldPath, int newFD, const char *newPath)
5467 {
5468 	KPath oldPathBuffer(oldPath, false, B_PATH_NAME_LENGTH + 1);
5469 	KPath newPathBuffer(newPath, false, B_PATH_NAME_LENGTH + 1);
5470 	if (oldPathBuffer.InitCheck() != B_OK || newPathBuffer.InitCheck() != B_OK)
5471 		return B_NO_MEMORY;
5472 
5473 	return common_rename(oldFD, oldPathBuffer.LockBuffer(),
5474 		newFD, newPathBuffer.LockBuffer(), true);
5475 }
5476 
5477 
5478 status_t
5479 _kern_access(const char *path, int mode)
5480 {
5481 	KPath pathBuffer(path, false, B_PATH_NAME_LENGTH + 1);
5482 	if (pathBuffer.InitCheck() != B_OK)
5483 		return B_NO_MEMORY;
5484 
5485 	return common_access(pathBuffer.LockBuffer(), mode, true);
5486 }
5487 
5488 
5489 /**	\brief Reads stat data of an entity specified by a FD + path pair.
5490  *
5491  *	If only \a fd is given, the stat operation associated with the type
5492  *	of the FD (node, attr, attr dir etc.) is performed. If only \a path is
5493  *	given, this path identifies the entry for whose node to retrieve the
5494  *	stat data. If both \a fd and \a path are given and the path is absolute,
5495  *	\a fd is ignored; a relative path is reckoned off of the directory (!)
5496  *	identified by \a fd and specifies the entry whose stat data shall be
5497  *	retrieved.
5498  *
5499  *	\param fd The FD. May be < 0.
5500  *	\param path The absolute or relative path. Must not be \c NULL.
5501  *	\param traverseLeafLink If \a path is given, \c true specifies that the
5502  *		   function shall not stick to symlinks, but traverse them.
5503  *	\param stat The buffer the stat data shall be written into.
5504  *	\param statSize The size of the supplied stat buffer.
5505  *	\return \c B_OK, if the the stat data have been read successfully, another
5506  *			error code otherwise.
5507  */
5508 
5509 status_t
5510 _kern_read_stat(int fd, const char *path, bool traverseLeafLink,
5511 	struct stat *stat, size_t statSize)
5512 {
5513 	struct stat completeStat;
5514 	struct stat *originalStat = NULL;
5515 	status_t status;
5516 
5517 	if (statSize > sizeof(struct stat))
5518 		return B_BAD_VALUE;
5519 
5520 	// this supports different stat extensions
5521 	if (statSize < sizeof(struct stat)) {
5522 		originalStat = stat;
5523 		stat = &completeStat;
5524 	}
5525 
5526 	if (path) {
5527 		// path given: get the stat of the node referred to by (fd, path)
5528 		KPath pathBuffer(path, false, B_PATH_NAME_LENGTH + 1);
5529 		if (pathBuffer.InitCheck() != B_OK)
5530 			return B_NO_MEMORY;
5531 
5532 		status = common_path_read_stat(fd, pathBuffer.LockBuffer(),
5533 			traverseLeafLink, stat, true);
5534 	} else {
5535 		// no path given: get the FD and use the FD operation
5536 		struct file_descriptor *descriptor
5537 			= get_fd(get_current_io_context(true), fd);
5538 		if (descriptor == NULL)
5539 			return B_FILE_ERROR;
5540 
5541 		if (descriptor->ops->fd_read_stat)
5542 			status = descriptor->ops->fd_read_stat(descriptor, stat);
5543 		else
5544 			status = EOPNOTSUPP;
5545 
5546 		put_fd(descriptor);
5547 	}
5548 
5549 	if (status == B_OK && originalStat != NULL)
5550 		memcpy(originalStat, stat, statSize);
5551 
5552 	return status;
5553 }
5554 
5555 
5556 /**	\brief Writes stat data of an entity specified by a FD + path pair.
5557  *
5558  *	If only \a fd is given, the stat operation associated with the type
5559  *	of the FD (node, attr, attr dir etc.) is performed. If only \a path is
5560  *	given, this path identifies the entry for whose node to write the
5561  *	stat data. If both \a fd and \a path are given and the path is absolute,
5562  *	\a fd is ignored; a relative path is reckoned off of the directory (!)
5563  *	identified by \a fd and specifies the entry whose stat data shall be
5564  *	written.
5565  *
5566  *	\param fd The FD. May be < 0.
5567  *	\param path The absolute or relative path. Must not be \c NULL.
5568  *	\param traverseLeafLink If \a path is given, \c true specifies that the
5569  *		   function shall not stick to symlinks, but traverse them.
5570  *	\param stat The buffer containing the stat data to be written.
5571  *	\param statSize The size of the supplied stat buffer.
5572  *	\param statMask A mask specifying which parts of the stat data shall be
5573  *		   written.
5574  *	\return \c B_OK, if the the stat data have been written successfully,
5575  *			another error code otherwise.
5576  */
5577 
5578 status_t
5579 _kern_write_stat(int fd, const char *path, bool traverseLeafLink,
5580 	const struct stat *stat, size_t statSize, int statMask)
5581 {
5582 	struct stat completeStat;
5583 
5584 	if (statSize > sizeof(struct stat))
5585 		return B_BAD_VALUE;
5586 
5587 	// this supports different stat extensions
5588 	if (statSize < sizeof(struct stat)) {
5589 		memset((uint8 *)&completeStat + statSize, 0, sizeof(struct stat) - statSize);
5590 		memcpy(&completeStat, stat, statSize);
5591 		stat = &completeStat;
5592 	}
5593 
5594 	status_t status;
5595 
5596 	if (path) {
5597 		// path given: write the stat of the node referred to by (fd, path)
5598 		KPath pathBuffer(path, false, B_PATH_NAME_LENGTH + 1);
5599 		if (pathBuffer.InitCheck() != B_OK)
5600 			return B_NO_MEMORY;
5601 
5602 		status = common_path_write_stat(fd, pathBuffer.LockBuffer(),
5603 			traverseLeafLink, stat, statMask, true);
5604 	} else {
5605 		// no path given: get the FD and use the FD operation
5606 		struct file_descriptor *descriptor
5607 			= get_fd(get_current_io_context(true), fd);
5608 		if (descriptor == NULL)
5609 			return B_FILE_ERROR;
5610 
5611 		if (descriptor->ops->fd_write_stat)
5612 			status = descriptor->ops->fd_write_stat(descriptor, stat, statMask);
5613 		else
5614 			status = EOPNOTSUPP;
5615 
5616 		put_fd(descriptor);
5617 	}
5618 
5619 	return status;
5620 }
5621 
5622 
5623 int
5624 _kern_open_attr_dir(int fd, const char *path)
5625 {
5626 	KPath pathBuffer(B_PATH_NAME_LENGTH + 1);
5627 	if (pathBuffer.InitCheck() != B_OK)
5628 		return B_NO_MEMORY;
5629 
5630 	if (path != NULL)
5631 		pathBuffer.SetTo(path);
5632 
5633 	return attr_dir_open(fd, path ? pathBuffer.LockBuffer() : NULL, true);
5634 }
5635 
5636 
5637 int
5638 _kern_create_attr(int fd, const char *name, uint32 type, int openMode)
5639 {
5640 	return attr_create(fd, name, type, openMode, true);
5641 }
5642 
5643 
5644 int
5645 _kern_open_attr(int fd, const char *name, int openMode)
5646 {
5647 	return attr_open(fd, name, openMode, true);
5648 }
5649 
5650 
5651 status_t
5652 _kern_remove_attr(int fd, const char *name)
5653 {
5654 	return attr_remove(fd, name, true);
5655 }
5656 
5657 
5658 status_t
5659 _kern_rename_attr(int fromFile, const char *fromName, int toFile, const char *toName)
5660 {
5661 	return attr_rename(fromFile, fromName, toFile, toName, true);
5662 }
5663 
5664 
5665 int
5666 _kern_open_index_dir(dev_t device)
5667 {
5668 	return index_dir_open(device, true);
5669 }
5670 
5671 
5672 status_t
5673 _kern_create_index(dev_t device, const char *name, uint32 type, uint32 flags)
5674 {
5675 	return index_create(device, name, type, flags, true);
5676 }
5677 
5678 
5679 status_t
5680 _kern_read_index_stat(dev_t device, const char *name, struct stat *stat)
5681 {
5682 	return index_name_read_stat(device, name, stat, true);
5683 }
5684 
5685 
5686 status_t
5687 _kern_remove_index(dev_t device, const char *name)
5688 {
5689 	return index_remove(device, name, true);
5690 }
5691 
5692 
5693 status_t
5694 _kern_getcwd(char *buffer, size_t size)
5695 {
5696 	PRINT(("_kern_getcwd: buf %p, %ld\n", buffer, size));
5697 
5698 	// Call vfs to get current working directory
5699 	return get_cwd(buffer, size, true);
5700 }
5701 
5702 
5703 status_t
5704 _kern_setcwd(int fd, const char *path)
5705 {
5706 	KPath pathBuffer(B_PATH_NAME_LENGTH + 1);
5707 	if (pathBuffer.InitCheck() != B_OK)
5708 		return B_NO_MEMORY;
5709 
5710 	if (path != NULL)
5711 		pathBuffer.SetTo(path);
5712 
5713 	return set_cwd(fd, path != NULL ? pathBuffer.LockBuffer() : NULL, true);
5714 }
5715 
5716 
5717 //	#pragma mark -
5718 //	Calls from userland (with extra address checks)
5719 
5720 
5721 status_t
5722 _user_mount(const char *userPath, const char *userDevice, const char *userFileSystem,
5723 	uint32 flags, const char *userArgs)
5724 {
5725 	char fileSystem[B_OS_NAME_LENGTH];
5726 	KPath path, device;
5727 	char *args = NULL;
5728 	status_t status;
5729 
5730 	if (!IS_USER_ADDRESS(userPath)
5731 		|| !IS_USER_ADDRESS(userFileSystem)
5732 		|| !IS_USER_ADDRESS(userDevice))
5733 		return B_BAD_ADDRESS;
5734 
5735 	if (path.InitCheck() != B_OK || device.InitCheck() != B_OK)
5736 		return B_NO_MEMORY;
5737 
5738 	if (user_strlcpy(path.LockBuffer(), userPath, B_PATH_NAME_LENGTH) < B_OK)
5739 		return B_BAD_ADDRESS;
5740 
5741 	if (userFileSystem != NULL
5742 		&& user_strlcpy(fileSystem, userFileSystem, sizeof(fileSystem)) < B_OK)
5743 		return B_BAD_ADDRESS;
5744 
5745 	if (userDevice != NULL
5746 		&& user_strlcpy(device.LockBuffer(), userDevice, B_PATH_NAME_LENGTH) < B_OK)
5747 		return B_BAD_ADDRESS;
5748 
5749 	if (userArgs != NULL) {
5750 		// We have no real length restriction, so we need to create
5751 		// a buffer large enough to hold the argument string
5752 		// ToDo: we could think about determinung the length of the string
5753 		//	in userland :)
5754 		ssize_t length = user_strlcpy(args, userArgs, 0);
5755 		if (length < B_OK)
5756 			return B_BAD_ADDRESS;
5757 
5758 		// this is a safety restriction
5759 		if (length > 32 * 1024)
5760 			return B_NAME_TOO_LONG;
5761 
5762 		if (length > 0) {
5763 			args = (char *)malloc(length + 1);
5764 			if (args == NULL)
5765 				return B_NO_MEMORY;
5766 
5767 			if (user_strlcpy(args, userArgs, length + 1) < B_OK) {
5768 				free(args);
5769 				return B_BAD_ADDRESS;
5770 			}
5771 		}
5772 	}
5773 	path.UnlockBuffer();
5774 	device.UnlockBuffer();
5775 
5776 	status = fs_mount(path.LockBuffer(), userDevice != NULL ? device.Path() : NULL,
5777 		userFileSystem ? fileSystem : NULL, flags, args, false);
5778 
5779 	free(args);
5780 	return status;
5781 }
5782 
5783 
5784 status_t
5785 _user_unmount(const char *userPath, uint32 flags)
5786 {
5787 	KPath pathBuffer(B_PATH_NAME_LENGTH + 1);
5788 	if (pathBuffer.InitCheck() != B_OK)
5789 		return B_NO_MEMORY;
5790 
5791 	char *path = pathBuffer.LockBuffer();
5792 
5793 	if (user_strlcpy(path, userPath, B_PATH_NAME_LENGTH) < B_OK)
5794 		return B_BAD_ADDRESS;
5795 
5796 	return fs_unmount(path, flags, false);
5797 }
5798 
5799 
5800 status_t
5801 _user_read_fs_info(dev_t device, struct fs_info *userInfo)
5802 {
5803 	struct fs_info info;
5804 	status_t status;
5805 
5806 	if (userInfo == NULL)
5807 		return B_BAD_VALUE;
5808 
5809 	if (!IS_USER_ADDRESS(userInfo))
5810 		return B_BAD_ADDRESS;
5811 
5812 	status = fs_read_info(device, &info);
5813 	if (status != B_OK)
5814 		return status;
5815 
5816 	if (user_memcpy(userInfo, &info, sizeof(struct fs_info)) < B_OK)
5817 		return B_BAD_ADDRESS;
5818 
5819 	return B_OK;
5820 }
5821 
5822 
5823 status_t
5824 _user_write_fs_info(dev_t device, const struct fs_info *userInfo, int mask)
5825 {
5826 	struct fs_info info;
5827 
5828 	if (userInfo == NULL)
5829 		return B_BAD_VALUE;
5830 
5831 	if (!IS_USER_ADDRESS(userInfo)
5832 		|| user_memcpy(&info, userInfo, sizeof(struct fs_info)) < B_OK)
5833 		return B_BAD_ADDRESS;
5834 
5835 	return fs_write_info(device, &info, mask);
5836 }
5837 
5838 
5839 dev_t
5840 _user_next_device(int32 *_userCookie)
5841 {
5842 	int32 cookie;
5843 	dev_t device;
5844 
5845 	if (!IS_USER_ADDRESS(_userCookie)
5846 		|| user_memcpy(&cookie, _userCookie, sizeof(int32)) < B_OK)
5847 		return B_BAD_ADDRESS;
5848 
5849 	device = fs_next_device(&cookie);
5850 
5851 	if (device >= B_OK) {
5852 		// update user cookie
5853 		if (user_memcpy(_userCookie, &cookie, sizeof(int32)) < B_OK)
5854 			return B_BAD_ADDRESS;
5855 	}
5856 
5857 	return device;
5858 }
5859 
5860 
5861 status_t
5862 _user_sync(void)
5863 {
5864 	return _kern_sync();
5865 }
5866 
5867 
5868 status_t
5869 _user_entry_ref_to_path(dev_t device, ino_t inode, const char *leaf,
5870 	char *userPath, size_t pathLength)
5871 {
5872 	char path[B_PATH_NAME_LENGTH + 1];
5873 	struct vnode *vnode;
5874 	int status;
5875 
5876 	if (!IS_USER_ADDRESS(userPath))
5877 		return B_BAD_ADDRESS;
5878 
5879 	// copy the leaf name onto the stack
5880 	char stackLeaf[B_FILE_NAME_LENGTH];
5881 	if (leaf) {
5882 		if (!IS_USER_ADDRESS(leaf))
5883 			return B_BAD_ADDRESS;
5884 
5885 		int len = user_strlcpy(stackLeaf, leaf, B_FILE_NAME_LENGTH);
5886 		if (len < 0)
5887 			return len;
5888 		if (len >= B_FILE_NAME_LENGTH)
5889 			return B_NAME_TOO_LONG;
5890 		leaf = stackLeaf;
5891 
5892 		// filter invalid leaf names
5893 		if (leaf[0] == '\0' || strchr(leaf, '/'))
5894 			return B_BAD_VALUE;
5895 	}
5896 
5897 	// get the vnode matching the dir's node_ref
5898 	if (leaf && (strcmp(leaf, ".") == 0 || strcmp(leaf, "..") == 0)) {
5899 		// special cases "." and "..": we can directly get the vnode of the
5900 		// referenced directory
5901 		status = entry_ref_to_vnode(device, inode, leaf, &vnode);
5902 		leaf = NULL;
5903 	} else
5904 		status = get_vnode(device, inode, &vnode, false);
5905 	if (status < B_OK)
5906 		return status;
5907 
5908 	// get the directory path
5909 	status = dir_vnode_to_path(vnode, path, sizeof(path));
5910 	put_vnode(vnode);
5911 		// we don't need the vnode anymore
5912 	if (status < B_OK)
5913 		return status;
5914 
5915 	// append the leaf name
5916 	if (leaf) {
5917 		// insert a directory separator if this is not the file system root
5918 		if ((strcmp(path, "/") && strlcat(path, "/", sizeof(path)) >= sizeof(path))
5919 			|| strlcat(path, leaf, sizeof(path)) >= sizeof(path)) {
5920 			return B_NAME_TOO_LONG;
5921 		}
5922 	}
5923 
5924 	int len = user_strlcpy(userPath, path, pathLength);
5925 	if (len < 0)
5926 		return len;
5927 	if (len >= (int)pathLength)
5928 		return B_BUFFER_OVERFLOW;
5929 	return B_OK;
5930 }
5931 
5932 
5933 int
5934 _user_open_entry_ref(dev_t device, ino_t inode, const char *userName,
5935 	int openMode, int perms)
5936 {
5937 	char name[B_FILE_NAME_LENGTH];
5938 	int status;
5939 
5940 	if (!IS_USER_ADDRESS(userName))
5941 		return B_BAD_ADDRESS;
5942 
5943 	status = user_strlcpy(name, userName, sizeof(name));
5944 	if (status < B_OK)
5945 		return status;
5946 
5947 	if (openMode & O_CREAT)
5948 		return file_create_entry_ref(device, inode, name, openMode, perms, false);
5949 
5950 	return file_open_entry_ref(device, inode, name, openMode, false);
5951 }
5952 
5953 
5954 int
5955 _user_open(int fd, const char *userPath, int openMode, int perms)
5956 {
5957 	char path[B_PATH_NAME_LENGTH + 1];
5958 	int status;
5959 
5960 	if (!IS_USER_ADDRESS(userPath))
5961 		return B_BAD_ADDRESS;
5962 
5963 	status = user_strlcpy(path, userPath, B_PATH_NAME_LENGTH);
5964 	if (status < 0)
5965 		return status;
5966 
5967 	if (openMode & O_CREAT)
5968 		return file_create(fd, path, openMode, perms, false);
5969 
5970 	return file_open(fd, path, openMode, false);
5971 }
5972 
5973 
5974 int
5975 _user_open_dir_entry_ref(dev_t device, ino_t inode, const char *uname)
5976 {
5977 	if (uname) {
5978 		char name[B_FILE_NAME_LENGTH];
5979 
5980 		if (!IS_USER_ADDRESS(uname))
5981 			return B_BAD_ADDRESS;
5982 
5983 		int status = user_strlcpy(name, uname, sizeof(name));
5984 		if (status < B_OK)
5985 			return status;
5986 
5987 		return dir_open_entry_ref(device, inode, name, false);
5988 	}
5989 	return dir_open_entry_ref(device, inode, NULL, false);
5990 }
5991 
5992 
5993 int
5994 _user_open_dir(int fd, const char *userPath)
5995 {
5996 	char path[B_PATH_NAME_LENGTH + 1];
5997 	int status;
5998 
5999 	if (!IS_USER_ADDRESS(userPath))
6000 		return B_BAD_ADDRESS;
6001 
6002 	status = user_strlcpy(path, userPath, B_PATH_NAME_LENGTH);
6003 	if (status < 0)
6004 		return status;
6005 
6006 	return dir_open(fd, path, false);
6007 }
6008 
6009 
6010 /**	\brief Opens a directory's parent directory and returns the entry name
6011  *		   of the former.
6012  *
6013  *	Aside from that is returns the directory's entry name, this method is
6014  *	equivalent to \code _user_open_dir(fd, "..") \endcode. It really is
6015  *	equivalent, if \a userName is \c NULL.
6016  *
6017  *	If a name buffer is supplied and the name does not fit the buffer, the
6018  *	function fails. A buffer of size \c B_FILE_NAME_LENGTH should be safe.
6019  *
6020  *	\param fd A FD referring to a directory.
6021  *	\param userName Buffer the directory's entry name shall be written into.
6022  *		   May be \c NULL.
6023  *	\param nameLength Size of the name buffer.
6024  *	\return The file descriptor of the opened parent directory, if everything
6025  *			went fine, an error code otherwise.
6026  */
6027 
6028 int
6029 _user_open_parent_dir(int fd, char *userName, size_t nameLength)
6030 {
6031 	bool kernel = false;
6032 
6033 	if (userName && !IS_USER_ADDRESS(userName))
6034 		return B_BAD_ADDRESS;
6035 
6036 	// open the parent dir
6037 	int parentFD = dir_open(fd, "..", kernel);
6038 	if (parentFD < 0)
6039 		return parentFD;
6040 	FDCloser fdCloser(parentFD, kernel);
6041 
6042 	if (userName) {
6043 		// get the vnodes
6044 		struct vnode *parentVNode = get_vnode_from_fd(parentFD, kernel);
6045 		struct vnode *dirVNode = get_vnode_from_fd(fd, kernel);
6046 		VNodePutter parentVNodePutter(parentVNode);
6047 		VNodePutter dirVNodePutter(dirVNode);
6048 		if (!parentVNode || !dirVNode)
6049 			return B_FILE_ERROR;
6050 
6051 		// get the vnode name
6052 		char name[B_FILE_NAME_LENGTH];
6053 		status_t status = get_vnode_name(dirVNode, parentVNode,
6054 			name, sizeof(name));
6055 		if (status != B_OK)
6056 			return status;
6057 
6058 		// copy the name to the userland buffer
6059 		int len = user_strlcpy(userName, name, nameLength);
6060 		if (len < 0)
6061 			return len;
6062 		if (len >= (int)nameLength)
6063 			return B_BUFFER_OVERFLOW;
6064 	}
6065 
6066 	return fdCloser.Detach();
6067 }
6068 
6069 
6070 status_t
6071 _user_fcntl(int fd, int op, uint32 argument)
6072 {
6073 	return common_fcntl(fd, op, argument, false);
6074 }
6075 
6076 
6077 status_t
6078 _user_fsync(int fd)
6079 {
6080 	return common_sync(fd, false);
6081 }
6082 
6083 
6084 status_t
6085 _user_lock_node(int fd)
6086 {
6087 	return common_lock_node(fd, false);
6088 }
6089 
6090 
6091 status_t
6092 _user_unlock_node(int fd)
6093 {
6094 	return common_unlock_node(fd, false);
6095 }
6096 
6097 
6098 status_t
6099 _user_create_dir_entry_ref(dev_t device, ino_t inode, const char *userName, int perms)
6100 {
6101 	char name[B_FILE_NAME_LENGTH];
6102 	status_t status;
6103 
6104 	if (!IS_USER_ADDRESS(userName))
6105 		return B_BAD_ADDRESS;
6106 
6107 	status = user_strlcpy(name, userName, sizeof(name));
6108 	if (status < 0)
6109 		return status;
6110 
6111 	return dir_create_entry_ref(device, inode, name, perms, false);
6112 }
6113 
6114 
6115 status_t
6116 _user_create_dir(int fd, const char *userPath, int perms)
6117 {
6118 	char path[B_PATH_NAME_LENGTH + 1];
6119 	status_t status;
6120 
6121 	if (!IS_USER_ADDRESS(userPath))
6122 		return B_BAD_ADDRESS;
6123 
6124 	status = user_strlcpy(path, userPath, B_PATH_NAME_LENGTH);
6125 	if (status < 0)
6126 		return status;
6127 
6128 	return dir_create(fd, path, perms, false);
6129 }
6130 
6131 
6132 status_t
6133 _user_remove_dir(const char *userPath)
6134 {
6135 	char path[B_PATH_NAME_LENGTH + 1];
6136 	int status;
6137 
6138 	if (!IS_USER_ADDRESS(userPath))
6139 		return B_BAD_ADDRESS;
6140 
6141 	status = user_strlcpy(path, userPath, B_PATH_NAME_LENGTH);
6142 	if (status < 0)
6143 		return status;
6144 
6145 	return dir_remove(path, false);
6146 }
6147 
6148 
6149 status_t
6150 _user_read_link(int fd, const char *userPath, char *userBuffer, size_t *userBufferSize)
6151 {
6152 	char path[B_PATH_NAME_LENGTH + 1];
6153 	char buffer[B_PATH_NAME_LENGTH];
6154 	size_t bufferSize;
6155 	int status;
6156 
6157 	if (!IS_USER_ADDRESS(userBuffer) || !IS_USER_ADDRESS(userBufferSize)
6158 		|| user_memcpy(&bufferSize, userBufferSize, sizeof(size_t)) < B_OK)
6159 		return B_BAD_ADDRESS;
6160 
6161 	if (userPath) {
6162 		if (!IS_USER_ADDRESS(userPath))
6163 			return B_BAD_ADDRESS;
6164 
6165 		status = user_strlcpy(path, userPath, B_PATH_NAME_LENGTH);
6166 		if (status < 0)
6167 			return status;
6168 
6169 		if (bufferSize > B_PATH_NAME_LENGTH)
6170 			bufferSize = B_PATH_NAME_LENGTH;
6171 	}
6172 
6173 	status = common_read_link(fd, userPath ? path : NULL, buffer, &bufferSize, false);
6174 
6175 	// we also update the bufferSize in case of errors
6176 	// (the real length will be returned in case of B_BUFFER_OVERFLOW)
6177 	if (user_memcpy(userBufferSize, &bufferSize, sizeof(size_t)) < B_OK)
6178 		return B_BAD_ADDRESS;
6179 
6180 	if (status < B_OK)
6181 		return status;
6182 
6183 	if (user_strlcpy(userBuffer, buffer, bufferSize) < 0)
6184 		return B_BAD_ADDRESS;
6185 
6186 	return B_OK;
6187 }
6188 
6189 
6190 status_t
6191 _user_write_link(const char *userPath, const char *userToPath)
6192 {
6193 	char path[B_PATH_NAME_LENGTH + 1];
6194 	char toPath[B_PATH_NAME_LENGTH + 1];
6195 	int status;
6196 
6197 	if (!IS_USER_ADDRESS(userPath)
6198 		|| !IS_USER_ADDRESS(userToPath))
6199 		return B_BAD_ADDRESS;
6200 
6201 	status = user_strlcpy(path, userPath, B_PATH_NAME_LENGTH);
6202 	if (status < 0)
6203 		return status;
6204 
6205 	status = user_strlcpy(toPath, userToPath, B_PATH_NAME_LENGTH);
6206 	if (status < 0)
6207 		return status;
6208 
6209 	status = check_path(toPath);
6210 	if (status < B_OK)
6211 		return status;
6212 
6213 	return common_write_link(path, toPath, false);
6214 }
6215 
6216 
6217 status_t
6218 _user_create_symlink(int fd, const char *userPath, const char *userToPath,
6219 	int mode)
6220 {
6221 	char path[B_PATH_NAME_LENGTH + 1];
6222 	char toPath[B_PATH_NAME_LENGTH + 1];
6223 	status_t status;
6224 
6225 	if (!IS_USER_ADDRESS(userPath)
6226 		|| !IS_USER_ADDRESS(userToPath))
6227 		return B_BAD_ADDRESS;
6228 
6229 	status = user_strlcpy(path, userPath, B_PATH_NAME_LENGTH);
6230 	if (status < 0)
6231 		return status;
6232 
6233 	status = user_strlcpy(toPath, userToPath, B_PATH_NAME_LENGTH);
6234 	if (status < 0)
6235 		return status;
6236 
6237 	status = check_path(toPath);
6238 	if (status < B_OK)
6239 		return status;
6240 
6241 	return common_create_symlink(fd, path, toPath, mode, false);
6242 }
6243 
6244 
6245 status_t
6246 _user_create_link(const char *userPath, const char *userToPath)
6247 {
6248 	char path[B_PATH_NAME_LENGTH + 1];
6249 	char toPath[B_PATH_NAME_LENGTH + 1];
6250 	status_t status;
6251 
6252 	if (!IS_USER_ADDRESS(userPath)
6253 		|| !IS_USER_ADDRESS(userToPath))
6254 		return B_BAD_ADDRESS;
6255 
6256 	status = user_strlcpy(path, userPath, B_PATH_NAME_LENGTH);
6257 	if (status < 0)
6258 		return status;
6259 
6260 	status = user_strlcpy(toPath, userToPath, B_PATH_NAME_LENGTH);
6261 	if (status < 0)
6262 		return status;
6263 
6264 	status = check_path(toPath);
6265 	if (status < B_OK)
6266 		return status;
6267 
6268 	return common_create_link(path, toPath, false);
6269 }
6270 
6271 
6272 status_t
6273 _user_unlink(int fd, const char *userPath)
6274 {
6275 	char path[B_PATH_NAME_LENGTH + 1];
6276 	int status;
6277 
6278 	if (!IS_USER_ADDRESS(userPath))
6279 		return B_BAD_ADDRESS;
6280 
6281 	status = user_strlcpy(path, userPath, B_PATH_NAME_LENGTH);
6282 	if (status < 0)
6283 		return status;
6284 
6285 	return common_unlink(fd, path, false);
6286 }
6287 
6288 
6289 status_t
6290 _user_rename(int oldFD, const char *userOldPath, int newFD,
6291 	const char *userNewPath)
6292 {
6293 	char oldPath[B_PATH_NAME_LENGTH + 1];
6294 	char newPath[B_PATH_NAME_LENGTH + 1];
6295 	int status;
6296 
6297 	if (!IS_USER_ADDRESS(userOldPath) || !IS_USER_ADDRESS(userNewPath))
6298 		return B_BAD_ADDRESS;
6299 
6300 	status = user_strlcpy(oldPath, userOldPath, B_PATH_NAME_LENGTH);
6301 	if (status < 0)
6302 		return status;
6303 
6304 	status = user_strlcpy(newPath, userNewPath, B_PATH_NAME_LENGTH);
6305 	if (status < 0)
6306 		return status;
6307 
6308 	return common_rename(oldFD, oldPath, newFD, newPath, false);
6309 }
6310 
6311 
6312 status_t
6313 _user_access(const char *userPath, int mode)
6314 {
6315 	char path[B_PATH_NAME_LENGTH + 1];
6316 	int status;
6317 
6318 	if (!IS_USER_ADDRESS(userPath))
6319 		return B_BAD_ADDRESS;
6320 
6321 	status = user_strlcpy(path, userPath, B_PATH_NAME_LENGTH);
6322 	if (status < 0)
6323 		return status;
6324 
6325 	return common_access(path, mode, false);
6326 }
6327 
6328 
6329 status_t
6330 _user_read_stat(int fd, const char *userPath, bool traverseLink,
6331 	struct stat *userStat, size_t statSize)
6332 {
6333 	struct stat stat;
6334 	int status;
6335 
6336 	if (statSize > sizeof(struct stat))
6337 		return B_BAD_VALUE;
6338 
6339 	if (!IS_USER_ADDRESS(userStat))
6340 		return B_BAD_ADDRESS;
6341 
6342 	if (userPath) {
6343 		// path given: get the stat of the node referred to by (fd, path)
6344 		char path[B_PATH_NAME_LENGTH + 1];
6345 		if (!IS_USER_ADDRESS(userPath))
6346 			return B_BAD_ADDRESS;
6347 		int len = user_strlcpy(path, userPath, B_PATH_NAME_LENGTH);
6348 		if (len < 0)
6349 			return len;
6350 		if (len >= B_PATH_NAME_LENGTH)
6351 			return B_NAME_TOO_LONG;
6352 
6353 		status = common_path_read_stat(fd, path, traverseLink, &stat, false);
6354 	} else {
6355 		// no path given: get the FD and use the FD operation
6356 		struct file_descriptor *descriptor
6357 			= get_fd(get_current_io_context(false), fd);
6358 		if (descriptor == NULL)
6359 			return B_FILE_ERROR;
6360 
6361 		if (descriptor->ops->fd_read_stat)
6362 			status = descriptor->ops->fd_read_stat(descriptor, &stat);
6363 		else
6364 			status = EOPNOTSUPP;
6365 
6366 		put_fd(descriptor);
6367 	}
6368 
6369 	if (status < B_OK)
6370 		return status;
6371 
6372 	return user_memcpy(userStat, &stat, statSize);
6373 }
6374 
6375 
6376 status_t
6377 _user_write_stat(int fd, const char *userPath, bool traverseLeafLink,
6378 	const struct stat *userStat, size_t statSize, int statMask)
6379 {
6380 	char path[B_PATH_NAME_LENGTH + 1];
6381 	struct stat stat;
6382 
6383 	if (statSize > sizeof(struct stat))
6384 		return B_BAD_VALUE;
6385 
6386 	if (!IS_USER_ADDRESS(userStat)
6387 		|| user_memcpy(&stat, userStat, statSize) < B_OK)
6388 		return B_BAD_ADDRESS;
6389 
6390 	// clear additional stat fields
6391 	if (statSize < sizeof(struct stat))
6392 		memset((uint8 *)&stat + statSize, 0, sizeof(struct stat) - statSize);
6393 
6394 	status_t status;
6395 
6396 	if (userPath) {
6397 		// path given: write the stat of the node referred to by (fd, path)
6398 		if (!IS_USER_ADDRESS(userPath))
6399 			return B_BAD_ADDRESS;
6400 		int len = user_strlcpy(path, userPath, B_PATH_NAME_LENGTH);
6401 		if (len < 0)
6402 			return len;
6403 		if (len >= B_PATH_NAME_LENGTH)
6404 			return B_NAME_TOO_LONG;
6405 
6406 		status = common_path_write_stat(fd, path, traverseLeafLink, &stat,
6407 			statMask, false);
6408 	} else {
6409 		// no path given: get the FD and use the FD operation
6410 		struct file_descriptor *descriptor
6411 			= get_fd(get_current_io_context(false), fd);
6412 		if (descriptor == NULL)
6413 			return B_FILE_ERROR;
6414 
6415 		if (descriptor->ops->fd_write_stat)
6416 			status = descriptor->ops->fd_write_stat(descriptor, &stat, statMask);
6417 		else
6418 			status = EOPNOTSUPP;
6419 
6420 		put_fd(descriptor);
6421 	}
6422 
6423 	return status;
6424 }
6425 
6426 
6427 int
6428 _user_open_attr_dir(int fd, const char *userPath)
6429 {
6430 	char pathBuffer[B_PATH_NAME_LENGTH + 1];
6431 
6432 	if (userPath != NULL) {
6433 		if (!IS_USER_ADDRESS(userPath)
6434 			|| user_strlcpy(pathBuffer, userPath, B_PATH_NAME_LENGTH) < B_OK)
6435 			return B_BAD_ADDRESS;
6436 	}
6437 
6438 	return attr_dir_open(fd, userPath ? pathBuffer : NULL, false);
6439 }
6440 
6441 
6442 int
6443 _user_create_attr(int fd, const char *userName, uint32 type, int openMode)
6444 {
6445 	char name[B_FILE_NAME_LENGTH];
6446 
6447 	if (!IS_USER_ADDRESS(userName)
6448 		|| user_strlcpy(name, userName, B_FILE_NAME_LENGTH) < B_OK)
6449 		return B_BAD_ADDRESS;
6450 
6451 	return attr_create(fd, name, type, openMode, false);
6452 }
6453 
6454 
6455 int
6456 _user_open_attr(int fd, const char *userName, int openMode)
6457 {
6458 	char name[B_FILE_NAME_LENGTH];
6459 
6460 	if (!IS_USER_ADDRESS(userName)
6461 		|| user_strlcpy(name, userName, B_FILE_NAME_LENGTH) < B_OK)
6462 		return B_BAD_ADDRESS;
6463 
6464 	return attr_open(fd, name, openMode, false);
6465 }
6466 
6467 
6468 status_t
6469 _user_remove_attr(int fd, const char *userName)
6470 {
6471 	char name[B_FILE_NAME_LENGTH];
6472 
6473 	if (!IS_USER_ADDRESS(userName)
6474 		|| user_strlcpy(name, userName, B_FILE_NAME_LENGTH) < B_OK)
6475 		return B_BAD_ADDRESS;
6476 
6477 	return attr_remove(fd, name, false);
6478 }
6479 
6480 
6481 status_t
6482 _user_rename_attr(int fromFile, const char *userFromName, int toFile, const char *userToName)
6483 {
6484 	char fromName[B_FILE_NAME_LENGTH];
6485 	char toName[B_FILE_NAME_LENGTH];
6486 
6487 	if (!IS_USER_ADDRESS(userFromName)
6488 		|| !IS_USER_ADDRESS(userToName))
6489 		return B_BAD_ADDRESS;
6490 
6491 	if (user_strlcpy(fromName, userFromName, B_FILE_NAME_LENGTH) < B_OK
6492 		|| user_strlcpy(toName, userToName, B_FILE_NAME_LENGTH) < B_OK)
6493 		return B_BAD_ADDRESS;
6494 
6495 	return attr_rename(fromFile, fromName, toFile, toName, false);
6496 }
6497 
6498 
6499 int
6500 _user_open_index_dir(dev_t device)
6501 {
6502 	return index_dir_open(device, false);
6503 }
6504 
6505 
6506 status_t
6507 _user_create_index(dev_t device, const char *userName, uint32 type, uint32 flags)
6508 {
6509 	char name[B_FILE_NAME_LENGTH];
6510 
6511 	if (!IS_USER_ADDRESS(userName)
6512 		|| user_strlcpy(name, userName, B_FILE_NAME_LENGTH) < B_OK)
6513 		return B_BAD_ADDRESS;
6514 
6515 	return index_create(device, name, type, flags, false);
6516 }
6517 
6518 
6519 status_t
6520 _user_read_index_stat(dev_t device, const char *userName, struct stat *userStat)
6521 {
6522 	char name[B_FILE_NAME_LENGTH];
6523 	struct stat stat;
6524 	status_t status;
6525 
6526 	if (!IS_USER_ADDRESS(userName)
6527 		|| !IS_USER_ADDRESS(userStat)
6528 		|| user_strlcpy(name, userName, B_FILE_NAME_LENGTH) < B_OK)
6529 		return B_BAD_ADDRESS;
6530 
6531 	status = index_name_read_stat(device, name, &stat, false);
6532 	if (status == B_OK) {
6533 		if (user_memcpy(userStat, &stat, sizeof(stat)) < B_OK)
6534 			return B_BAD_ADDRESS;
6535 	}
6536 
6537 	return status;
6538 }
6539 
6540 
6541 status_t
6542 _user_remove_index(dev_t device, const char *userName)
6543 {
6544 	char name[B_FILE_NAME_LENGTH];
6545 
6546 	if (!IS_USER_ADDRESS(userName)
6547 		|| user_strlcpy(name, userName, B_FILE_NAME_LENGTH) < B_OK)
6548 		return B_BAD_ADDRESS;
6549 
6550 	return index_remove(device, name, false);
6551 }
6552 
6553 
6554 status_t
6555 _user_getcwd(char *userBuffer, size_t size)
6556 {
6557 	char buffer[B_PATH_NAME_LENGTH];
6558 	int status;
6559 
6560 	PRINT(("user_getcwd: buf %p, %ld\n", userBuffer, size));
6561 
6562 	if (!IS_USER_ADDRESS(userBuffer))
6563 		return B_BAD_ADDRESS;
6564 
6565 	if (size > B_PATH_NAME_LENGTH)
6566 		size = B_PATH_NAME_LENGTH;
6567 
6568 	status = get_cwd(buffer, size, false);
6569 	if (status < 0)
6570 		return status;
6571 
6572 	// Copy back the result
6573 	if (user_strlcpy(userBuffer, buffer, size) < B_OK)
6574 		return B_BAD_ADDRESS;
6575 
6576 	return status;
6577 }
6578 
6579 
6580 status_t
6581 _user_setcwd(int fd, const char *userPath)
6582 {
6583 	char path[B_PATH_NAME_LENGTH];
6584 
6585 	PRINT(("user_setcwd: path = %p\n", userPath));
6586 
6587 	if (userPath != NULL) {
6588 		if (!IS_USER_ADDRESS(userPath)
6589 			|| user_strlcpy(path, userPath, B_PATH_NAME_LENGTH) < B_OK)
6590 			return B_BAD_ADDRESS;
6591 	}
6592 
6593 	return set_cwd(fd, userPath != NULL ? path : NULL, false);
6594 }
6595 
6596 
6597 int
6598 _user_open_query(dev_t device, const char *userQuery, size_t queryLength,
6599 	uint32 flags, port_id port, int32 token)
6600 {
6601 	char *query;
6602 
6603 	if (device < 0 || userQuery == NULL || queryLength == 0 || queryLength >= 65536)
6604 		return B_BAD_VALUE;
6605 
6606 	query = (char *)malloc(queryLength + 1);
6607 	if (query == NULL)
6608 		return B_NO_MEMORY;
6609 	if (user_strlcpy(query, userQuery, queryLength + 1) < B_OK) {
6610 		free(query);
6611 		return B_BAD_ADDRESS;
6612 	}
6613 
6614 	int fd = query_open(device, query, flags, port, token, false);
6615 
6616 	free(query);
6617 	return fd;
6618 }
6619