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