Index: uspace/app/bdsh/cmds/builtins/cd/cd.c
===================================================================
--- uspace/app/bdsh/cmds/builtins/cd/cd.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/app/bdsh/cmds/builtins/cd/cd.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -29,7 +29,7 @@
 #include <stdio.h>
 #include <stdlib.h>
-#include <unistd.h>
 #include <str.h>
 #include <errno.h>
+#include <vfs/vfs.h>
 
 #include "util.h"
@@ -51,12 +51,14 @@
 static bool previous_directory_set = false;
 
-static int chdir_and_remember(const char *new_dir) {
+static int chdir_and_remember(const char *new_dir)
+{
 
-	char *ok = getcwd(previous_directory_tmp, PATH_MAX);
-	previous_directory_valid = ok != NULL;
+	int rc = vfs_cwd_get(previous_directory_tmp, PATH_MAX);
+	previous_directory_valid = (rc == EOK);
 	previous_directory_set = true;
 
-	if (chdir(new_dir) != 0)
-		return errno;
+	rc = vfs_cwd_set(new_dir);
+	if (rc != EOK)
+		return rc;
 
 	str_cpy(previous_directory, PATH_MAX, previous_directory_tmp);
Index: uspace/app/bdsh/cmds/modules/cat/cat.c
===================================================================
--- uspace/app/bdsh/cmds/modules/cat/cat.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/app/bdsh/cmds/modules/cat/cat.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -33,5 +33,4 @@
 #include <getopt.h>
 #include <str.h>
-#include <fcntl.h>
 #include <io/console.h>
 #include <io/color.h>
@@ -187,4 +186,5 @@
 	size_t offset = 0, copied_bytes = 0;
 	off64_t file_size = 0, length = 0;
+	aoff64_t pos = 0;
 
 	bool reading_stdin = dash_represents_stdin && (str_cmp(fname, "-") == 0);
@@ -195,5 +195,5 @@
 		blen = STR_BOUNDS(1);
 	} else
-		fd = open(fname, O_RDONLY);
+		fd = vfs_lookup_open(fname, WALK_REGULAR, MODE_READ);
 	
 	if (fd < 0) {
@@ -203,12 +203,20 @@
 
 	if (NULL == (buff = (char *) malloc(blen + 1))) {
-		close(fd);
+		vfs_put(fd);
 		printf("Unable to allocate enough memory to read %s\n",
-			fname);
+		    fname);
 		return 1;
 	}
 
 	if (tail != CAT_FULL_FILE) {
-		file_size = lseek(fd, 0, SEEK_END);
+		struct stat st;
+
+		if (vfs_stat(fd, &st) != EOK) {
+			vfs_put(fd);
+			free(buff);
+			printf("Unable to vfs_stat %d\n", fd);
+			return 1;
+		}
+		file_size = st.size;
 		if (head == CAT_FULL_FILE) {
 			head = file_size;
@@ -223,7 +231,7 @@
 
 		if (tail_first) {
-			lseek(fd, (tail >= file_size) ? 0 : (file_size - tail), SEEK_SET);
+			pos = (tail >= file_size) ? 0 : (file_size - tail);
 		} else {
-			lseek(fd, ((head - tail) >= file_size) ? 0 : (head - tail), SEEK_SET);
+			pos = ((head - tail) >= file_size) ? 0 : (head - tail);
 		}
 	} else
@@ -243,5 +251,5 @@
 		}
 		
-		bytes = read(fd, buff + copied_bytes, bytes_to_read);
+		bytes = vfs_read(fd, &pos, buff + copied_bytes, bytes_to_read);
 		copied_bytes = 0;
 
@@ -279,5 +287,5 @@
 	} while (bytes > 0 && !should_quit && (count < length || length == CAT_FULL_FILE));
 
-	close(fd);
+	vfs_put(fd);
 	if (bytes == -1) {
 		printf("Error reading %s\n", fname);
Index: uspace/app/bdsh/cmds/modules/cmp/cmp.c
===================================================================
--- uspace/app/bdsh/cmds/modules/cmp/cmp.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/app/bdsh/cmds/modules/cmp/cmp.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -28,5 +28,4 @@
 
 #include <errno.h>
-#include <fcntl.h>
 #include <getopt.h>
 #include <mem.h>
@@ -79,9 +78,10 @@
 	char buffer[2][CMP_BUFLEN];
 	ssize_t offset[2];
+	aoff64_t pos[2] = {};
 
 	for (int i = 0; i < 2; i++) {
-		fd[i] = open(fn[i], O_RDONLY);
+		fd[i] = vfs_lookup_open(fn[i], WALK_REGULAR, MODE_READ);
 		if (fd[i] < 0) {
-			rc = errno;
+			rc = fd[i];
 			printf("Unable to open %s\n", fn[i]);
 			goto end;
@@ -94,8 +94,9 @@
 			ssize_t size;
 			do {
-				size = read(fd[i], buffer[i] + offset[i],
+				size = vfs_read(fd[i], &pos[i],
+				    buffer[i] + offset[i],
 				    CMP_BUFLEN - offset[i]);
 				if (size < 0) {
-					rc = errno;
+					rc = size;
 					printf("Error reading from %s\n",
 					    fn[i]);
@@ -115,7 +116,7 @@
 end:
 	if (fd[0] >= 0)
-		close(fd[0]);
+		vfs_put(fd[0]);
 	if (fd[1] >= 0)
-		close(fd[1]);
+		vfs_put(fd[1]);
 	return rc;
 }
Index: uspace/app/bdsh/cmds/modules/cp/cp.c
===================================================================
--- uspace/app/bdsh/cmds/modules/cp/cp.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/app/bdsh/cmds/modules/cp/cp.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -35,6 +35,5 @@
 #include <getopt.h>
 #include <str.h>
-#include <fcntl.h>
-#include <sys/stat.h>
+#include <vfs/vfs.h>
 #include <dirent.h>
 #include "config.h"
@@ -83,7 +82,7 @@
 	struct stat s;
 
-	int r = stat(path, &s);
-
-	if (r != 0)
+	int r = vfs_stat_path(path, &s);
+
+	if (r != EOK)
 		return TYPE_NONE;
 	else if (s.is_directory)
@@ -235,5 +234,5 @@
 			 */
 			if (force && !interactive) {
-				if (unlink(dest_path) != 0) {
+				if (vfs_unlink_path(dest_path) != EOK) {
 					printf("Unable to remove %s\n",
 					    dest_path);
@@ -246,5 +245,5 @@
 				if (overwrite) {
 					printf("Overwriting file: %s\n", dest_path);
-					if (unlink(dest_path) != 0) {
+					if (vfs_unlink_path(dest_path) != EOK) {
 						printf("Unable to remove %s\n", dest_path);
 						goto exit;
@@ -295,5 +294,6 @@
 				merge_paths(dest_path, PATH_MAX, src_dirname);
 
-				if (mkdir(dest_path, 0) != 0) {
+				if (vfs_link_path(dest_path, KIND_DIRECTORY,
+				    NULL) != EOK) {
 					printf("Unable to create "
 					    "dest directory %s\n", dest_path);
@@ -309,5 +309,6 @@
 			 * e.g. cp -r /src /data/new_dir_src
 			 */
-			if (mkdir(dest_path, 0) != 0) {
+			if (vfs_link_path(dest_path, KIND_DIRECTORY,
+			    NULL) != EOK) {
 				printf("Unable to create "
 				    "dest directory %s\n", dest_path);
@@ -341,6 +342,6 @@
 
 			/* Check if we are copying a directory into itself */
-			stat(src_dent, &src_s);
-			stat(dest_path, &dest_s);
+			vfs_stat_path(src_dent, &src_s);
+			vfs_stat_path(dest_path, &dest_s);
 
 			if (dest_s.index == src_s.index &&
@@ -377,25 +378,33 @@
 	int64_t copied = 0;
 	char *buff = NULL;
+	aoff64_t posr = 0, posw = 0;
+	struct stat st;
 
 	if (vb)
 		printf("Copying %s to %s\n", src, dest);
 
-	if (-1 == (fd1 = open(src, O_RDONLY))) {
+	fd1 = vfs_lookup_open(src, WALK_REGULAR, MODE_READ);
+	if (fd1 < 0) {
 		printf("Unable to open source file %s\n", src);
 		return -1;
 	}
 
-	if (-1 == (fd2 = open(dest, O_CREAT))) {
+	fd2 = vfs_lookup_open(dest, WALK_REGULAR | WALK_MAY_CREATE, MODE_WRITE);
+	if (fd2 < 0) {
 		printf("Unable to open destination file %s\n", dest);
-		close(fd1);
+		vfs_put(fd1);
 		return -1;
 	}
 
-	total = lseek(fd1, 0, SEEK_END);
-
+	if (vfs_stat(fd1, &st) != EOK) {
+		printf("Unable to fstat %d\n", fd1);
+		vfs_put(fd1);
+		vfs_put(fd2);
+		return -1;	
+	}
+
+	total = st.size;
 	if (vb)
 		printf("%" PRIu64 " bytes to copy\n", total);
-
-	lseek(fd1, 0, SEEK_SET);
 
 	if (NULL == (buff = (char *) malloc(blen))) {
@@ -406,6 +415,6 @@
 	}
 
-	while ((bytes = read(fd1, buff, blen)) > 0) {
-		if ((bytes = write(fd2, buff, bytes)) < 0)
+	while ((bytes = vfs_read(fd1, &posr, buff, blen)) > 0) {
+		if ((bytes = vfs_write(fd2, &posw, buff, bytes)) < 0)
 			break;
 		copied += bytes;
@@ -413,11 +422,11 @@
 
 	if (bytes < 0) {
-		printf("\nError copying %s, (%d)\n", src, errno);
+		printf("\nError copying %s, (%d)\n", src, bytes);
 		copied = bytes;
 	}
 
 out:
-	close(fd1);
-	close(fd2);
+	vfs_put(fd1);
+	vfs_put(fd2);
 	if (buff)
 		free(buff);
Index: uspace/app/bdsh/cmds/modules/ls/ls.c
===================================================================
--- uspace/app/bdsh/cmds/modules/ls/ls.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/app/bdsh/cmds/modules/ls/ls.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -34,10 +34,8 @@
 #include <stdio.h>
 #include <stdlib.h>
-#include <unistd.h>
 #include <dirent.h>
-#include <fcntl.h>
 #include <getopt.h>
 #include <sys/types.h>
-#include <sys/stat.h>
+#include <vfs/vfs.h>
 #include <str.h>
 #include <sort.h>
@@ -185,8 +183,8 @@
 		buff[len] = '\0';
 
-		rc = stat(buff, &tosort[nbdirs++].s);
-		if (rc != 0) {
+		rc = vfs_stat_path(buff, &tosort[nbdirs++].s);
+		if (rc != EOK) {
 			printf("ls: skipping bogus node %s\n", buff);
-			printf("error=%d\n", errno);
+			printf("error=%d\n", rc);
 			goto out;
 		}
@@ -315,5 +313,5 @@
 static unsigned int ls_scope(const char *path, struct dir_elem_t *de)
 {
-	if (stat(path, &de->s) != 0) {
+	if (vfs_stat_path(path, &de->s) != EOK) {
 		cli_error(CL_ENOENT, "%s", path);
 		return LS_BOGUS;
@@ -388,5 +386,5 @@
 
 	if (argc == 0) {
-		if (getcwd(de.name, PATH_MAX) == NULL) {
+		if (vfs_cwd_get(de.name, PATH_MAX) != EOK) {
 			cli_error(CL_EFAIL, "%s: Failed determining working "
 			    "directory", cmdname);
Index: uspace/app/bdsh/cmds/modules/ls/ls.h
===================================================================
--- uspace/app/bdsh/cmds/modules/ls/ls.h	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/app/bdsh/cmds/modules/ls/ls.h	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -1,4 +1,6 @@
 #ifndef LS_H
 #define LS_H
+
+#include <vfs/vfs.h>
 
 /* Various values that can be returned by ls_scope() */
Index: uspace/app/bdsh/cmds/modules/mkdir/mkdir.c
===================================================================
--- uspace/app/bdsh/cmds/modules/mkdir/mkdir.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/app/bdsh/cmds/modules/mkdir/mkdir.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -30,7 +30,5 @@
 #include <stdlib.h>
 #include <dirent.h>
-#include <fcntl.h>
 #include <sys/types.h>
-#include <sys/stat.h>
 #include <getopt.h>
 #include <stdarg.h>
@@ -98,7 +96,8 @@
 
 	if (!create_parents) {
-		if (mkdir(path, 0) != 0) {
+		ret = vfs_link_path(path, KIND_DIRECTORY, NULL);
+		if (ret != EOK) {
 			cli_error(CL_EFAIL, "%s: could not create %s (%s)",
-			    cmdname, path, str_error(errno));
+			    cmdname, path, str_error(ret));
 			ret = 1;
 		}
@@ -136,7 +135,8 @@
 			path[prev_off] = 0;
 
-			if (mkdir(path, 0) != 0 && errno != EEXIST) {
+			ret = vfs_link_path(path, KIND_DIRECTORY, NULL);
+			if (ret != EOK && ret != EEXIST) {
 				cli_error(CL_EFAIL, "%s: could not create %s (%s)",
-				    cmdname, path, str_error(errno));
+				    cmdname, path, str_error(ret));
 				ret = 1;
 				goto leave;
@@ -146,7 +146,8 @@
 		}
 		/* Create the final directory. */
-		if (mkdir(path, 0) != 0) {
+		ret = vfs_link_path(path, KIND_DIRECTORY, NULL);
+		if (ret != EOK) {
 			cli_error(CL_EFAIL, "%s: could not create %s (%s)",
-			    cmdname, path, str_error(errno));
+			    cmdname, path, str_error(ret));
 			ret = 1;
 		}
@@ -207,5 +208,5 @@
 
 	if (follow && (argv[optind] != NULL)) {
-		if (chdir(argv[optind]) != 0)
+		if (vfs_cwd_set(argv[optind]) != EOK)
 			printf("%s: Error switching to directory.", cmdname);
 	}
Index: uspace/app/bdsh/cmds/modules/mkfile/mkfile.c
===================================================================
--- uspace/app/bdsh/cmds/modules/mkfile/mkfile.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/app/bdsh/cmds/modules/mkfile/mkfile.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -31,7 +31,5 @@
 #include <stdlib.h>
 #include <dirent.h>
-#include <fcntl.h>
 #include <sys/types.h>
-#include <sys/stat.h>
 #include <macros.h>
 #include <getopt.h>
@@ -39,4 +37,5 @@
 #include <str.h>
 #include <ctype.h>
+#include <vfs/vfs.h>
 
 #include "config.h"
@@ -121,4 +120,5 @@
 	void *buffer;
 	bool create_sparse = false;
+	aoff64_t pos = 0;
 
 	file_size = 0;
@@ -156,5 +156,5 @@
 	file_name = argv[optind];
 
-	fd = open(file_name, O_CREAT | O_EXCL | O_WRONLY, 0666);
+	fd = vfs_lookup_open(file_name, WALK_REGULAR | WALK_MUST_CREATE, MODE_WRITE);
 	if (fd < 0) {
 		printf("%s: failed to create file %s.\n", cmdname, file_name);
@@ -164,13 +164,9 @@
 	if (create_sparse && file_size > 0) {
 		const char byte = 0x00;
-
-		if ((rc2 = lseek(fd, file_size - 1, SEEK_SET)) < 0) {
-			close(fd);
-			goto error;
-		}
-
-		rc2 = write(fd, &byte, sizeof(char));
+		
+		pos = file_size - 1;
+		rc2 = vfs_write(fd, &pos, &byte, sizeof(char));
 		if (rc2 < 0) {
-			close(fd);
+			vfs_put(fd);
 			goto error;
 		}
@@ -187,8 +183,8 @@
 	while (total_written < file_size) {
 		to_write = min(file_size - total_written, BUFFER_SIZE);
-		rc = write(fd, buffer, to_write);
+		rc = vfs_write(fd, &pos, buffer, to_write);
 		if (rc <= 0) {
 			printf("%s: Error writing file (%d).\n", cmdname, errno);
-			close(fd);
+			vfs_put(fd);
 			free(buffer);
 			return CMD_FAILURE;
@@ -199,5 +195,5 @@
 	free(buffer);
 
-	if (close(fd) < 0)
+	if (vfs_put(fd) < 0)
 		goto error;
 
Index: uspace/app/bdsh/cmds/modules/mount/mount.c
===================================================================
--- uspace/app/bdsh/cmds/modules/mount/mount.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/app/bdsh/cmds/modules/mount/mount.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -32,4 +32,5 @@
 #include <str_error.h>
 #include <vfs/vfs.h>
+#include <vfs/vfs_mtab.h>
 #include <adt/list.h>
 #include <errno.h>
@@ -82,6 +83,4 @@
 
 		printf("%s", mtab_ent->fs_name);
-		if (mtab_ent->instance)
-			printf("/%d", mtab_ent->instance);
 
 		printf(" %s", mtab_ent->mp);
@@ -94,7 +93,4 @@
 			printf(" (%" PRIun ")", mtab_ent->service_id);
 		}
-
-		if (str_size(mtab_ent->opts) > 0)
-			printf(" (%s)", mtab_ent->opts);
 
 		putchar('\n');
@@ -151,8 +147,8 @@
 		mopts = t_argv[4];
 
-	rc = vfs_mount(t_argv[1], t_argv[2], dev, mopts, 0, instance);
+	rc = vfs_mount_path(t_argv[2], t_argv[1], dev, mopts, 0, instance);
 	if (rc != EOK) {
 		printf("Unable to mount %s filesystem to %s on %s (rc=%s)\n",
-		    t_argv[1], t_argv[2], t_argv[3], str_error(rc));
+		    t_argv[2], t_argv[1], t_argv[3], str_error(rc));
 		return CMD_FAILURE;
 	}
Index: uspace/app/bdsh/cmds/modules/mv/mv.c
===================================================================
--- uspace/app/bdsh/cmds/modules/mv/mv.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/app/bdsh/cmds/modules/mv/mv.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -30,4 +30,5 @@
 #include <stdlib.h>
 #include <errno.h>
+#include <vfs/vfs.h>
 #include "config.h"
 #include "util.h"
@@ -59,8 +60,8 @@
 	}
 
-	rc = rename(argv[1], argv[2]);
-	if (rc != 0) {
+	rc = vfs_rename_path(argv[1], argv[2]);
+	if (rc != EOK) {
 		printf("Unable to rename %s to %s (error=%d)\n",
-		    argv[1], argv[2], errno);
+		    argv[1], argv[2], rc);
 		return CMD_FAILURE;
 	}
Index: uspace/app/bdsh/cmds/modules/pwd/pwd.c
===================================================================
--- uspace/app/bdsh/cmds/modules/pwd/pwd.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/app/bdsh/cmds/modules/pwd/pwd.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -30,4 +30,6 @@
 #include <stdlib.h>
 #include <mem.h>
+#include <vfs/vfs.h>
+#include <abi/errno.h>
 
 #include "config.h"
@@ -57,5 +59,5 @@
 	memset(buff, 0, PATH_MAX);
 
-	if (getcwd(buff, PATH_MAX) == NULL) {
+	if (vfs_cwd_get(buff, PATH_MAX) != EOK) {
 		cli_error(CL_EFAIL,
 			"Unable to determine the current working directory");
Index: uspace/app/bdsh/cmds/modules/rm/rm.c
===================================================================
--- uspace/app/bdsh/cmds/modules/rm/rm.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/app/bdsh/cmds/modules/rm/rm.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -30,10 +30,9 @@
 #include <stdio.h>
 #include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
 #include <dirent.h>
 #include <getopt.h>
 #include <mem.h>
 #include <str.h>
+#include <vfs/vfs.h>
 
 #include "config.h"
@@ -110,7 +109,7 @@
 	memset(rm->cwd, 0, PATH_MAX);
 
-	chdir(".");
-
-	if (NULL == (getcwd(rm->owd, PATH_MAX)))
+	vfs_cwd_set(".");
+
+	if (EOK != vfs_cwd_get(rm->owd, PATH_MAX))
 		return 0;
 
@@ -132,5 +131,5 @@
 static unsigned int rm_single(const char *path)
 {
-	if (unlink(path) != 0) {
+	if (vfs_unlink_path(path) != EOK) {
 		cli_error(CL_EFAIL, "rm: could not remove file %s", path);
 		return 1;
@@ -150,7 +149,7 @@
 	}
 
-	fd = open(path, O_RDONLY);
+	fd = vfs_lookup(path, WALK_REGULAR);
 	if (fd >= 0) {
-		close(fd);
+		vfs_put(fd);
 		return RM_FILE;
 	}
@@ -201,6 +200,6 @@
 
 	/* First see if it will just go away */
-	rc = rmdir(path);
-	if (rc == 0)
+	rc = vfs_unlink_path(path);
+	if (rc == EOK)
 		return 0;
 
@@ -209,7 +208,7 @@
 
 	/* Delete directory */
-	rc = rmdir(path);
-	if (rc == 0)
-		return errno;
+	rc = vfs_unlink_path(path);
+	if (rc == EOK)
+		return EOK;
 
 	cli_error(CL_ENOTSUP, "Can not remove %s", path);
Index: uspace/app/bdsh/cmds/modules/touch/touch.c
===================================================================
--- uspace/app/bdsh/cmds/modules/touch/touch.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/app/bdsh/cmds/modules/touch/touch.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -35,11 +35,10 @@
 #include <stdlib.h>
 #include <unistd.h>
-#include <fcntl.h>
 #include <dirent.h>
 #include <sys/types.h>
 #include <str.h>
 #include <getopt.h>
-#include <sys/stat.h>
 #include <errno.h>
+#include <vfs/vfs.h>
 
 #include "config.h"
@@ -123,6 +122,8 @@
 		
 		/* Check whether file exists if -c (--no-create) option is given */
-		if ((!no_create) || ((no_create) && (stat(buff, &file_stat) == 0)))
-			fd = open(buff, O_RDWR | O_CREAT);
+		if ((!no_create) ||
+		    ((no_create) && (vfs_stat_path(buff, &file_stat) == EOK))) {
+			fd = vfs_lookup(buff, WALK_REGULAR | WALK_MAY_CREATE);
+		}
 		
 		if (fd < 0) {
@@ -132,5 +133,5 @@
 			continue;
 		} else {
-			close(fd);
+			vfs_put(fd);
 			fd = -1;
 		}
Index: uspace/app/bdsh/cmds/modules/unmount/unmount.c
===================================================================
--- uspace/app/bdsh/cmds/modules/unmount/unmount.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/app/bdsh/cmds/modules/unmount/unmount.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -66,5 +66,5 @@
 	}
 
-	rc = vfs_unmount(argv[1]);
+	rc = vfs_unmount_path(argv[1]);
 	if (rc != EOK) {
 		printf("Unable to unmount %s (rc=%d)\n", argv[1], rc);
Index: uspace/app/bdsh/compl.c
===================================================================
--- uspace/app/bdsh/compl.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/app/bdsh/compl.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -33,5 +33,5 @@
 #include <macros.h>
 #include <stdlib.h>
-#include <sys/stat.h>
+#include <vfs/vfs.h>
 
 #include "cmds/cmds.h"
@@ -360,5 +360,5 @@
 				asprintf(&ent_path, "%s/%s", *cs->path, dent->d_name);
 				struct stat ent_stat;
-				if (stat(ent_path, &ent_stat) != 0) {
+				if (vfs_stat_path(ent_path, &ent_stat) != EOK) {
 					/* Error */
 					free(ent_path);
Index: uspace/app/bdsh/exec.c
===================================================================
--- uspace/app/bdsh/exec.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/app/bdsh/exec.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -37,5 +37,4 @@
 #include <unistd.h>
 #include <str.h>
-#include <fcntl.h>
 #include <str_error.h>
 #include <errno.h>
@@ -60,7 +59,7 @@
 	int fd;
 
-	fd = open(f, O_RDONLY);
+	fd = vfs_lookup_open(f, WALK_REGULAR, MODE_READ);
 	if (fd >= 0) {
-		close(fd);
+		vfs_put(fd);
 		return 0;
 	} else
@@ -101,6 +100,5 @@
 	char *tmp;
 	int rc, retval, i;
-	int file_handles[3];
-	int *file_handles_p[4];
+	int file_handles[3] = { -1, -1, -1 };
 	FILE *files[3];
 
@@ -113,14 +111,9 @@
 	
 	for (i = 0; i < 3 && files[i] != NULL; i++) {
-		if (vfs_fhandle(files[i], &file_handles[i]) == EOK) {
-			file_handles_p[i] = &file_handles[i];
-		}
-		else {
-			file_handles_p[i] = NULL;
-		}
+		vfs_fhandle(files[i], &file_handles[i]);
 	}
-	file_handles_p[i] = NULL;
 
-	rc = task_spawnvf(&tid, &twait, tmp, (const char **) argv, file_handles_p);
+	rc = task_spawnvf(&tid, &twait, tmp, (const char **) argv,
+	    file_handles[0], file_handles[1], file_handles[2]);
 	free(tmp);
 
Index: uspace/app/bdsh/util.c
===================================================================
--- uspace/app/bdsh/util.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/app/bdsh/util.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -31,4 +31,6 @@
 #include <stdarg.h>
 #include <stdlib.h>
+#include <vfs/vfs.h>
+#include <abi/errno.h>
 
 #include "config.h"
@@ -58,5 +60,5 @@
 		return 1;
 	}
-	if (!getcwd(usr->cwd, PATH_MAX)) 
+	if (vfs_cwd_get(usr->cwd, PATH_MAX) != EOK)
 		snprintf(usr->cwd, PATH_MAX, "(unknown)");
 
Index: uspace/app/df/df.c
===================================================================
--- uspace/app/df/df.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/app/df/df.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -40,8 +40,8 @@
 #include <stdint.h>
 #include <getopt.h>
-#include <sys/statfs.h>
 #include <errno.h>
 #include <adt/list.h>
 #include <vfs/vfs.h>
+#include <vfs/vfs_mtab.h>
 
 #define NAME  "df"
@@ -123,5 +123,5 @@
 	print_header();
 	list_foreach(mtab_list, link, mtab_ent_t, mtab_ent) {
-		if (statfs(mtab_ent->mp, &st) == 0) {
+		if (vfs_statfs_path(mtab_ent->mp, &st) == 0) {
 			print_statfs(&st, mtab_ent->fs_name, mtab_ent->mp);
 		} else {
Index: uspace/app/fontviewer/fontviewer.c
===================================================================
--- uspace/app/fontviewer/fontviewer.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/app/fontviewer/fontviewer.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -34,7 +34,5 @@
 
 #include <stdio.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/stat.h>
+#include <stdlib.h>
 #include <errno.h>
 #include <malloc.h>
Index: uspace/app/getterm/getterm.c
===================================================================
--- uspace/app/getterm/getterm.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/app/getterm/getterm.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -36,5 +36,4 @@
 
 #include <sys/types.h>
-#include <fcntl.h>
 #include <unistd.h>
 #include <stdio.h>
@@ -43,4 +42,5 @@
 #include <errno.h>
 #include <loc.h>
+#include <vfs/vfs.h>
 #include "version.h"
 #include "welcome.h"
@@ -58,6 +58,6 @@
 }
 
-static void reopen(FILE **stream, int fd, const char *path, int flags,
-    const char *mode)
+static void reopen(FILE **stream, int fd, const char *path, int mode,
+    const char *fmode)
 {
 	if (fclose(*stream))
@@ -66,17 +66,17 @@
 	*stream = NULL;
 	
-	int oldfd = open(path, flags);
+	int oldfd = vfs_lookup_open(path, WALK_REGULAR, mode);
 	if (oldfd < 0)
 		return;
 	
 	if (oldfd != fd) {
-		if (dup2(oldfd, fd) != fd)
+		if (vfs_clone(oldfd, fd, false) != fd)
 			return;
 		
-		if (close(oldfd))
+		if (vfs_put(oldfd))
 			return;
 	}
 	
-	*stream = fdopen(fd, mode);
+	*stream = fdopen(fd, fmode);
 }
 
@@ -141,7 +141,7 @@
 	snprintf(term_node, LOC_NAME_MAXLEN, "%s/%s", locfs, term);
 	
-	reopen(&stdin, 0, term_node, O_RDONLY, "r");
-	reopen(&stdout, 1, term_node, O_WRONLY, "w");
-	reopen(&stderr, 2, term_node, O_WRONLY, "w");
+	reopen(&stdin, 0, term_node, MODE_READ, "r");
+	reopen(&stdout, 1, term_node, MODE_WRITE, "w");
+	reopen(&stderr, 2, term_node, MODE_WRITE, "w");
 	
 	if (stdin == NULL)
Index: uspace/app/init/init.c
===================================================================
--- uspace/app/init/init.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/app/init/init.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -41,6 +41,4 @@
 #include <stdbool.h>
 #include <errno.h>
-#include <fcntl.h>
-#include <sys/stat.h>
 #include <task.h>
 #include <malloc.h>
@@ -50,4 +48,5 @@
 #include <str_error.h>
 #include <config.h>
+#include <io/logctl.h>
 #include "init.h"
 
@@ -127,6 +126,8 @@
 		opts = "restore";
 	
-	int rc = vfs_mount(fstype, ROOT_MOUNT_POINT, ROOT_DEVICE, opts,
+	int rc = vfs_mount_path(ROOT_MOUNT_POINT, fstype, ROOT_DEVICE, opts,
 	    IPC_FLAG_BLOCKING, 0);
+	if (rc == EOK)
+		logctl_set_root();
 	return mount_report("Root filesystem", ROOT_MOUNT_POINT, fstype,
 	    ROOT_DEVICE, rc);
@@ -144,5 +145,5 @@
 static bool mount_locfs(void)
 {
-	int rc = vfs_mount(LOCFS_FS_TYPE, LOCFS_MOUNT_POINT, "", "",
+	int rc = vfs_mount_path(LOCFS_MOUNT_POINT, LOCFS_FS_TYPE, "", "",
 	    IPC_FLAG_BLOCKING, 0);
 	return mount_report("Location service filesystem", LOCFS_MOUNT_POINT,
@@ -153,5 +154,5 @@
 {
 	struct stat s;
-	if (stat(path, &s) != 0) {
+	if (vfs_stat_path(path, &s) != EOK) {
 		printf("%s: Unable to stat %s\n", NAME, path);
 		return ENOENT;
@@ -300,5 +301,5 @@
 static bool mount_tmpfs(void)
 {
-	int rc = vfs_mount(TMPFS_FS_TYPE, TMPFS_MOUNT_POINT, "", "", 0, 0);
+	int rc = vfs_mount_path(TMPFS_MOUNT_POINT, TMPFS_FS_TYPE, "", "", 0, 0);
 	return mount_report("Temporary filesystem", TMPFS_MOUNT_POINT,
 	    TMPFS_FS_TYPE, NULL, rc);
Index: uspace/app/kio/kio.c
===================================================================
--- uspace/app/kio/kio.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/app/kio/kio.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -48,4 +48,5 @@
 #include <adt/prodcons.h>
 #include <tinput.h>
+#include <vfs/vfs.h>
 
 #define NAME       "kio"
@@ -128,5 +129,5 @@
 			
 			fflush(log);
-			fsync(fileno(log));
+			vfs_sync(fileno(log));
 		}
 		
Index: uspace/app/redir/redir.c
===================================================================
--- uspace/app/redir/redir.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/app/redir/redir.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -37,5 +37,4 @@
 #include <sys/types.h>
 #include <stdlib.h>
-#include <fcntl.h>
 #include <unistd.h>
 #include <str.h>
@@ -44,4 +43,5 @@
 #include <str_error.h>
 #include <errno.h>
+#include <vfs/vfs.h>
 
 #define NAME  "redir"
@@ -53,5 +53,6 @@
 }
 
-static void reopen(FILE **stream, int fd, const char *path, int flags, const char *mode)
+static void reopen(FILE **stream, int fd, const char *path, int flags, int mode,
+    const char *fmode)
 {
 	if (fclose(*stream))
@@ -60,17 +61,17 @@
 	*stream = NULL;
 	
-	int oldfd = open(path, flags);
+	int oldfd = vfs_lookup_open(path, WALK_REGULAR | flags, mode);
 	if (oldfd < 0)
 		return;
 	
 	if (oldfd != fd) {
-		if (dup2(oldfd, fd) != fd)
+		if (vfs_clone(oldfd, fd, false) != fd)
 			return;
 		
-		if (close(oldfd))
+		if (vfs_put(oldfd))
 			return;
 	}
 	
-	*stream = fdopen(fd, mode);
+	*stream = fdopen(fd, fmode);
 }
 
@@ -121,5 +122,5 @@
 				return -2;
 			}
-			reopen(&stdin, 0, argv[i], O_RDONLY, "r");
+			reopen(&stdin, 0, argv[i], 0, MODE_READ, "r");
 		} else if (str_cmp(argv[i], "-o") == 0) {
 			i++;
@@ -128,5 +129,6 @@
 				return -3;
 			}
-			reopen(&stdout, 1, argv[i], O_WRONLY | O_CREAT, "w");
+			reopen(&stdout, 1, argv[i], WALK_MAY_CREATE, MODE_WRITE,
+			    "w");
 		} else if (str_cmp(argv[i], "-e") == 0) {
 			i++;
@@ -135,5 +137,6 @@
 				return -4;
 			}
-			reopen(&stderr, 2, argv[i], O_WRONLY | O_CREAT, "w");
+			reopen(&stderr, 2, argv[i], WALK_MAY_CREATE, MODE_WRITE,
+			    "w");
 		} else if (str_cmp(argv[i], "--") == 0) {
 			i++;
Index: uspace/app/sysinst/futil.c
===================================================================
--- uspace/app/sysinst/futil.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/app/sysinst/futil.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -35,9 +35,8 @@
 #include <dirent.h>
 #include <errno.h>
-#include <fcntl.h>
 #include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <sys/stat.h>
+#include <vfs/vfs.h>
 #include <sys/types.h>
 #include <dirent.h>
@@ -60,17 +59,18 @@
 	ssize_t nr, nw;
 	int rc;
+	aoff64_t posr = 0, posw = 0;
 
 	printf("Copy '%s' to '%s'.\n", srcp, destp);
 
-	sf = open(srcp, O_RDONLY);
+	sf = vfs_lookup_open(srcp, WALK_REGULAR, MODE_READ);
 	if (sf < 0)
 		return EIO;
 
-	df = open(destp, O_CREAT | O_WRONLY, 0);
+	df = vfs_lookup_open(destp, WALK_REGULAR | WALK_MAY_CREATE, MODE_WRITE);
 	if (df < 0)
 		return EIO;
 
 	do {
-		nr = read(sf, buf, BUF_SIZE);
+		nr = vfs_read(sf, &posr, buf, BUF_SIZE);
 		if (nr == 0)
 			break;
@@ -78,12 +78,12 @@
 			return EIO;
 
-		nw = write(df, buf, nr);
+		nw = vfs_write(df, &posw, buf, nr);
 		if (nw <= 0)
 			return EIO;
 	} while (true);
 
-	(void) close(sf);
+	(void) vfs_put(sf);
 
-	rc = close(df);
+	rc = vfs_put(df);
 	if (rc < 0)
 		return EIO;
@@ -118,5 +118,5 @@
 			return ENOMEM;
 
-		rc = stat(srcp, &s);
+		rc = vfs_stat_path(srcp, &s);
 		if (rc != EOK)
 			return EIO;
@@ -128,5 +128,5 @@
 		} else if (s.is_directory) {
 			printf("Create directory '%s'\n", destp);
-			rc = mkdir(destp, 0);
+			rc = vfs_link_path(destp, KIND_DIRECTORY, NULL);
 			if (rc != EOK)
 				return EIO;
@@ -157,31 +157,33 @@
 	int sf;
 	ssize_t nr;
-	off64_t off;
 	size_t fsize;
 	char *data;
+	struct stat st;
 
-	sf = open(srcp, O_RDONLY);
+	sf = vfs_lookup_open(srcp, WALK_REGULAR, MODE_READ);
 	if (sf < 0)
 		return ENOENT;
 
-	off = lseek(sf, 0, SEEK_END);
-	if (off == (off64_t)-1)
+	if (vfs_stat(sf, &st) != EOK) {
+		vfs_put(sf);
 		return EIO;
+	}	
 
-	fsize = (size_t)off;
-
-	off = lseek(sf, 0, SEEK_SET);
-	if (off == (off64_t)-1)
-		return EIO;
+	fsize = st.size;
 
 	data = calloc(fsize, 1);
-	if (data == NULL)
+	if (data == NULL) {
+		vfs_put(sf);
 		return ENOMEM;
+	}
 
-	nr = read(sf, data, fsize);
-	if (nr != (ssize_t)fsize)
+	nr = vfs_read(sf, (aoff64_t []) { 0 }, data, fsize);
+	if (nr != (ssize_t)fsize) {
+		vfs_put(sf);
+		free(data);
 		return EIO;
+	}
 
-	(void) close(sf);
+	(void) vfs_put(sf);
 	*rdata = data;
 	*rsize = fsize;
Index: uspace/app/sysinst/sysinst.c
===================================================================
--- uspace/app/sysinst/sysinst.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/app/sysinst/sysinst.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -43,5 +43,4 @@
 #include <stdio.h>
 #include <stdlib.h>
-#include <sys/stat.h>
 #include <task.h>
 #include <vfs/vfs.h>
@@ -175,10 +174,10 @@
 		return EIO;
 
-	rc = mkdir(MOUNT_POINT, 0);
+	rc = vfs_link_path(MOUNT_POINT, KIND_DIRECTORY, NULL);
 	if (rc != EOK)
 		return rc;
 
 	printf("sysinst_fs_mount(): mount filesystem\n");
-	rc = vfs_mount(FS_TYPE, MOUNT_POINT, dev, "", 0, 0);
+	rc = vfs_mount_path(MOUNT_POINT, FS_TYPE, dev, "", 0, 0);
 	if (rc != EOK)
 		return rc;
@@ -214,10 +213,10 @@
 
 	printf("sysinst_copy_boot_files(): create CD mount point\n");
-	rc = mkdir(CD_MOUNT_POINT, 0);
+	rc = vfs_link_path(CD_MOUNT_POINT, KIND_DIRECTORY, NULL);
 	if (rc != EOK)
 		return rc;
 
 	printf("sysinst_copy_boot_files(): mount CD filesystem\n");
-	rc = vfs_mount(CD_FS_TYPE, CD_MOUNT_POINT, CD_DEV, "", 0, 0);
+	rc = vfs_mount_path(CD_MOUNT_POINT, CD_FS_TYPE, CD_DEV, "", 0, 0);
 	if (rc != EOK)
 		return rc;
@@ -229,5 +228,5 @@
 
 	printf("sysinst_copy_boot_files(): unmount %s\n", MOUNT_POINT);
-	rc = vfs_unmount(MOUNT_POINT);
+	rc = vfs_unmount_path(MOUNT_POINT);
 	if (rc != EOK)
 		return rc;
Index: uspace/app/taskdump/elf_core.c
===================================================================
--- uspace/app/taskdump/elf_core.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/app/taskdump/elf_core.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -54,7 +54,5 @@
 #include <errno.h>
 #include <sys/types.h>
-#include <sys/stat.h>
 #include <unistd.h>
-#include <fcntl.h>
 #include <mem.h>
 #include <stdint.h>
@@ -63,10 +61,10 @@
 #include <macros.h>
 #include <libarch/istate.h>
+#include <vfs/vfs.h>
 
 #include "elf_core.h"
 
 static off64_t align_foff_up(off64_t, uintptr_t, size_t);
-static int align_pos(int, size_t);
-static int write_mem_area(int, as_area_info_t *, async_sess_t *);
+static int write_mem_area(int, aoff64_t *, as_area_info_t *, async_sess_t *);
 
 #define BUFFER_SIZE 0x1000
@@ -97,4 +95,5 @@
 	elf_note_t note;
 	size_t word_size;
+	aoff64_t pos = 0;
 
 	int fd;
@@ -124,5 +123,6 @@
 	}
 
-	fd = open(file_name, O_CREAT | O_WRONLY, 0644);
+	fd = vfs_lookup_open(file_name, WALK_REGULAR | WALK_MAY_CREATE,
+	    MODE_WRITE);
 	if (fd < 0) {
 		printf("Failed opening file.\n");
@@ -207,5 +207,5 @@
 	}
 
-	rc = write(fd, &elf_hdr, sizeof(elf_hdr));
+	rc = vfs_write(fd, &pos, &elf_hdr, sizeof(elf_hdr));
 	if (rc != sizeof(elf_hdr)) {
 		printf("Failed writing ELF header.\n");
@@ -215,5 +215,5 @@
 
 	for (i = 0; i < n_ph; ++i) {
-		rc = write(fd, &p_hdr[i], sizeof(p_hdr[i]));
+		rc = vfs_write(fd, &pos, &p_hdr[i], sizeof(p_hdr[i]));
 		if (rc != sizeof(p_hdr[i])) {
 			printf("Failed writing program header.\n");
@@ -223,9 +223,5 @@
 	}
 
-	if (lseek(fd, p_hdr[0].p_offset, SEEK_SET) == (off64_t) -1) {
-		printf("Failed writing memory data.\n");
-		free(p_hdr);
-		return EIO;
-	}
+	pos = p_hdr[0].p_offset;
 
 	/*
@@ -236,5 +232,5 @@
 	note.type = NT_PRSTATUS;
 
-	rc = write(fd, &note, sizeof(elf_note_t));
+	rc = vfs_write(fd, &pos, &note, sizeof(elf_note_t));
 	if (rc != sizeof(elf_note_t)) {
 		printf("Failed writing note header.\n");
@@ -243,5 +239,5 @@
 	}
 
-	rc = write(fd, "CORE", note.namesz);
+	rc = vfs_write(fd, &pos, "CORE", note.namesz);
 	if (rc != (ssize_t) note.namesz) {
 		printf("Failed writing note header.\n");
@@ -250,12 +246,7 @@
 	}
 
-	rc = align_pos(fd, word_size);
-	if (rc != EOK) {
-		printf("Failed writing note header.\n");
-		free(p_hdr);
-		return EIO;
-	}
-
-	rc = write(fd, &pr_status, sizeof(elf_prstatus_t));
+	pos = ALIGN_UP(pos, word_size);
+
+	rc = vfs_write(fd, &pos, &pr_status, sizeof(elf_prstatus_t));
 	if (rc != sizeof(elf_prstatus_t)) {
 		printf("Failed writing register data.\n");
@@ -265,10 +256,6 @@
 
 	for (i = 1; i < n_ph; ++i) {
-		if (lseek(fd, p_hdr[i].p_offset, SEEK_SET) == (off64_t) -1) {
-			printf("Failed writing memory data.\n");
-			free(p_hdr);
-			return EIO;
-		}
-		if (write_mem_area(fd, &ainfo[i - 1], sess) != EOK) {
+		pos = p_hdr[i].p_offset;
+		if (write_mem_area(fd, &pos, &ainfo[i - 1], sess) != EOK) {
 			printf("Failed writing memory data.\n");
 			free(p_hdr);
@@ -297,4 +284,5 @@
  *
  * @param fd   File to write to.
+ * @param pos  Pointer to the position to write to.
  * @param area Memory area info structure.
  * @param sess Debugging session.
@@ -303,5 +291,6 @@
  *
  */
-static int write_mem_area(int fd, as_area_info_t *area, async_sess_t *sess)
+static int write_mem_area(int fd, aoff64_t *pos, as_area_info_t *area,
+    async_sess_t *sess)
 {
 	size_t to_copy;
@@ -321,5 +310,5 @@
 		}
 
-		rc = write(fd, buffer, to_copy);
+		rc = vfs_write(fd, pos, buffer, to_copy);
 		if (rc != (ssize_t) to_copy) {
 			printf("Failed writing memory contents.\n");
@@ -334,23 +323,4 @@
 }
 
-static int align_pos(int fd, size_t align)
-{
-	off64_t cur_pos;
-	size_t rem, adv;
-
-	cur_pos = lseek(fd, 0, SEEK_CUR);
-	if (cur_pos < 0)
-		return -1;
-
-	rem = cur_pos % align;
-	adv = align - rem;
-
-	cur_pos = lseek(fd, adv, SEEK_CUR);
-	if (cur_pos < 0)
-		return -1;
-
-	return EOK;
-}
-
 /** @}
  */
Index: uspace/app/taskdump/symtab.c
===================================================================
--- uspace/app/taskdump/symtab.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/app/taskdump/symtab.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -41,6 +41,5 @@
 #include <errno.h>
 #include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
+#include <vfs/vfs.h>
 
 #include "include/symtab.h"
@@ -68,4 +67,5 @@
 	char *shstrt, *sec_name;
 	void *data;
+	aoff64_t pos = 0;
 
 	int fd;
@@ -81,5 +81,5 @@
 		return ENOMEM;
 
-	fd = open(file_name, O_RDONLY);
+	fd = vfs_lookup_open(file_name, WALK_REGULAR, MODE_READ);
 	if (fd < 0) {
 		printf("failed opening file\n");
@@ -88,5 +88,5 @@
 	}
 
-	rc = read(fd, &elf_hdr, sizeof(elf_header_t));
+	rc = vfs_read(fd, &pos, &elf_hdr, sizeof(elf_header_t));
 	if (rc != sizeof(elf_header_t)) {
 		printf("failed reading elf header\n");
@@ -165,5 +165,5 @@
 
 	free(shstrt);
-	close(fd);
+	vfs_put(fd);
 
 	if (stab->sym == NULL || stab->strtab == NULL) {
@@ -304,11 +304,7 @@
 {
 	int rc;
-
-	rc = lseek(fd, elf_hdr->e_shoff + idx * sizeof(elf_section_header_t),
-	    SEEK_SET);
-	if (rc == (off64_t) -1)
-		return EIO;
-
-	rc = read(fd, sec_hdr, sizeof(elf_section_header_t));
+	aoff64_t pos = elf_hdr->e_shoff + idx * sizeof(elf_section_header_t);
+
+	rc = vfs_read(fd, &pos, sec_hdr, sizeof(elf_section_header_t));
 	if (rc != sizeof(elf_section_header_t))
 		return EIO;
@@ -331,12 +327,5 @@
 {
 	ssize_t rc;
-	off64_t offs;
-
-	offs = lseek(fd, start, SEEK_SET);
-	if (offs == (off64_t) -1) {
-		printf("failed seeking chunk\n");
-		*ptr = NULL;
-		return EIO;
-	}
+	aoff64_t pos = start;
 
 	*ptr = malloc(size);
@@ -346,5 +335,5 @@
 	}
 
-	rc = read(fd, *ptr, size);
+	rc = vfs_read(fd, &pos, *ptr, size);
 	if (rc != (ssize_t) size) {
 		printf("failed reading chunk\n");
Index: uspace/app/tester/hw/misc/virtchar1.c
===================================================================
--- uspace/app/tester/hw/misc/virtchar1.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/app/tester/hw/misc/virtchar1.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -45,6 +45,4 @@
 #include <vfs/vfs.h>
 #include <vfs/vfs_sess.h>
-#include <sys/stat.h>
-#include <fcntl.h>
 #include "../../tester.h"
 
@@ -56,5 +54,5 @@
 {
 	TPRINTF("Opening `%s'...\n", path);
-	int fd = open(path, O_RDONLY);
+	int fd = vfs_lookup(path, WALK_REGULAR);
 	if (fd < 0) {
 		TPRINTF("   ...error: %s\n", str_error(errno));
@@ -71,5 +69,5 @@
 	async_sess_t *sess = vfs_fd_session(fd, INTERFACE_DDF);
 	if (!sess) {
-		close(fd);
+		vfs_put(fd);
 		TPRINTF("   ...error: %s\n", str_error(errno));
 		return "Failed to get session to device";
@@ -92,5 +90,5 @@
 	TPRINTF(" Closing session and file descriptor\n");
 	async_hangup(sess);
-	close(fd);
+	vfs_put(fd);
 	
 	return NULL;
Index: uspace/app/tester/mm/pager1.c
===================================================================
--- uspace/app/tester/mm/pager1.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/app/tester/mm/pager1.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -28,6 +28,5 @@
 
 #include <stdio.h>
-#include <unistd.h>
-#include <fcntl.h>
+#include <vfs/vfs.h>
 #include <stdlib.h>
 #include <malloc.h>
@@ -48,10 +47,12 @@
 	TPRINTF("Creating temporary file...\n");
 
-	fd = open(TEST_FILE, O_CREAT);
+	fd = vfs_lookup_open(TEST_FILE, WALK_REGULAR | WALK_MAY_CREATE,
+	    MODE_READ | MODE_WRITE);
 	if (fd < 0)
 		return NULL;
-	(void) unlink(TEST_FILE);
-	if (write(fd, text, sizeof(text)) != sizeof(text)) {
-		close(fd);
+	(void) vfs_unlink_path(TEST_FILE);
+
+	if (vfs_write(fd, (aoff64_t []) {0}, text, sizeof(text)) < 0) {
+		vfs_put(fd);
 		return NULL;
 	}
@@ -64,5 +65,5 @@
 
 	if (!vfs_pager_sess) {
-		close(fd);
+		vfs_put(fd);
 		return NULL;
 	}
@@ -73,5 +74,5 @@
 	    AS_AREA_READ | AS_AREA_CACHEABLE, vfs_pager_sess, fd, 0, 0);
 	if (result == AS_MAP_FAILED) {
-		close(fd);
+		vfs_put(fd);
 		return NULL;
 	}
@@ -101,5 +102,5 @@
 
 	as_area_destroy(buffer);	
-	close(fd);
+	vfs_put(fd);
 	
 	return NULL;
Index: uspace/app/tester/vfs/vfs1.c
===================================================================
--- uspace/app/tester/vfs/vfs1.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/app/tester/vfs/vfs1.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -33,9 +33,7 @@
 #include <vfs/vfs.h>
 #include <unistd.h>
-#include <fcntl.h>
 #include <dirent.h>
 #include <loc.h>
 #include <sys/types.h>
-#include <sys/stat.h>
 #include "../tester.h"
 
@@ -70,28 +68,31 @@
 const char *test_vfs1(void)
 {
-	if (mkdir(TEST_DIRECTORY, 0) != 0) {
-		TPRINTF("rc=%d\n", errno);
-		return "mkdir() failed";
+	aoff64_t pos = 0;
+	int rc;
+
+	rc = vfs_link_path(TEST_DIRECTORY, KIND_DIRECTORY, NULL);
+	if (rc != EOK) {
+		TPRINTF("rc=%d\n", rc);
+		return "vfs_link_path() failed";
 	}
 	TPRINTF("Created directory %s\n", TEST_DIRECTORY);
 	
-	int fd0 = open(TEST_FILE, O_CREAT);
+	int fd0 = vfs_lookup_open(TEST_FILE, WALK_REGULAR | WALK_MAY_CREATE,
+	    MODE_READ | MODE_WRITE);
 	if (fd0 < 0)
-		return "open() failed";
+		return "vfs_lookup_open() failed";
 	TPRINTF("Created file %s (fd=%d)\n", TEST_FILE, fd0);
 	
 	size_t size = sizeof(text);
-	ssize_t cnt = write(fd0, text, size);
+	ssize_t cnt = vfs_write(fd0, &pos, text, size);
 	if (cnt < 0)
 		return "write() failed";
 	TPRINTF("Written %zd bytes\n", cnt);
-	
-	if (lseek(fd0, 0, SEEK_SET) != 0)
-		return "lseek() failed";
-	TPRINTF("Sought to position 0\n");
+
+	pos = 0;
 	
 	char buf[BUF_SIZE];
 	TPRINTF("read..\n");
-	while ((cnt = read(fd0, buf, BUF_SIZE))) {
+	while ((cnt = vfs_read(fd0, &pos, buf, BUF_SIZE))) {
 		TPRINTF("read returns %zd\n", cnt);
 		if (cnt < 0)
@@ -107,5 +108,5 @@
 	}
 	
-	close(fd0);
+	vfs_put(fd0);
 	
 	const char *rv = read_root();
@@ -113,14 +114,14 @@
 		return rv;
 	
-	if (rename(TEST_FILE, TEST_FILE2) != 0)
-		return "rename() failed";
+	if (vfs_rename_path(TEST_FILE, TEST_FILE2) != EOK)
+		return "vfs_rename_path() failed";
 	TPRINTF("Renamed %s to %s\n", TEST_FILE, TEST_FILE2);
 	
-	if (unlink(TEST_FILE2) != 0)
-		return "unlink() failed";
+	if (vfs_unlink_path(TEST_FILE2) != EOK)
+		return "vfs_unlink_path() failed";
 	TPRINTF("Unlinked %s\n", TEST_FILE2);
 	
-	if (rmdir(TEST_DIRECTORY) != 0)
-		return "rmdir() failed";
+	if (vfs_unlink_path(TEST_DIRECTORY) != EOK)
+		return "vfs_unlink_path() failed";
 	TPRINTF("Removed directory %s\n", TEST_DIRECTORY);
 	
Index: uspace/app/tetris/scores.c
===================================================================
--- uspace/app/tetris/scores.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/app/tetris/scores.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -65,5 +65,4 @@
 #include <vfs/vfs.h>
 #include <stdlib.h>
-#include <fcntl.h>
 #include <err.h>
 #include <time.h>
Index: uspace/app/trace/trace.c
===================================================================
--- uspace/app/trace/trace.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/app/trace/trace.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -512,6 +512,6 @@
 		goto error;
 
-	/* Send program pathname */
-	rc = loader_set_pathname(ldr, path);
+	/* Send program. */
+	rc = loader_set_program_path(ldr, path);
 	if (rc != EOK)
 		goto error;
@@ -523,30 +523,35 @@
 
 	/* Send default files */
-	int *files[4];
+	int fd_root;
 	int fd_stdin;
 	int fd_stdout;
 	int fd_stderr;
 	
-	if ((stdin != NULL) && (vfs_fhandle(stdin, &fd_stdin) == EOK))
-		files[0] = &fd_stdin;
-	else
-		files[0] = NULL;
-	
-	if ((stdout != NULL) && (vfs_fhandle(stdout, &fd_stdout) == EOK))
-		files[1] = &fd_stdout;
-	else
-		files[1] = NULL;
-	
-	if ((stderr != NULL) && (vfs_fhandle(stderr, &fd_stderr) == EOK))
-		files[2] = &fd_stderr;
-	else
-		files[2] = NULL;
-	
-	files[3] = NULL;
-	
-	rc = loader_set_files(ldr, files);
-	if (rc != EOK)
-		goto error;
-
+	fd_root = vfs_root();
+	if (fd_root >= 0) {
+		rc = loader_add_inbox(ldr, "root", fd_root);
+		vfs_put(fd_root);
+		if (rc != EOK)
+			goto error;
+	}
+	
+	if ((stdin != NULL) && (vfs_fhandle(stdin, &fd_stdin) == EOK)) {
+		rc = loader_add_inbox(ldr, "stdin", fd_stdin);
+		if (rc != EOK)
+			goto error;
+	}
+	
+	if ((stdout != NULL) && (vfs_fhandle(stdout, &fd_stdout) == EOK)) {
+		rc = loader_add_inbox(ldr, "stdout", fd_stdout);
+		if (rc != EOK)
+			goto error;
+	}
+	
+	if ((stderr != NULL) && (vfs_fhandle(stderr, &fd_stderr) == EOK)) {
+		rc = loader_add_inbox(ldr, "stderr", fd_stderr);
+		if (rc != EOK)
+			goto error;
+	}
+	
 	/* Load the program. */
 	rc = loader_load_program(ldr);
@@ -696,34 +701,30 @@
 
 	p = proto_new("vfs");
-	o = oper_new("open", 2, arg_def, V_INT_ERRNO, 0, resp_def);
-	proto_add_oper(p, VFS_IN_OPEN, o);
-	o = oper_new("read", 1, arg_def, V_ERRNO, 1, resp_def);
+	o = oper_new("read", 3, arg_def, V_ERRNO, 1, resp_def);
 	proto_add_oper(p, VFS_IN_READ, o);
-	o = oper_new("write", 1, arg_def, V_ERRNO, 1, resp_def);
+	o = oper_new("write", 3, arg_def, V_ERRNO, 1, resp_def);
 	proto_add_oper(p, VFS_IN_WRITE, o);
-	o = oper_new("seek", 3, arg_def, V_ERRNO, 0, resp_def);
-	proto_add_oper(p, VFS_IN_SEEK, o);
-	o = oper_new("truncate", 5, arg_def, V_ERRNO, 0, resp_def);
-	proto_add_oper(p, VFS_IN_TRUNCATE, o);
-	o = oper_new("fstat", 1, arg_def, V_ERRNO, 0, resp_def);
-	proto_add_oper(p, VFS_IN_FSTAT, o);
-	o = oper_new("close", 1, arg_def, V_ERRNO, 0, resp_def);
-	proto_add_oper(p, VFS_IN_CLOSE, o);
-	o = oper_new("mount", 2, arg_def, V_ERRNO, 0, resp_def);
+	o = oper_new("vfs_resize", 5, arg_def, V_ERRNO, 0, resp_def);
+	proto_add_oper(p, VFS_IN_RESIZE, o);
+	o = oper_new("vfs_stat", 1, arg_def, V_ERRNO, 0, resp_def);
+	proto_add_oper(p, VFS_IN_STAT, o);
+	o = oper_new("vfs_put", 1, arg_def, V_ERRNO, 0, resp_def);
+	proto_add_oper(p, VFS_IN_PUT, o);
+	o = oper_new("vfs_mount", 2, arg_def, V_ERRNO, 0, resp_def);
 	proto_add_oper(p, VFS_IN_MOUNT, o);
 /*	o = oper_new("unmount", 0, arg_def);
 	proto_add_oper(p, VFS_IN_UNMOUNT, o);*/
-	o = oper_new("sync", 1, arg_def, V_ERRNO, 0, resp_def);
+	o = oper_new("vfs_sync", 1, arg_def, V_ERRNO, 0, resp_def);
 	proto_add_oper(p, VFS_IN_SYNC, o);
-	o = oper_new("mkdir", 1, arg_def, V_ERRNO, 0, resp_def);
-	proto_add_oper(p, VFS_IN_MKDIR, o);
-	o = oper_new("unlink", 0, arg_def, V_ERRNO, 0, resp_def);
-	proto_add_oper(p, VFS_IN_UNLINK, o);
 	o = oper_new("rename", 0, arg_def, V_ERRNO, 0, resp_def);
 	proto_add_oper(p, VFS_IN_RENAME, o);
-	o = oper_new("stat", 0, arg_def, V_ERRNO, 0, resp_def);
-	proto_add_oper(p, VFS_IN_STAT, o);
-	o = oper_new("statfs", 0, arg_def, V_ERRNO, 0, resp_def);
+	o = oper_new("vfs_statfs", 0, arg_def, V_ERRNO, 0, resp_def);
 	proto_add_oper(p, VFS_IN_STATFS, o);
+	o = oper_new("vfs_walk", 2, arg_def, V_INT_ERRNO, 0, resp_def);
+	proto_add_oper(p, VFS_IN_WALK, o);
+	o = oper_new("vfs_open", 2, arg_def, V_ERRNO, 0, resp_def);
+	proto_add_oper(p, VFS_IN_OPEN, o);
+	o = oper_new("vfs_unlink", 3, arg_def, V_ERRNO, 0, resp_def);
+	proto_add_oper(p, VFS_IN_UNLINK, o);
 
 	proto_register(SERVICE_VFS, p);
Index: uspace/app/untar/main.c
===================================================================
--- uspace/app/untar/main.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/app/untar/main.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -35,7 +35,7 @@
 #include <stdio.h>
 #include <stdlib.h>
-#include <sys/stat.h>
 #include <errno.h>
 #include <str_error.h>
+#include <vfs/vfs.h>
 #include "tar.h"
 
@@ -103,9 +103,12 @@
 static int handle_directory(const tar_header_t *header, FILE *tarfile)
 {
-	if (mkdir(header->filename, 0755) != 0) {
-		if (errno != EEXIST) {
+	int rc;
+
+	rc = vfs_link_path(header->filename, KIND_DIRECTORY, NULL);
+	if (rc != EOK) {
+		if (rc != EEXIST) {
 			fprintf(stderr, "Failed to create directory %s: %s.\n",
-			    header->filename, str_error(errno));
-			return errno;
+			    header->filename, str_error(rc));
+			return rc;
 		}
 	}
Index: uspace/app/viewer/viewer.c
===================================================================
--- uspace/app/viewer/viewer.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/app/viewer/viewer.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -34,7 +34,6 @@
 
 #include <stdio.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/stat.h>
+#include <stdlib.h>
+#include <vfs/vfs.h>
 #include <errno.h>
 #include <malloc.h>
@@ -110,12 +109,12 @@
 static bool img_load(const char *fname, surface_t **p_local_surface)
 {
-	int fd = open(fname, O_RDONLY);
+	int fd = vfs_lookup_open(fname, WALK_REGULAR, MODE_READ);
 	if (fd < 0)
 		return false;
 	
 	struct stat stat;
-	int rc = fstat(fd, &stat);
-	if (rc != 0) {
-		close(fd);
+	int rc = vfs_stat(fd, &stat);
+	if (rc != EOK) {
+		vfs_put(fd);
 		return false;
 	}
@@ -123,16 +122,16 @@
 	void *tga = malloc(stat.size);
 	if (tga == NULL) {
-		close(fd);
-		return false;
-	}
-	
-	ssize_t rd = read(fd, tga, stat.size);
+		vfs_put(fd);
+		return false;
+	}
+
+	ssize_t rd = vfs_read(fd, (aoff64_t []) {0}, tga, stat.size);
 	if ((rd < 0) || (rd != (ssize_t) stat.size)) {
 		free(tga);
-		close(fd);
-		return false;
-	}
-	
-	close(fd);
+		vfs_put(fd);
+		return false;
+	}
+	
+	vfs_put(fd);
 	
 	*p_local_surface = decode_tga(tga, stat.size, 0);
Index: uspace/app/websrv/websrv.c
===================================================================
--- uspace/app/websrv/websrv.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/app/websrv/websrv.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -39,8 +39,8 @@
 #include <stdio.h>
 #include <sys/types.h>
-#include <sys/stat.h>
 #include <stdlib.h>
-#include <fcntl.h>
 #include <task.h>
+
+#include <vfs/vfs.h>
 
 #include <inet/addr.h>
@@ -225,5 +225,5 @@
 		return ENOMEM;
 	
-	int fd = open(fname, O_RDONLY);
+	int fd = vfs_lookup_open(fname, WALK_REGULAR, MODE_READ);
 	if (fd < 0) {
 		rc = send_response(conn, msg_not_found);
@@ -238,11 +238,12 @@
 		return rc;
 	
+	aoff64_t pos = 0;
 	while (true) {
-		ssize_t nr = read(fd, fbuf, BUFFER_SIZE);
+		ssize_t nr = vfs_read(fd, &pos, fbuf, BUFFER_SIZE);
 		if (nr == 0)
 			break;
 		
 		if (nr < 0) {
-			close(fd);
+			vfs_put(fd);
 			return EIO;
 		}
@@ -251,10 +252,10 @@
 		if (rc != EOK) {
 			fprintf(stderr, "tcp_conn_send() failed\n");
-			close(fd);
+			vfs_put(fd);
 			return rc;
 		}
 	}
 	
-	close(fd);
+	vfs_put(fd);
 	
 	return EOK;
Index: uspace/dist/src/c/demos/tetris/scores.c
===================================================================
--- uspace/dist/src/c/demos/tetris/scores.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/dist/src/c/demos/tetris/scores.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -65,5 +65,4 @@
 #include <vfs/vfs.h>
 #include <stdlib.h>
-#include <fcntl.h>
 #include <err.h>
 #include <time.h>
Index: uspace/drv/bus/isa/isa.c
===================================================================
--- uspace/drv/bus/isa/isa.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/drv/bus/isa/isa.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -51,8 +51,7 @@
 #include <malloc.h>
 #include <dirent.h>
-#include <fcntl.h>
 #include <ipc/irc.h>
 #include <ipc/services.h>
-#include <sys/stat.h>
+#include <vfs/vfs.h>
 #include <irc.h>
 #include <ns.h>
@@ -254,6 +253,7 @@
 	size_t len;
 	ssize_t r;
-
-	fd = open(conf_path, O_RDONLY);
+	struct stat st;
+
+	fd = vfs_lookup_open(conf_path, WALK_REGULAR, MODE_READ);
 	if (fd < 0) {
 		ddf_msg(LVL_ERROR, "Unable to open %s", conf_path);
@@ -263,6 +263,10 @@
 	opened = true;
 
-	len = lseek(fd, 0, SEEK_END);
-	lseek(fd, 0, SEEK_SET);
+	if (vfs_stat(fd, &st) != EOK) {
+		ddf_msg(LVL_ERROR, "Unable to vfs_stat %d", fd);
+		goto cleanup;
+	}
+
+	len = st.size;
 	if (len == 0) {
 		ddf_msg(LVL_ERROR, "Configuration file '%s' is empty.",
@@ -277,5 +281,5 @@
 	}
 
-	r = read(fd, buf, len);
+	r = vfs_read(fd, (aoff64_t []) {0}, buf, len);
 	if (r < 0) {
 		ddf_msg(LVL_ERROR, "Unable to read file '%s'.", conf_path);
@@ -294,5 +298,5 @@
 
 	if (opened)
-		close(fd);
+		vfs_put(fd);
 
 	return buf;
Index: uspace/drv/char/ns8250/ns8250.c
===================================================================
--- uspace/drv/char/ns8250/ns8250.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/drv/char/ns8250/ns8250.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -48,6 +48,4 @@
 #include <malloc.h>
 #include <dirent.h>
-#include <fcntl.h>
-#include <sys/stat.h>
 #include <ddi.h>
 
Index: uspace/lib/bithenge/src/failure.c
===================================================================
--- uspace/lib/bithenge/src/failure.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/lib/bithenge/src/failure.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -41,5 +41,4 @@
 #include <stdio.h>
 #include <stdlib.h>
-#include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/wait.h>
@@ -152,7 +151,7 @@
 		if (null == -1)
 			exit(127);
-		dup2(null, STDOUT_FILENO);
-		dup2(null, STDERR_FILENO);
-		close(null);
+		vfs_clone(null, STDOUT_FILENO, false);
+		vfs_clone(null, STDERR_FILENO, false);
+		vfs_put(null);
 		return 1;
 	}
Index: uspace/lib/bithenge/src/failure.h
===================================================================
--- uspace/lib/bithenge/src/failure.h	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/lib/bithenge/src/failure.h	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -42,5 +42,4 @@
 #include <stdio.h>
 #include <stdlib.h>
-#include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
Index: uspace/lib/bithenge/src/file.c
===================================================================
--- uspace/lib/bithenge/src/file.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/lib/bithenge/src/file.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -38,8 +38,7 @@
 #include <assert.h>
 #include <errno.h>
-#include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <sys/stat.h>
+#include <vfs/vfs.h>
 #include <sys/types.h>
 #include <unistd.h>
@@ -78,18 +77,9 @@
 	if (offset > blob->size)
 		return ELIMIT;
-	if (lseek(blob->fd, offset, SEEK_SET) < 0)
-		return errno == EINVAL ? EIO : errno;
 
-	ssize_t amount_read;
-	aoff64_t remaining_size = *size;
-	*size = 0;
-	do {
-		amount_read = read(blob->fd, buffer, remaining_size);
-		if (amount_read < 0)
-			return errno;
-		buffer += amount_read;
-		*size += amount_read;
-		remaining_size -= amount_read;
-	} while (remaining_size && amount_read);
+	ssize_t amount_read = vfs_read(blob->fd, &offset, buffer, *size);
+	if (amount_read < 0)
+		return errno;
+	*size += amount_read;
 	return EOK;
 }
@@ -98,5 +88,5 @@
 {
 	file_blob_t *blob = blob_as_file(base);
-	close(blob->fd);
+	vfs_put(blob->fd);
 	free(blob);
 }
@@ -113,8 +103,8 @@
 
 	struct stat stat;
-	int rc = fstat(fd, &stat);
-	if (rc != 0) {
+	int rc = vfs_stat(fd, &stat);
+	if (rc != EOK) {
 		if (needs_close)
-			close(fd);
+			vfs_put(fd);
 		return rc;
 	}
@@ -124,5 +114,5 @@
 	if (!blob) {
 		if (needs_close)
-			close(fd);
+			vfs_put(fd);
 		return ENOMEM;
 	}
@@ -131,5 +121,5 @@
 		free(blob);
 		if (needs_close)
-			close(fd);
+			vfs_put(fd);
 		return rc;
 	}
@@ -155,5 +145,5 @@
 	assert(filename);
 
-	int fd = open(filename, O_RDONLY);
+	int fd = vfs_lookup_open(filename, WALK_REGULAR, MODE_READ);
 	if (fd < 0)
 		return errno;
Index: uspace/lib/c/Makefile
===================================================================
--- uspace/lib/c/Makefile	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/lib/c/Makefile	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -73,4 +73,5 @@
 	generic/device/clock_dev.c \
 	generic/device/led_dev.c \
+	generic/dirent.c \
 	generic/dhcp.c \
 	generic/dnsr.c \
@@ -147,6 +148,8 @@
 	generic/stdlib.c \
 	generic/udebug.c \
+	generic/vfs/canonify.c \
+	generic/vfs/inbox.c \
+	generic/vfs/mtab.c \
 	generic/vfs/vfs.c \
-	generic/vfs/canonify.c \
 	generic/rcu.c \
 	generic/setjmp.c \
Index: uspace/lib/c/generic/dirent.c
===================================================================
--- uspace/lib/c/generic/dirent.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
+++ uspace/lib/c/generic/dirent.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2008 Jakub Jermar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libc
+ * @{
+ */
+/** @file
+ */
+
+#include <vfs/vfs.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <assert.h>
+
+/** Open directory.
+ *
+ * @param dirname Directory pathname
+ *
+ * @return Non-NULL pointer on success. On error returns @c NULL and sets errno.
+ */
+DIR *opendir(const char *dirname)
+{
+	DIR *dirp = malloc(sizeof(DIR));
+	if (!dirp) {
+		errno = ENOMEM;
+		return NULL;
+	}
+	
+	int fd = vfs_lookup(dirname, WALK_DIRECTORY);
+	if (fd < 0) {
+		free(dirp);
+		errno = fd;
+		return NULL;
+	}
+	
+	int rc = vfs_open(fd, MODE_READ);
+	if (rc < 0) {
+		free(dirp);
+		vfs_put(fd);
+		errno = rc;
+		return NULL;
+	}
+	
+	dirp->fd = fd;
+	dirp->pos = 0;
+	return dirp;
+}
+
+/** Read directory entry.
+ *
+ * @param dirp Open directory
+ * @return Non-NULL pointer to directory entry on success. On error returns
+ *         @c NULL and sets errno.
+ */
+struct dirent *readdir(DIR *dirp)
+{
+	int rc;
+	ssize_t len = 0;
+	
+	rc = vfs_read_short(dirp->fd, dirp->pos, &dirp->res.d_name[0],
+	    NAME_MAX + 1, &len);
+	if (rc != EOK) {
+		errno = rc;
+		return NULL;
+	}
+	
+	dirp->pos += len;
+	
+	return &dirp->res;
+}
+
+/** Rewind directory position to the beginning.
+ *
+ * @param dirp Open directory
+ */
+void rewinddir(DIR *dirp)
+{
+	dirp->pos = 0;
+}
+
+/** Close directory.
+ *
+ * @param dirp Open directory
+ * @return 0 on success. On error returns -1 and sets errno.
+ */
+int closedir(DIR *dirp)
+{
+	int rc;
+	
+	rc = vfs_put(dirp->fd);
+	free(dirp);
+
+	/* On error errno was set by close() */
+	return rc;
+}
+
+/** @}
+ */
Index: uspace/lib/c/generic/elf/elf_load.c
===================================================================
--- uspace/lib/c/generic/elf/elf_load.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/lib/c/generic/elf/elf_load.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -41,4 +41,5 @@
 #include <stdio.h>
 #include <stdlib.h>
+#include <vfs/vfs.h>
 
 #ifdef CONFIG_RTLD
@@ -50,9 +51,9 @@
 /** Load ELF program.
  *
- * @param file_name File name
+ * @param file File handle 
  * @param info Place to store ELF program information
  * @return EOK on success or non-zero error code
  */
-int elf_load(const char *file_name, elf_info_t *info)
+int elf_load(int file, elf_info_t *info)
 {
 #ifdef CONFIG_RTLD
@@ -61,5 +62,5 @@
 	int rc;
 
-	rc = elf_load_file(file_name, 0, 0, &info->finfo);
+	rc = elf_load_file(file, 0, 0, &info->finfo);
 	if (rc != EE_OK) {
 		DPRINTF("Failed to load executable '%s'.\n", file_name);
Index: uspace/lib/c/generic/elf/elf_mod.c
===================================================================
--- uspace/lib/c/generic/elf/elf_mod.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/lib/c/generic/elf/elf_mod.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -44,5 +44,7 @@
  */
 
+#include <errno.h>
 #include <stdio.h>
+#include <vfs/vfs.h>
 #include <sys/types.h>
 #include <align.h>
@@ -50,9 +52,9 @@
 #include <as.h>
 #include <elf/elf.h>
-#include <unistd.h>
-#include <fcntl.h>
 #include <smc.h>
 #include <loader/pcb.h>
 #include <entry_point.h>
+#include <str_error.h>
+#include <stdlib.h>
 
 #include <elf/elf_load.h>
@@ -82,5 +84,5 @@
  * pointed to by @a info.
  *
- * @param file_name Path to the ELF file.
+ * @param file      ELF file.
  * @param so_bias   Bias to use if the file is a shared object.
  * @param info      Pointer to a structure for storing information
@@ -90,19 +92,15 @@
  *
  */
-int elf_load_file(const char *file_name, size_t so_bias, eld_flags_t flags,
-    elf_finfo_t *info)
+int elf_load_file(int file, size_t so_bias, eld_flags_t flags, elf_finfo_t *info)
 {
 	elf_ld_t elf;
 
-	int fd;
-	int rc;
-
-	fd = open(file_name, O_RDONLY);
-	if (fd < 0) {
-		DPRINTF("failed opening file\n");
-		return -1;
-	}
-
-	elf.fd = fd;
+	int ofile = vfs_clone(file, -1, true);
+	int rc = vfs_open(ofile, MODE_READ);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	elf.fd = ofile;
 	elf.info = info;
 	elf.flags = flags;
@@ -110,6 +108,14 @@
 	rc = elf_load_module(&elf, so_bias);
 
-	close(fd);
-
+	vfs_put(ofile);
+	return rc;
+}
+
+int elf_load_file_name(const char *path, size_t so_bias, eld_flags_t flags,
+    elf_finfo_t *info)
+{
+	int file = vfs_lookup(path, 0);
+	int rc = elf_load_file(file, so_bias, flags, info);
+	vfs_put(file);
 	return rc;
 }
@@ -129,7 +135,8 @@
 	elf_header_t header_buf;
 	elf_header_t *header = &header_buf;
+	aoff64_t pos = 0;
 	int i, rc;
 
-	rc = read(elf->fd, header, sizeof(elf_header_t));
+	rc = vfs_read(elf->fd, &pos, header, sizeof(elf_header_t));
 	if (rc != sizeof(elf_header_t)) {
 		DPRINTF("Read error.\n"); 
@@ -189,9 +196,6 @@
 		elf_segment_header_t segment_hdr;
 
-		/* Seek to start of segment header */
-		lseek(elf->fd, header->e_phoff
-		        + i * sizeof(elf_segment_header_t), SEEK_SET);
-
-		rc = read(elf->fd, &segment_hdr,
+		pos = header->e_phoff + i * sizeof(elf_segment_header_t);
+		rc = vfs_read(elf->fd, &pos, &segment_hdr,
 		    sizeof(elf_segment_header_t));
 		if (rc != sizeof(elf_segment_header_t)) {
@@ -211,9 +215,6 @@
 		elf_section_header_t section_hdr;
 
-		/* Seek to start of section header */
-		lseek(elf->fd, header->e_shoff
-		    + i * sizeof(elf_section_header_t), SEEK_SET);
-
-		rc = read(elf->fd, &section_hdr,
+		pos = header->e_shoff + i * sizeof(elf_section_header_t);
+		rc = vfs_read(elf->fd, &pos, &section_hdr,
 		    sizeof(elf_section_header_t));
 		if (rc != sizeof(elf_section_header_t)) {
@@ -327,4 +328,5 @@
 	uintptr_t seg_addr;
 	size_t mem_sz;
+	aoff64_t pos;
 	ssize_t rc;
 
@@ -384,34 +386,9 @@
 	 * Load segment data
 	 */
-	rc = lseek(elf->fd, entry->p_offset, SEEK_SET);
+	pos = entry->p_offset;
+	rc = vfs_read(elf->fd, &pos, seg_ptr, entry->p_filesz);
 	if (rc < 0) {
-		printf("seek error\n");
+		DPRINTF("read error\n");
 		return EE_INVALID;
-	}
-
-/*	rc = read(fd, (void *)(entry->p_vaddr + bias), entry->p_filesz);
-	if (rc < 0) { printf("read error\n"); return EE_INVALID; }*/
-
-	/* Long reads are not possible yet. Load segment piecewise. */
-
-	unsigned left, now;
-	uint8_t *dp;
-
-	left = entry->p_filesz;
-	dp = seg_ptr;
-
-	while (left > 0) {
-		now = 16384;
-		if (now > left) now = left;
-
-		rc = read(elf->fd, dp, now);
-
-		if (rc != (ssize_t) now) { 
-			DPRINTF("Read error.\n");
-			return EE_INVALID;
-		}
-
-		left -= now;
-		dp += now;
 	}
 
Index: uspace/lib/c/generic/io/io.c
===================================================================
--- uspace/lib/c/generic/io/io.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/lib/c/generic/io/io.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -35,5 +35,4 @@
 #include <stdio.h>
 #include <unistd.h>
-#include <fcntl.h>
 #include <assert.h>
 #include <str.h>
@@ -45,4 +44,5 @@
 #include <vfs/vfs.h>
 #include <vfs/vfs_sess.h>
+#include <vfs/inbox.h>
 #include <ipc/loc.h>
 #include <adt/list.h>
@@ -55,4 +55,5 @@
 static FILE stdin_null = {
 	.fd = -1,
+	.pos = 0, 
 	.error = true,
 	.eof = true,
@@ -69,4 +70,5 @@
 static FILE stdout_kio = {
 	.fd = -1,
+	.pos = 0, 
 	.error = false,
 	.eof = false,
@@ -83,4 +85,5 @@
 static FILE stderr_kio = {
 	.fd = -1,
+	.pos = 0, 
 	.error = false,
 	.eof = false,
@@ -101,8 +104,16 @@
 static LIST_INITIALIZE(files);
 
-void __stdio_init(int filc)
-{
-	if (filc > 0) {
-		stdin = fdopen(0, "r");
+void __stdio_init(void)
+{
+	/* The first three standard file descriptors are assigned for compatibility.
+	 * This will probably be removed later.
+	 */
+	 
+	int infd = inbox_get("stdin");
+	if (infd >= 0) {
+		int stdinfd = vfs_clone(infd, -1, false);
+		assert(stdinfd == 0);
+		vfs_open(stdinfd, MODE_READ);
+		stdin = fdopen(stdinfd, "r");
 	} else {
 		stdin = &stdin_null;
@@ -110,6 +121,12 @@
 	}
 	
-	if (filc > 1) {
-		stdout = fdopen(1, "w");
+	int outfd = inbox_get("stdout");
+	if (outfd >= 0) {
+		int stdoutfd = vfs_clone(outfd, -1, false);
+		assert(stdoutfd <= 1);
+		while (stdoutfd < 1)
+			stdoutfd = vfs_clone(outfd, -1, false);
+		vfs_open(stdoutfd, MODE_APPEND);
+		stdout = fdopen(stdoutfd, "a");
 	} else {
 		stdout = &stdout_kio;
@@ -117,6 +134,12 @@
 	}
 	
-	if (filc > 2) {
-		stderr = fdopen(2, "w");
+	int errfd = inbox_get("stderr");
+	if (errfd >= 0) {
+		int stderrfd = vfs_clone(errfd, -1, false);
+		assert(stderrfd <= 2);
+		while (stderrfd < 2)
+			stderrfd = vfs_clone(errfd, -1, false);
+		vfs_open(stderrfd, MODE_APPEND);
+		stderr = fdopen(stderrfd, "a");
 	} else {
 		stderr = &stderr_kio;
@@ -133,8 +156,8 @@
 }
 
-static bool parse_mode(const char *mode, int *flags)
+static bool parse_mode(const char *fmode, int *mode, bool *create, bool *truncate)
 {
 	/* Parse mode except first character. */
-	const char *mp = mode;
+	const char *mp = fmode;
 	if (*mp++ == 0) {
 		errno = EINVAL;
@@ -156,12 +179,18 @@
 		return false;
 	}
-	
-	/* Parse first character of mode and determine flags for open(). */
-	switch (mode[0]) {
+
+	*create = false;
+	*truncate = false;
+	
+	/* Parse first character of fmode and determine mode for vfs_open(). */
+	switch (fmode[0]) {
 	case 'r':
-		*flags = plus ? O_RDWR : O_RDONLY;
+		*mode = plus ? MODE_READ | MODE_WRITE : MODE_READ;
 		break;
 	case 'w':
-		*flags = (O_TRUNC | O_CREAT) | (plus ? O_RDWR : O_WRONLY);
+		*mode = plus ? MODE_READ | MODE_WRITE : MODE_WRITE;
+		*create = true;
+		if (!plus)
+			*truncate = true;
 		break;
 	case 'a':
@@ -171,5 +200,7 @@
 			return false;
 		}
-		*flags = (O_APPEND | O_CREAT) | (plus ? O_RDWR : O_WRONLY);
+
+		*mode = MODE_APPEND | (plus ? MODE_READ | MODE_WRITE : MODE_WRITE);
+		*create = true;
 		break;
 	default:
@@ -245,8 +276,11 @@
  *
  */
-FILE *fopen(const char *path, const char *mode)
-{
-	int flags;
-	if (!parse_mode(mode, &flags))
+FILE *fopen(const char *path, const char *fmode)
+{
+	int mode;
+	bool create;
+	bool truncate;
+
+	if (!parse_mode(fmode, &mode, &create, &truncate))
 		return NULL;
 	
@@ -257,12 +291,35 @@
 		return NULL;
 	}
-	
-	stream->fd = open(path, flags, 0666);
-	if (stream->fd < 0) {
-		/* errno was set by open() */
+
+	int flags = WALK_REGULAR;
+	if (create)
+		flags |= WALK_MAY_CREATE;
+	int file = vfs_lookup(path, flags);
+	if (file < 0) {
+		errno = file;
 		free(stream);
 		return NULL;
 	}
-	
+
+	int rc = vfs_open(file, mode);
+	if (rc != EOK) {
+		errno = rc;
+		vfs_put(file);
+		free(stream);
+		return NULL;
+	}
+	
+	if (truncate) {
+		rc = vfs_resize(file, 0);
+		if (rc != EOK) {
+			errno = rc;
+			vfs_put(file);
+			free(stream);
+			return NULL;
+		}
+	}
+
+	stream->fd = file;
+	stream->pos = 0;
 	stream->error = false;
 	stream->eof = false;
@@ -288,4 +345,5 @@
 	
 	stream->fd = fd;
+	stream->pos = 0;
 	stream->error = false;
 	stream->eof = false;
@@ -312,5 +370,5 @@
 	
 	if (stream->fd >= 0)
-		rc = close(stream->fd);
+		rc = vfs_put(stream->fd);
 	
 	list_remove(&stream->link);
@@ -373,27 +431,17 @@
 static size_t _fread(void *buf, size_t size, size_t nmemb, FILE *stream)
 {
-	size_t left, done;
-
 	if (size == 0 || nmemb == 0)
 		return 0;
 
-	left = size * nmemb;
-	done = 0;
-	
-	while ((left > 0) && (!stream->error) && (!stream->eof)) {
-		ssize_t rd = read(stream->fd, buf + done, left);
-		
-		if (rd < 0) {
-			/* errno was set by read() */
-			stream->error = true;
-		} else if (rd == 0) {
-			stream->eof = true;
-		} else {
-			left -= rd;
-			done += rd;
-		}
-	}
-	
-	return (done / size);
+	ssize_t rd = vfs_read(stream->fd, &stream->pos, buf, size * nmemb);
+	if (rd < 0) {
+		errno = rd;
+		stream->error = true;
+		rd = 0;
+	} else if (rd == 0) {
+		stream->eof = true;
+	}
+	
+	return (rd / size);
 }
 
@@ -410,48 +458,30 @@
 static size_t _fwrite(const void *buf, size_t size, size_t nmemb, FILE *stream)
 {
-	size_t left;
-	size_t done;
-	int rc;
-
 	if (size == 0 || nmemb == 0)
 		return 0;
 
-	left = size * nmemb;
-	done = 0;
-
-	while ((left > 0) && (!stream->error)) {
-		ssize_t wr;
-		size_t uwr;
-		
-		if (stream->kio) {
-			uwr = 0;
-			rc = kio_write(buf + done, left, &uwr);
-			if (rc != EOK)
-				errno = rc;
+	ssize_t wr;
+	if (stream->kio) {
+		size_t nwritten;
+		wr = kio_write(buf, size * nmemb, &nwritten);
+		if (wr != EOK) {
+			stream->error = true;
+			wr = 0;
 		} else {
-			wr = write(stream->fd, buf + done, left);
-			if (wr >= 0) {
-				uwr = (size_t)wr;
-				rc = EOK;
-			} else {
-				/* errno was set by write */
-				uwr = 0;
-				rc = errno;
-			}
+			wr = nwritten;
 		}
-		
-		if (rc != EOK) {
-			/* errno was set above */
+	} else {
+		wr = vfs_write(stream->fd, &stream->pos, buf, size * nmemb);
+		if (wr < 0) {
+			errno = wr;
 			stream->error = true;
-		} else {
-			left -= uwr;
-			done += uwr;
+			wr = 0;
 		}
 	}
 
-	if (done > 0)
+	if (wr > 0)
 		stream->need_sync = true;
 	
-	return (done / size);
+	return (wr / size);
 }
 
@@ -466,7 +496,7 @@
 	stream->buf_head = stream->buf_tail = stream->buf;
 
-	rc = read(stream->fd, stream->buf, stream->buf_size);
+	rc = vfs_read(stream->fd, &stream->pos, stream->buf, stream->buf_size);
 	if (rc < 0) {
-		/* errno was set by read() */
+		errno = rc;
 		stream->error = true;
 		return;
@@ -493,13 +523,6 @@
 
 	/* If buffer has prefetched read data, we need to seek back. */
-	if (bytes_used > 0 && stream->buf_state == _bs_read) {
-		off64_t rc;
-		rc = lseek(stream->fd, - (ssize_t) bytes_used, SEEK_CUR);
-		if (rc == (off64_t)-1) {
-			/* errno was set by lseek */
-			stream->error = 1;
-			return;
-		}
-	}
+	if (bytes_used > 0 && stream->buf_state == _bs_read)
+		stream->pos -= bytes_used;
 
 	/* If buffer has unwritten data, we need to write them out. */
@@ -773,21 +796,34 @@
 int fseek(FILE *stream, off64_t offset, int whence)
 {
-	off64_t rc;
+	int rc;
 
 	if (stream->error)
-		return EOF;
+		return -1;
 
 	_fflushbuf(stream);
 	if (stream->error) {
 		/* errno was set by _fflushbuf() */
-		return EOF;
+		return -1;
 	}
 
 	stream->ungetc_chars = 0;
 
-	rc = lseek(stream->fd, offset, whence);
-	if (rc == (off64_t) (-1)) {
-		/* errno has been set by lseek() */
-		return EOF;
+	struct stat st;
+	switch (whence) {
+	case SEEK_SET:
+		stream->pos = offset;
+		break;
+	case SEEK_CUR:
+		stream->pos += offset;
+		break;
+	case SEEK_END:
+		rc = vfs_stat(stream->fd, &st);
+		if (rc != EOK) {
+			errno = rc;
+			stream->error = true;
+			return -1;	
+		}
+		stream->pos = st.size + offset;
+		break;
 	}
 
@@ -798,6 +834,8 @@
 off64_t ftell(FILE *stream)
 {
-	off64_t pos;
-	
+	/* The native position is too large for the C99-ish interface. */
+	if (stream->pos - stream->ungetc_chars > INT64_MAX)
+		return EOF;
+
 	if (stream->error)
 		return EOF;
@@ -809,11 +847,5 @@
 	}
 
-	pos = lseek(stream->fd, 0, SEEK_CUR);
-	if (pos == (off64_t) -1) {
-		/* errno was set by lseek */
-		return (off64_t) -1;
-	}
-	
-	return pos - stream->ungetc_chars;
+	return stream->pos - stream->ungetc_chars;
 }
 
@@ -840,4 +872,6 @@
 	
 	if ((stream->fd >= 0) && (stream->need_sync)) {
+		int rc;
+
 		/**
 		 * Better than syncing always, but probably still not the
@@ -845,6 +879,7 @@
 		 */
 		stream->need_sync = false;
-		if (fsync(stream->fd) != 0) {
-			/* errno was set by fsync() */
+		rc = vfs_sync(stream->fd);
+		if (rc != EOK) {
+			errno = rc;
 			return EOF;
 		}
Index: uspace/lib/c/generic/io/logctl.c
===================================================================
--- uspace/lib/c/generic/io/logctl.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/lib/c/generic/io/logctl.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -39,4 +39,5 @@
 #include <ns.h>
 #include <str.h>
+#include <vfs/vfs.h>
 
 /** IPC session with the logger service. */
@@ -122,4 +123,30 @@
 }
 
+/** Set logger's VFS root.
+ *
+ * @return Error code or EOK on success.
+ */
+int logctl_set_root(void)
+{
+	async_exch_t *exchange = NULL;
+	int rc = start_logger_exchange(&exchange);
+	if (rc != EOK)
+		return rc;
+
+	aid_t reg_msg = async_send_0(exchange, LOGGER_CONTROL_SET_ROOT, NULL);
+	async_exch_t *vfs_exch = vfs_exchange_begin();
+	rc = vfs_pass_handle(vfs_exch, vfs_root(), exchange);
+	vfs_exchange_end(vfs_exch);
+	sysarg_t reg_msg_rc;
+	async_wait_for(reg_msg, &reg_msg_rc);
+
+	async_exchange_end(exchange);
+
+	if (rc != EOK)
+		return rc;
+
+	return (int) reg_msg_rc;
+}
+
 /** @}
  */
Index: uspace/lib/c/generic/libc.c
===================================================================
--- uspace/lib/c/generic/libc.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/lib/c/generic/libc.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -48,4 +48,6 @@
 #include <task.h>
 #include <loader/pcb.h>
+#include <vfs/vfs.h>
+#include <vfs/inbox.h>
 #include "private/libc.h"
 #include "private/async.h"
@@ -107,10 +109,12 @@
 		argc = 0;
 		argv = NULL;
-		__stdio_init(0);
+		__stdio_init();
 	} else {
 		argc = __pcb->argc;
 		argv = __pcb->argv;
-		__stdio_init(__pcb->filc);
-		(void) chdir(__pcb->cwd);
+		__inbox_init(__pcb->inbox, __pcb->inbox_entries);
+		__stdio_init();
+		vfs_root_set(inbox_get("root"));
+		(void) vfs_cwd_set(__pcb->cwd);
 	}
 	
Index: uspace/lib/c/generic/loader.c
===================================================================
--- uspace/lib/c/generic/loader.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/lib/c/generic/loader.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -124,5 +124,5 @@
 		return ENOMEM;
 	
-	if (getcwd(cwd, MAX_PATH_LEN + 1) == NULL)
+	if (vfs_cwd_get(cwd, MAX_PATH_LEN + 1) != EOK)
 		str_cpy(cwd, MAX_PATH_LEN + 1, "/");
 	
@@ -147,41 +147,65 @@
 }
 
-/** Set pathname of the program to load.
- *
- * Sets the name of the program file to load. The name can be relative
- * to the current working directory (it will be absolutized before
- * sending to the loader).
+/** Set the program to load.
  *
  * @param ldr  Loader connection structure.
- * @param path Pathname of the program file.
- *
- * @return Zero on success or negative error code.
- *
- */
-int loader_set_pathname(loader_t *ldr, const char *path)
-{
-	size_t pa_len;
-	char *pa = vfs_absolutize(path, &pa_len);
-	if (!pa)
-		return ENOMEM;
-	
-	/* Send program pathname */
-	async_exch_t *exch = async_exchange_begin(ldr->sess);
-	
+ * @param name Name to set for the spawned program.
+ * @param file Program file.
+ *
+ * @return Zero on success or negative error code.
+ *
+ */
+int loader_set_program(loader_t *ldr, const char *name, int file)
+{
+	async_exch_t *exch = async_exchange_begin(ldr->sess);
+
 	ipc_call_t answer;
-	aid_t req = async_send_0(exch, LOADER_SET_PATHNAME, &answer);
-	sysarg_t rc = async_data_write_start(exch, (void *) pa, pa_len);
-	
-	async_exchange_end(exch);
-	free(pa);
-	
+	aid_t req = async_send_0(exch, LOADER_SET_PROGRAM, &answer);
+
+	sysarg_t rc = async_data_write_start(exch, name, str_size(name) + 1);
+	if (rc == EOK) {
+		async_exch_t *vfs_exch = vfs_exchange_begin();
+		rc = vfs_pass_handle(vfs_exch, file, exch);
+		vfs_exchange_end(vfs_exch);
+	}
+
+	async_exchange_end(exch);
+
 	if (rc != EOK) {
 		async_forget(req);
 		return (int) rc;
 	}
-	
+
 	async_wait_for(req, &rc);
 	return (int) rc;
 }
+
+/** Set the program to load by path.
+ *
+ * @param ldr  Loader connection structure.
+ * @param path Program path.
+ *
+ * @return Zero on success or negative error code.
+ *
+ */
+int loader_set_program_path(loader_t *ldr, const char *path)
+{
+	const char *name = str_rchr(path, '/');
+	if (name == NULL) {
+		name = path;
+	} else {
+		name++;
+	}
+	
+	int fd = vfs_lookup(path, 0);
+	if (fd < 0) {
+		return fd;
+	}
+	
+	int rc = loader_set_program(ldr, name, fd);
+	vfs_put(fd);
+	return rc;
+}
+
 
 /** Set command-line arguments for the program.
@@ -244,46 +268,34 @@
 }
 
-/** Set preset files for the program.
- *
- * Sets the vector of preset files to be passed to the loaded
- * program. By convention, the first three files represent stdin,
- * stdout and stderr respectively.
- *
- * @param ldr   Loader connection structure.
- * @param files NULL-terminated array of pointers to files.
- *
- * @return Zero on success or negative error code.
- *
- */
-int loader_set_files(loader_t *ldr, int * const files[])
-{
-	/* Send serialized files to the loader */
+/** Add a file to the task's inbox.
+ *
+ * @param ldr        Loader connection structure.
+ * @param name       Identification of the file.
+ * @param file       The file's descriptor.
+ *
+ * @return Zero on success or negative error code.
+ *
+ */
+int loader_add_inbox(loader_t *ldr, const char *name, int file)
+{
 	async_exch_t *exch = async_exchange_begin(ldr->sess);
 	async_exch_t *vfs_exch = vfs_exchange_begin();
 	
-	int i;
-	for (i = 0; files[i]; i++);
-
-	ipc_call_t answer;
-	aid_t req = async_send_1(exch, LOADER_SET_FILES, i, &answer);
-
-	sysarg_t rc = EOK;
-	
-	for (i = 0; files[i]; i++) {
-		rc = async_state_change_start(exch, VFS_PASS_HANDLE, *files[i],
-		    0, vfs_exch); 
-		if (rc != EOK)
-			break;
-	}
-	
-	vfs_exchange_end(vfs_exch);
-	async_exchange_end(exch);
-
-	if (rc != EOK) {
-		async_forget(req);
-		return (int) rc;
-	}
-	
-	async_wait_for(req, &rc);
+	aid_t req = async_send_0(exch, LOADER_ADD_INBOX, NULL);
+	
+	sysarg_t rc = async_data_write_start(exch, name, str_size(name) + 1);
+	if (rc == EOK) {
+		rc = vfs_pass_handle(vfs_exch, file, exch);
+	}
+	
+	async_exchange_end(vfs_exch);
+	async_exchange_end(exch);
+	
+	if (rc == EOK) {
+		async_wait_for(req, &rc);
+	} else {
+		async_forget(req);
+	}
+	
 	return (int) rc;
 }
Index: uspace/lib/c/generic/private/io.h
===================================================================
--- uspace/lib/c/generic/private/io.h	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/lib/c/generic/private/io.h	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -36,6 +36,10 @@
 #define LIBC_PRIVATE_IO_H_
 
-extern void __stdio_init(int);
+#include <loader/pcb.h>
+
+extern void __stdio_init(void);
 extern void __stdio_done(void);
+
+extern void __inbox_init(struct pcb_inbox_entry *entries, int count);
 
 #endif
Index: uspace/lib/c/generic/private/stdio.h
===================================================================
--- uspace/lib/c/generic/private/stdio.h	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/lib/c/generic/private/stdio.h	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -49,4 +49,7 @@
 	/** Underlying file descriptor. */
 	int fd;
+
+	/** File position. */
+	aoff64_t pos;
 	
 	/** Error indicator. */
Index: uspace/lib/c/generic/rtld/module.c
===================================================================
--- uspace/lib/c/generic/rtld/module.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/lib/c/generic/rtld/module.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -38,5 +38,4 @@
 #include <elf/elf_load.h>
 #include <errno.h>
-#include <fcntl.h>
 #include <loader/pcb.h>
 #include <stdio.h>
@@ -196,5 +195,5 @@
 	DPRINTF("load '%s' at 0x%x\n", name_buf, m->bias);
 
-	rc = elf_load_file(name_buf, m->bias, ELDF_RW, &info);
+	rc = elf_load_file_name(name_buf, m->bias, ELDF_RW, &info);
 	if (rc != EE_OK) {
 		printf("Failed to load '%s'\n", name_buf);
Index: uspace/lib/c/generic/task.c
===================================================================
--- uspace/lib/c/generic/task.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/lib/c/generic/task.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -48,4 +48,5 @@
 #include "private/ns.h"
 #include <vfs/vfs.h>
+#include <unistd.h>
 
 task_id_t task_get_id(void)
@@ -107,27 +108,23 @@
 {
 	/* Send default files */
-	int *files[4];
-	int fd_stdin;
-	int fd_stdout;
-	int fd_stderr;
-	
-	if ((stdin != NULL) && (vfs_fhandle(stdin, &fd_stdin) == EOK))
-		files[0] = &fd_stdin;
-	else
-		files[0] = NULL;
-	
-	if ((stdout != NULL) && (vfs_fhandle(stdout, &fd_stdout) == EOK))
-		files[1] = &fd_stdout;
-	else
-		files[1] = NULL;
-	
-	if ((stderr != NULL) && (vfs_fhandle(stderr, &fd_stderr) == EOK))
-		files[2] = &fd_stderr;
-	else
-		files[2] = NULL;
-	
-	files[3] = NULL;
-	
-	return task_spawnvf(id, wait, path, args, files);
+	
+	int fd_stdin = -1;
+	int fd_stdout = -1;
+	int fd_stderr = -1;
+	
+	if (stdin != NULL) {
+		(void) vfs_fhandle(stdin, &fd_stdin);
+	}
+	
+	if (stdout != NULL) {
+		(void) vfs_fhandle(stdout, &fd_stdout);
+	}
+
+	if (stderr != NULL) {
+		(void) vfs_fhandle(stderr, &fd_stderr);
+	}
+	
+	return task_spawnvf(id, wait, path, args, fd_stdin, fd_stdout,
+	    fd_stderr);
 }
 
@@ -138,10 +135,11 @@
  * Files are passed as null-terminated array of pointers to fdi_node_t.
  *
- * @param id    If not NULL, the ID of the task is stored here on success.
- * @param wait  If not NULL, setup waiting for task's return value and store
- *              the information necessary for waiting here on success.
- * @param path  Pathname of the binary to execute.
- * @param argv  Command-line arguments.
- * @param files Standard files to use.
+ * @param id      If not NULL, the ID of the task is stored here on success.
+ * @param wait    If not NULL, setup waiting for task's return value and store
+ * @param path    Pathname of the binary to execute.
+ * @param argv    Command-line arguments.
+ * @param std_in  File to use as stdin.
+ * @param std_out File to use as stdout.
+ * @param std_err File to use as stderr.
  *
  * @return Zero on success or negative error code.
@@ -149,5 +147,5 @@
  */
 int task_spawnvf(task_id_t *id, task_wait_t *wait, const char *path,
-    const char *const args[], int *const files[])
+    const char *const args[], int fd_stdin, int fd_stdout, int fd_stderr)
 {
 	/* Connect to a program loader. */
@@ -169,6 +167,6 @@
 		goto error;
 	
-	/* Send program pathname. */
-	rc = loader_set_pathname(ldr, path);
+	/* Send program binary. */
+	rc = loader_set_program_path(ldr, path);
 	if (rc != EOK)
 		goto error;
@@ -180,7 +178,29 @@
 	
 	/* Send files */
-	rc = loader_set_files(ldr, files);
-	if (rc != EOK)
-		goto error;
+	int root = vfs_root();
+	if (root >= 0) {
+		rc = loader_add_inbox(ldr, "root", root);
+		vfs_put(root);
+		if (rc != EOK)
+			goto error;
+	}
+	
+	if (fd_stdin >= 0) {
+		rc = loader_add_inbox(ldr, "stdin", fd_stdin);
+		if (rc != EOK)
+			goto error;
+	}
+	
+	if (fd_stdout >= 0) {
+		rc = loader_add_inbox(ldr, "stdout", fd_stdout);
+		if (rc != EOK)
+			goto error;
+	}
+	
+	if (fd_stderr >= 0) {
+		rc = loader_add_inbox(ldr, "stderr", fd_stderr);
+		if (rc != EOK)
+			goto error;
+	}		
 	
 	/* Load the program. */
Index: uspace/lib/c/generic/vfs/inbox.c
===================================================================
--- uspace/lib/c/generic/vfs/inbox.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
+++ uspace/lib/c/generic/vfs/inbox.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2013 Jiri Zarevucky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libc 
+ * @{
+ */ 
+
+/**
+ * @file
+ * @brief
+ */
+
+#include <vfs/inbox.h>
+#include <vfs/vfs.h>
+
+#include <adt/list.h>
+#include <str.h>
+#include <stdlib.h>
+#include <loader/pcb.h>
+#include "../private/io.h"
+#include <errno.h>
+
+/*
+ * This is an attempt at generalization of the "standard files" concept to
+ * arbitrary names.  When loading a task, the parent can put arbitrary files to
+ * an "inbox" through IPC calls, every file in an inbox has a name assigned
+ * (e.g. "stdin", "stdout", "stderr", "data", "logfile", etc.). The client then
+ * retrieves those files from inbox by name. "stdin", "stdout" and "stderr" are
+ * handled automatically by libc to initialize standard <stdio.h> streams and
+ * legacy file descriptors 0, 1, 2. Other names are subject to conventions and
+ * application-specific rules.
+ */
+
+typedef struct {
+	link_t link;
+	char *name;
+	int file;
+} inbox_entry;
+
+static LIST_INITIALIZE(inb_list);
+
+/* Inserts a named file into the inbox.
+ *
+ * If a file with the same name is already present, it overwrites it and returns
+ * the original value. Otherwise, it returns -1.  If the argument 'file' is -1,
+ * nothing is inserted and the file with specified name is removed and returned
+ * if present.
+ *
+ * @param name Name of the inbox entry.
+ * @param file File to insert or -1.
+ * @return Original value of the entry or -1 if not originally present.
+ */
+int inbox_set(const char *name, int file)
+{
+	inbox_entry *next = NULL;
+	
+	list_foreach(inb_list, link, inbox_entry, e) {
+		int cmp = str_cmp(e->name, name);
+		switch (cmp) {
+		case -1:
+			continue;
+		case 0:;
+			int result = e->file;
+			if (file == -1) {
+				free(e->name);
+				/* Safe because we exit immediately. */
+				list_remove(&e->link);
+			} else {
+				e->file = file;
+			}
+			return result;
+		case 1:
+			next = e;
+			goto out;
+		}
+	}
+
+out:
+	if (file == -1)
+		return -1;
+
+	inbox_entry *entry = calloc(sizeof(inbox_entry), 1);
+	entry->name = str_dup(name);
+	entry->file = file;
+
+	if (next == NULL) {
+		list_append((link_t *)entry, &inb_list);
+	} else {
+		list_insert_before((link_t *)entry, (link_t *)next);
+	}
+	return -1;
+}
+
+/* Retrieve a file with this name.
+ *
+ * @param name Name of the entry.
+ * @return Requested file or ENOENT if not set.
+ */
+int inbox_get(const char *name)
+{
+	list_foreach(inb_list, link, inbox_entry, e) {
+		int cmp = str_cmp(e->name, name);
+		switch (cmp) {
+		case 0:
+			return e->file;
+		case 1:
+			return ENOENT;
+		} 
+	}
+
+	return ENOENT;
+}
+
+/* Writes names of entries that are currently set into an array provided by the
+ * user.
+ *
+ * @param names Array in which names are stored.
+ * @param capacity Capacity of the array.
+ * @return Number of entries written. If capacity == 0, return the total number
+ *         of entries.
+ */
+int inbox_list(const char **names, int capacity)
+{
+	if (capacity == 0)
+		return list_count(&inb_list);
+
+	int used = 0;
+
+	list_foreach(inb_list, link, inbox_entry, e) {
+		if (used == capacity)
+			return used;
+		names[used] = e->name;
+		used++;
+	}
+
+	return used;
+}
+
+void __inbox_init(struct pcb_inbox_entry *entries, int count)
+{
+	for (int i = 0; i < count; i++) {
+		int original = inbox_set(entries[i].name, entries[i].file);
+		if (original >= 0)
+			vfs_put(original);
+	}
+}
+
+/**
+ * @}
+ */
Index: uspace/lib/c/generic/vfs/mtab.c
===================================================================
--- uspace/lib/c/generic/vfs/mtab.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
+++ uspace/lib/c/generic/vfs/mtab.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2008 Jakub Jermar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libc
+ * @{
+ */
+/** @file
+ */
+
+#include <vfs/vfs.h>
+#include <vfs/vfs_mtab.h>
+#include <macros.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <assert.h>
+
+static void process_mp(const char *path, struct stat *stat, list_t *mtab_list)
+{
+	mtab_ent_t *ent;
+
+	ent = (mtab_ent_t *) malloc(sizeof(mtab_ent_t));
+	if (!ent)
+		return;
+
+	link_initialize(&ent->link);
+	str_cpy(ent->mp, sizeof(ent->mp), path);
+	ent->service_id = stat->service_id;
+
+	struct statfs stfs;
+	if (vfs_statfs_path(path, &stfs) == EOK)
+		str_cpy(ent->fs_name, sizeof(ent->fs_name), stfs.fs_name);
+	else
+		str_cpy(ent->fs_name, sizeof(ent->fs_name), "?");
+	
+	list_append(&ent->link, mtab_list);
+}
+
+static int vfs_get_mtab_visit(const char *path, list_t *mtab_list,
+    fs_handle_t fs_handle, service_id_t service_id)
+{
+	DIR *dir;
+	struct dirent *dirent;
+
+	dir = opendir(path);
+	if (!dir)
+		return ENOENT;
+
+	while ((dirent = readdir(dir)) != NULL) {
+		char *child;
+		struct stat st;
+		int rc;
+
+		rc = asprintf(&child, "%s/%s", path, dirent->d_name);
+		if (rc < 0) {
+			closedir(dir);
+			return rc;
+		}
+
+		char *pa = vfs_absolutize(child, NULL);
+		if (!pa) {
+			free(child);
+			closedir(dir);
+			return ENOMEM;
+		}
+
+		free(child);
+		child = pa;
+
+		rc = vfs_stat_path(child, &st);
+		if (rc != 0) {
+			free(child);
+			closedir(dir);
+			return rc;
+		}
+
+		if (st.fs_handle != fs_handle || st.service_id != service_id) {
+			/*
+			 * We have discovered a mountpoint.
+			 */
+			process_mp(child, &st, mtab_list);
+		}
+
+		if (st.is_directory) {
+			(void) vfs_get_mtab_visit(child, mtab_list,
+			    st.fs_handle, st.service_id);
+		}
+
+		free(child);
+	}
+
+	closedir(dir);
+	return EOK;
+}
+
+int vfs_get_mtab_list(list_t *mtab_list)
+{
+	struct stat st;
+
+	int rc = vfs_stat_path("/", &st);
+	if (rc != 0)
+		return rc;
+
+	process_mp("/", &st, mtab_list);
+
+	return vfs_get_mtab_visit("/", mtab_list, st.fs_handle, st.service_id);
+}
+
+/** @}
+ */
Index: uspace/lib/c/generic/vfs/vfs.c
===================================================================
--- uspace/lib/c/generic/vfs/vfs.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/lib/c/generic/vfs/vfs.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -33,15 +33,10 @@
  */
 
+#include <vfs/vfs.h>
 #include <vfs/canonify.h>
-#include <vfs/vfs.h>
+#include <vfs/vfs_mtab.h>
 #include <vfs/vfs_sess.h>
 #include <macros.h>
 #include <stdlib.h>
-#include <unistd.h>
-#include <dirent.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <sys/stat.h>
-#include <sys/statfs.h>
 #include <sys/types.h>
 #include <ipc/services.h>
@@ -56,4 +51,67 @@
 #include <ipc/loc.h>
 
+/*
+ * This file contains the implementation of the native HelenOS file system API.
+ *
+ * The API supports client-side file system roots, client-side IO cursors and
+ * uses file handles as a primary means to refer to files. In order to call the
+ * API functions, one just includes vfs/vfs.h.
+ *
+ * The API functions come in two main flavors:
+ *
+ * - functions that operate on integer file handles, such as:
+ *   vfs_walk(), vfs_open(), vfs_read(), vfs_link(), ...
+ *  
+ * - functions that operate on paths, such as:
+ *   vfs_lookup(), vfs_link_path(), vfs_unlink_path(), vfs_rename_path(), ...
+ *
+ * There is usually a corresponding path function for each file handle function
+ * that exists mostly as a convenience wrapper, except for cases when only a
+ * path version exists due to file system consistency considerations (see
+ * vfs_rename_path()). Sometimes one of the versions does not make sense, in
+ * which case it is also omitted.
+ *
+ * Besides of that, the API provides some convenience wrappers for frequently
+ * performed pairs of operations, for example there is a combo API for
+ * vfs_lookup() and vfs_open(): vfs_lookup_open().
+ *
+ * Some of the functions here return a file handle that can be passed to other
+ * functions. Note that a file handle does not automatically represent a file
+ * from which one can read or to which one can write. In order to do so, the
+ * file handle must be opened first for reading/writing using vfs_open().
+ *
+ * All file handles, no matter whether opened or not, must be eventually
+ * returned to the system using vfs_put(). Non-returned file handles are in use
+ * and consume system resources.
+ *
+ * Functions that return int return a negative error code on error and do not
+ * set errno. Depending on function, success is signalled by returning either
+ * EOK or a non-negative file handle.
+ *
+ * An example life-cycle of a file handle is as follows:
+ *
+ * 	#include <vfs/vfs.h>
+ *
+ * 	int file = vfs_lookup("/foo/bar/foobar", WALK_REGULAR);
+ * 	if (file < 0)
+ * 		return file;
+ * 	int rc = vfs_open(file, MODE_READ);
+ * 	if (rc != EOK) {
+ * 		(void) vfs_put(file);
+ *		return rc;
+ * 	}
+ * 	aoff64_t pos = 42;
+ * 	char buf[512];
+ * 	ssize_t size = vfs_read(file, &pos, buf, sizeof(buf));
+ * 	if (size < 0) {
+ * 		vfs_put(file);
+ * 		return size;
+ * 	}
+ *
+ *	// buf is now filled with data from file
+ *
+ *	vfs_put(file);
+ */
+
 static FIBRIL_MUTEX_INITIALIZE(vfs_mutex);
 static async_sess_t *vfs_sess = NULL;
@@ -65,32 +123,49 @@
 static size_t cwd_size = 0;
 
-/** Start an async exchange on the VFS session.
- *
- * @return New exchange.
- *
- */
-async_exch_t *vfs_exchange_begin(void)
-{
-	fibril_mutex_lock(&vfs_mutex);
-	
-	while (vfs_sess == NULL)
-		vfs_sess = service_connect_blocking(SERVICE_VFS, INTERFACE_VFS,
-		    0);
-	
-	fibril_mutex_unlock(&vfs_mutex);
-	
-	return async_exchange_begin(vfs_sess);
-}
-
-/** Finish an async exchange on the VFS session.
- *
- * @param exch Exchange to be finished.
- *
- */
-void vfs_exchange_end(async_exch_t *exch)
-{
-	async_exchange_end(exch);
-}
-
+static FIBRIL_MUTEX_INITIALIZE(root_mutex);
+static int root_fd = -1;
+
+static int get_parent_and_child(const char *path, char **child)
+{
+	size_t size;
+	char *apath = vfs_absolutize(path, &size);
+	if (!apath)
+		return ENOMEM;
+
+	char *slash = str_rchr(apath, L'/');
+	int parent;
+	if (slash == apath) {
+		parent = vfs_root();
+		*child = apath;
+	} else {
+		*slash = '\0';
+		parent = vfs_lookup(apath, WALK_DIRECTORY);
+		if (parent < 0) {
+			free(apath);
+			return parent;
+		}
+		*slash = '/';
+		*child = str_dup(slash);
+		free(apath);
+		if (!*child) {
+			vfs_put(parent);
+			return ENOMEM;
+		}
+	}
+
+	return parent;
+}
+
+/** Make a potentially relative path absolute
+ *
+ * This function coverts a current-working-directory-relative path into a
+ * well-formed, absolute path. The caller is responsible for deallocating the
+ * returned buffer.
+ *
+ * @param[in] path      Path to be absolutized
+ * @param[out] retlen   Length of the absolutized path
+ *
+ * @return              New buffer holding the absolutized path or NULL
+ */
 char *vfs_absolutize(const char *path, size_t *retlen)
 {
@@ -143,5 +218,300 @@
 }
 
-int vfs_mount(const char *fs_name, const char *mp, const char *fqsn,
+/** Clone a file handle
+ *
+ * The caller can choose whether to clone an existing file handle into another
+ * already existing file handle (in which case it is first closed) or to a new
+ * file handle allocated either from low or high indices.
+ *
+ * @param file_from     Source file handle
+ * @param file_to       Destination file handle or -1
+ * @param high          If file_to is -1, high controls whether the new file
+ *                      handle will be allocated from high indices
+ *
+ * @return              New file handle on success or a negative error code
+ */
+int vfs_clone(int file_from, int file_to, bool high)
+{
+	async_exch_t *vfs_exch = vfs_exchange_begin();
+	int rc = async_req_3_0(vfs_exch, VFS_IN_CLONE, (sysarg_t) file_from,
+	    (sysarg_t) file_to, (sysarg_t) high);
+	vfs_exchange_end(vfs_exch);
+	return rc;
+}
+
+/** Get current working directory path
+ *
+ * @param[out] buf      Buffer
+ * @param size          Size of @a buf
+ *
+ * @return              EOK on success or a non-negative error code
+ */
+int vfs_cwd_get(char *buf, size_t size)
+{
+	fibril_mutex_lock(&cwd_mutex);
+	
+	if ((cwd_size == 0) || (size < cwd_size + 1)) {
+		fibril_mutex_unlock(&cwd_mutex);
+		return ERANGE;
+	}
+	
+	str_cpy(buf, size, cwd_path);
+	fibril_mutex_unlock(&cwd_mutex);
+	
+	return EOK;
+}
+
+/** Change working directory
+ *
+ * @param path  Path of the new working directory
+ *
+ * @return      EOK on success or a negative error code
+ */
+int vfs_cwd_set(const char *path)
+{
+	size_t abs_size;
+	char *abs = vfs_absolutize(path, &abs_size);
+	if (!abs)
+		return ENOMEM;
+	
+	int fd = vfs_lookup(abs, WALK_DIRECTORY);
+	if (fd < 0) {
+		free(abs);
+		return fd;
+	}
+	
+	fibril_mutex_lock(&cwd_mutex);
+	
+	if (cwd_fd >= 0)
+		vfs_put(cwd_fd);
+	
+	if (cwd_path)
+		free(cwd_path);
+	
+	cwd_fd = fd;
+	cwd_path = abs;
+	cwd_size = abs_size;
+	
+	fibril_mutex_unlock(&cwd_mutex);
+	return EOK;
+}
+
+/** Start an async exchange on the VFS session
+ *
+ * @return      New exchange
+ */
+async_exch_t *vfs_exchange_begin(void)
+{
+	fibril_mutex_lock(&vfs_mutex);
+	
+	while (vfs_sess == NULL) {
+		vfs_sess = service_connect_blocking(SERVICE_VFS, INTERFACE_VFS,
+		    0);
+	}
+	
+	fibril_mutex_unlock(&vfs_mutex);
+	
+	return async_exchange_begin(vfs_sess);
+}
+
+/** Finish an async exchange on the VFS session
+ *
+ * @param exch  Exchange to be finished
+ */
+void vfs_exchange_end(async_exch_t *exch)
+{
+	async_exchange_end(exch);
+}
+
+/** Open session to service represented by a special file
+ *
+ * Given that the file referred to by @a file represents a service,
+ * open a session to that service.
+ *
+ * @param file  File handle representing a service
+ * @param iface Interface to connect to (XXX Should be automatic)
+ *
+ * @return      Session pointer on success.
+ * @return      @c NULL or error.
+ */
+async_sess_t *vfs_fd_session(int file, iface_t iface)
+{
+	struct stat stat;
+	int rc = vfs_stat(file, &stat);
+	if (rc != 0)
+		return NULL;
+	
+	if (stat.service == 0)
+		return NULL;
+	
+	return loc_service_connect(stat.service, iface, 0);
+}
+
+/** Link a file or directory
+ *
+ * Create a new name and an empty file or an empty directory in a parent
+ * directory. If child with the same name already exists, the function returns
+ * a failure, the existing file remains untouched and no file system object
+ * is created.
+ *
+ * @param parent        File handle of the parent directory node
+ * @param child         New name to be linked
+ * @param kind          Kind of the object to be created: KIND_FILE or
+ *                      KIND_DIRECTORY
+ * @param[out] linkedfd If not NULL, will receive a file handle to the linked
+ *                      child
+ * @return              EOK on success or a negative error code
+ */
+int vfs_link(int parent, const char *child, vfs_file_kind_t kind, int *linkedfd)
+{
+	int flags = (kind == KIND_DIRECTORY) ? WALK_DIRECTORY : WALK_REGULAR;
+	int file = vfs_walk(parent, child, WALK_MUST_CREATE | flags);
+
+	if (file < 0)
+		return file;
+
+	if (linkedfd)
+		*linkedfd = file;
+	else
+		vfs_put(file);
+
+	return EOK;
+}
+
+/** Link a file or directory
+ *
+ * Create a new name and an empty file or an empty directory at given path.
+ * If a link with the same name already exists, the function returns
+ * a failure, the existing file remains untouched and no file system object
+ * is created.
+ *
+ * @param path          New path to be linked
+ * @param kind          Kind of the object to be created: KIND_FILE or
+ *                      KIND_DIRECTORY
+ * @param[out] linkedfd If not NULL, will receive a file handle to the linked
+ *                      child
+ * @return              EOK on success or a negative error code
+ */
+int vfs_link_path(const char *path, vfs_file_kind_t kind, int *linkedfd)
+{
+	char *child;
+	int parent = get_parent_and_child(path, &child);
+	if (parent < 0)
+		return parent;
+
+	int rc = vfs_link(parent, child, kind, linkedfd);
+
+	free(child);
+	vfs_put(parent);
+	return rc;
+}	
+
+/** Lookup a path relative to the local root
+ *
+ * @param path  Path to be looked up
+ * @param flags Walk flags
+ *
+ * @return      File handle representing the result on success or a negative
+ *              error code on error
+ */
+int vfs_lookup(const char *path, int flags)
+{
+	size_t size;
+	char *p = vfs_absolutize(path, &size);
+	if (!p)
+		return ENOMEM;
+	int root = vfs_root();
+	if (root < 0) {
+		free(p);
+		return ENOENT;
+	}
+	int rc = vfs_walk(root, p, flags);
+	vfs_put(root);
+	free(p);
+	return rc;
+}
+
+/** Lookup a path relative to the local root and open the result
+ *
+ * This function is a convenience combo for vfs_lookup() and vfs_open().
+ *
+ * @param path  Path to be looked up
+ * @param flags Walk flags
+ * @param mode  Mode in which to open file in
+ *
+ * @return      EOK on success or a negative error code
+ */
+int vfs_lookup_open(const char *path, int flags, int mode)
+{
+	int file = vfs_lookup(path, flags);
+	if (file < 0)
+		return file;
+
+	int rc = vfs_open(file, mode);
+	if (rc != EOK) {
+		vfs_put(file);
+		return rc;
+	}
+	
+	return file;
+}
+
+/** Mount a file system
+ *
+ * @param[in] mp                File handle representing the mount-point
+ * @param[in] fs_name           File system name
+ * @param[in] serv              Service representing the mountee
+ * @param[in] opts              Mount options for the endpoint file system
+ * @param[in] flags             Mount flags
+ * @param[in] instance          Instance number of the file system server
+ * @param[out] mountedfd        File handle of the mounted root if not NULL
+ *
+ * @return                      EOK on success or a negative error code
+ */
+int vfs_mount(int mp, const char *fs_name, service_id_t serv, const char *opts,
+    unsigned int flags, unsigned int instance, int *mountedfd)
+{
+	sysarg_t rc, rc1;
+	
+	if (!mountedfd)
+		flags |= VFS_MOUNT_NO_REF;
+	if (mp < 0)
+		flags |= VFS_MOUNT_CONNECT_ONLY;
+	
+	ipc_call_t answer;
+	async_exch_t *exch = vfs_exchange_begin();
+	aid_t req = async_send_4(exch, VFS_IN_MOUNT, mp, serv, flags, instance,
+	    &answer);
+
+	rc1 = async_data_write_start(exch, (void *) opts, str_size(opts));
+	if (rc1 == EOK) {
+		rc1 = async_data_write_start(exch, (void *) fs_name,
+		    str_size(fs_name));
+	}
+
+	vfs_exchange_end(exch);
+
+	async_wait_for(req, &rc);
+
+	if (mountedfd)
+		*mountedfd = (int) IPC_GET_ARG1(answer);
+	
+	if (rc != EOK)
+		return rc;
+	return rc1;
+}
+
+/** Mount a file system
+ *
+ * @param[in] mp                Path representing the mount-point
+ * @param[in] fs_name           File system name
+ * @param[in] fqsn              Fully qualified service name of the mountee
+ * @param[in] opts              Mount options for the endpoint file system
+ * @param[in] flags             Mount flags
+ * @param[in] instance          Instance number of the file system server
+ *
+ * @return                      EOK on success or a negative error code
+ */
+int vfs_mount_path(const char *mp, const char *fs_name, const char *fqsn,
     const char *opts, unsigned int flags, unsigned int instance)
 {
@@ -150,6 +520,7 @@
 	
 	if (str_cmp(fqsn, "") == 0) {
-		/* No device specified, create a fresh
-		   null/%d device instead */
+		/*
+		 * No device specified, create a fresh null/%d device instead.
+		*/
 		null_id = loc_null_create();
 		
@@ -161,4 +532,9 @@
 	}
 	
+	if (flags & IPC_FLAG_BLOCKING)
+		flags = VFS_MOUNT_BLOCKING;
+	else
+		flags = 0;
+	
 	service_id_t service_id;
 	int res = loc_service_get_id(fqsn, &service_id, flags);
@@ -179,73 +555,42 @@
 	}
 	
-	async_exch_t *exch = vfs_exchange_begin();
-
-	sysarg_t rc_orig;
-	aid_t req = async_send_3(exch, VFS_IN_MOUNT, service_id, flags,
-	    instance, NULL);
-	sysarg_t rc = async_data_write_start(exch, (void *) mpa, mpa_size);
-	if (rc != EOK) {
-		vfs_exchange_end(exch);
-		free(mpa);
-		async_wait_for(req, &rc_orig);
+	fibril_mutex_lock(&root_mutex);
+	
+	int rc;
+	
+	if (str_cmp(mpa, "/") == 0) {
+		/* Mounting root. */
 		
-		if (null_id != -1)
-			loc_null_destroy(null_id);
+		if (root_fd >= 0) {
+			fibril_mutex_unlock(&root_mutex);
+			if (null_id != -1)
+				loc_null_destroy(null_id);
+			return EBUSY;
+		}
 		
-		if (rc_orig == EOK)
-			return (int) rc;
-		else
-			return (int) rc_orig;
-	}
-	
-	rc = async_data_write_start(exch, (void *) opts, str_size(opts));
-	if (rc != EOK) {
-		vfs_exchange_end(exch);
-		free(mpa);
-		async_wait_for(req, &rc_orig);
+		int root;
+		rc = vfs_mount(-1, fs_name, service_id, opts, flags, instance,
+		    &root);
+		if (rc == EOK)
+			root_fd = root;
+	} else {
+		if (root_fd < 0) {
+			fibril_mutex_unlock(&root_mutex);
+			if (null_id != -1)
+				loc_null_destroy(null_id);
+			return EINVAL;
+		}
 		
-		if (null_id != -1)
-			loc_null_destroy(null_id);
-		
-		if (rc_orig == EOK)
-			return (int) rc;
-		else
-			return (int) rc_orig;
-	}
-	
-	rc = async_data_write_start(exch, (void *) fs_name, str_size(fs_name));
-	if (rc != EOK) {
-		vfs_exchange_end(exch);
-		free(mpa);
-		async_wait_for(req, &rc_orig);
-		
-		if (null_id != -1)
-			loc_null_destroy(null_id);
-		
-		if (rc_orig == EOK)
-			return (int) rc;
-		else
-			return (int) rc_orig;
-	}
-	
-	/* Ask VFS whether it likes fs_name. */
-	rc = async_req_0_0(exch, VFS_IN_PING);
-	if (rc != EOK) {
-		vfs_exchange_end(exch);
-		free(mpa);
-		async_wait_for(req, &rc_orig);
-		
-		if (null_id != -1)
-			loc_null_destroy(null_id);
-		
-		if (rc_orig == EOK)
-			return (int) rc;
-		else
-			return (int) rc_orig;
-	}
-	
-	vfs_exchange_end(exch);
-	free(mpa);
-	async_wait_for(req, &rc);
+		int mpfd = vfs_walk(root_fd, mpa, WALK_DIRECTORY);
+		if (mpfd >= 0) {
+			rc = vfs_mount(mpfd, fs_name, service_id, opts, flags,
+			    instance, NULL);
+			vfs_put(mpfd);
+		} else {
+			rc = mpfd;
+		}
+	}
+	
+	fibril_mutex_unlock(&root_mutex);
 	
 	if ((rc != EOK) && (null_id != -1))
@@ -255,132 +600,114 @@
 }
 
-int vfs_unmount(const char *mp)
-{
-	sysarg_t rc;
-	sysarg_t rc_orig;
-	aid_t req;
-	size_t mpa_size;
-	char *mpa;
-	
-	mpa = vfs_absolutize(mp, &mpa_size);
-	if (mpa == NULL)
-		return ENOMEM;
-	
-	async_exch_t *exch = vfs_exchange_begin();
-	
-	req = async_send_0(exch, VFS_IN_UNMOUNT, NULL);
-	rc = async_data_write_start(exch, (void *) mpa, mpa_size);
-	if (rc != EOK) {
-		vfs_exchange_end(exch);
-		free(mpa);
-		async_wait_for(req, &rc_orig);
-		if (rc_orig == EOK)
-			return (int) rc;
-		else
-			return (int) rc_orig;
-	}
-	
-
-	vfs_exchange_end(exch);
-	free(mpa);
-	async_wait_for(req, &rc);
-	
-	return (int) rc;
-}
-
-/** Open file (internal).
- *
- * @param abs Absolute path to file
- * @param abs_size Size of @a abs string
- * @param lflag L_xxx flags
- * @param oflag O_xxx flags
- * @param fd Place to store new file descriptor
- *
- * @return EOK on success, non-zero error code on error
- */
-static int open_internal(const char *abs, size_t abs_size, int lflag, int oflag,
-    int *fd)
-{
-	async_exch_t *exch = vfs_exchange_begin();
-	
-	ipc_call_t answer;
-	aid_t req = async_send_3(exch, VFS_IN_OPEN, lflag, oflag, 0, &answer);
-	sysarg_t rc = async_data_write_start(exch, abs, abs_size);
-	
-	if (rc != EOK) {
-		vfs_exchange_end(exch);
-
-		sysarg_t rc_orig;
-		async_wait_for(req, &rc_orig);
-		
-		if (rc_orig == EOK)
-			return (int) rc;
-		else
-			return (int) rc_orig;
-	}
-	
-	vfs_exchange_end(exch);
-	async_wait_for(req, &rc);
-	
+
+/** Open a file handle for I/O
+ *
+ * @param file  File handle to enable I/O on
+ * @param mode  Mode in which to open file in
+ *
+ * @return      EOK on success or a negative error code
+ */
+int vfs_open(int file, int mode)
+{
+	async_exch_t *exch = vfs_exchange_begin();
+	int rc = async_req_2_0(exch, VFS_IN_OPEN, file, mode);
+	vfs_exchange_end(exch);
+	
+	return rc;
+}
+
+/** Pass a file handle to another VFS client
+ *
+ * @param vfs_exch      Donor's VFS exchange
+ * @param file          Donor's file handle to pass
+ * @param exch          Exchange to the acceptor
+ *
+ * @return              EOK on success or a negative error code
+ */
+int vfs_pass_handle(async_exch_t *vfs_exch, int file, async_exch_t *exch)
+{
+	return async_state_change_start(exch, VFS_PASS_HANDLE, (sysarg_t) file,
+	    0, vfs_exch);
+}
+
+/** Stop working with a file handle
+ *
+ * @param file  File handle to put
+ *
+ * @return      EOK on success or a negative error code
+ */
+int vfs_put(int file)
+{
+	async_exch_t *exch = vfs_exchange_begin();
+	int rc = async_req_1_0(exch, VFS_IN_PUT, file);
+	vfs_exchange_end(exch);
+	
+	return rc;
+}
+
+/** Receive a file handle from another VFS client
+ *
+ * @param high   If true, the received file handle will be allocated from high
+ *               indices
+ *
+ * @return       EOK on success or a negative error code
+ */
+int vfs_receive_handle(bool high)
+{
+	ipc_callid_t callid;
+	if (!async_state_change_receive(&callid, NULL, NULL, NULL)) {
+		async_answer_0(callid, EINVAL);
+		return EINVAL;
+	}
+
+	async_exch_t *vfs_exch = vfs_exchange_begin();
+
+	async_state_change_finalize(callid, vfs_exch);
+
+	sysarg_t ret;
+	sysarg_t rc = async_req_1_1(vfs_exch, VFS_IN_WAIT_HANDLE, high, &ret);
+
+	async_exchange_end(vfs_exch);
+
 	if (rc != EOK)
-	    return (int) rc;
-	
-	*fd = (int) IPC_GET_ARG1(answer);
-	return EOK;
-}
-
-/** Open file.
- *
- * @param path File path
- * @param oflag O_xxx flags
- * @param mode File mode (only with O_CREAT)
- *
- * @return Nonnegative file descriptor on success. On error -1 is returned
- *         and errno is set.
- */
-int open(const char *path, int oflag, ...)
-{
-	size_t abs_size;
-	char *abs = vfs_absolutize(path, &abs_size);
-	int fd = -1;
-	
-	if (abs == NULL) {
-		errno = ENOMEM;
-		return -1;
-	}
-	
-	int rc = open_internal(abs, abs_size, L_FILE, oflag, &fd);
-	free(abs);
-	
-	if (rc != EOK) {
-		errno = rc;
-		return -1;
-	}
-	
-	return fd;
-}
-
-/** Close file.
- *
- * @param fildes File descriptor
- * @return Zero on success. On error -1 is returned and errno is set.
- */
-int close(int fildes)
-{
-	sysarg_t rc;
-	
-	async_exch_t *exch = vfs_exchange_begin();
-	rc = async_req_1_0(exch, VFS_IN_CLOSE, fildes);
-	vfs_exchange_end(exch);
-	
-	if (rc != EOK) {
-		errno = rc;
-		return -1;
-	}
-	
-	return 0;
-}
-
-/** Read bytes from file.
+		return rc;
+	return ret;
+}
+
+/** Read data
+ *
+ * Read up to @a nbytes bytes from file if available. This function always reads
+ * all the available bytes up to @a nbytes.
+ *
+ * @param file          File handle to read from
+ * @param[inout] pos    Position to read from, updated by the actual bytes read
+ * @param buf		Buffer, @a nbytes bytes long
+ * @param nbytes	Number of bytes to read
+ *
+ * @return              On success, non-negative number of bytes read
+ * @return              On failure, a negative error code
+ */
+ssize_t vfs_read(int file, aoff64_t *pos, void *buf, size_t nbyte)
+{
+	ssize_t cnt = 0;
+	size_t nread = 0;
+	uint8_t *bp = (uint8_t *) buf;
+	int rc;
+	
+	do {
+		bp += cnt;
+		nread += cnt;
+		*pos += cnt;
+		rc = vfs_read_short(file, *pos, bp, nbyte - nread, &cnt);
+	} while (rc == EOK && cnt > 0 && (nbyte - nread - cnt) > 0);
+	
+	if (rc != EOK)
+		return rc;
+	
+	*pos += cnt;
+	return nread + cnt;
+}
+
+/** Read bytes from a file
  *
  * Read up to @a nbyte bytes from file. The actual number of bytes read
@@ -389,12 +716,14 @@
  * return success with zero bytes read.
  *
- * @param fildes File descriptor
- * @param buf Buffer
- * @param nbyte Maximum number of bytes to read
- * @param nread Place to store actual number of bytes read (0 or more)
- *
- * @return EOK on success, non-zero error code on error.
- */
-static int _read_short(int fildes, void *buf, size_t nbyte, ssize_t *nread)
+ * @param file          File handle to read from
+ * @param[in] pos       Position to read from
+ * @param buf           Buffer to read from
+ * @param nbyte         Maximum number of bytes to read
+ * @param[out] nread	Actual number of bytes read (0 or more)
+ *
+ * @return              EOK on success or a negative error code
+ */
+int vfs_read_short(int file, aoff64_t pos, void *buf, size_t nbyte,
+    ssize_t *nread)
 {
 	sysarg_t rc;
@@ -407,223 +736,152 @@
 	async_exch_t *exch = vfs_exchange_begin();
 	
-	req = async_send_1(exch, VFS_IN_READ, fildes, &answer);
+	req = async_send_3(exch, VFS_IN_READ, file, LOWER32(pos),
+	    UPPER32(pos), &answer);
 	rc = async_data_read_start(exch, (void *) buf, nbyte);
+
+	vfs_exchange_end(exch);
+	
+	if (rc == EOK)
+		async_wait_for(req, &rc);
+	else
+		async_forget(req);
+	
+	if (rc != EOK)
+		return rc;
+	
+	*nread = (ssize_t) IPC_GET_ARG1(answer);
+	return EOK;
+}
+
+/** Rename a file or directory
+ *
+ * There is no file-handle-based variant to disallow attempts to introduce loops
+ * and breakage in the directory tree when relinking eg. a node under its own
+ * descendant.  The path-based variant is not susceptible because the VFS can
+ * prevent this lexically by comparing the paths.
+ *
+ * @param old   Old path
+ * @param new   New path
+ *
+ * @return      EOK on success or a negative error code
+ */
+int vfs_rename_path(const char *old, const char *new)
+{
+	sysarg_t rc;
+	sysarg_t rc_orig;
+	aid_t req;
+	
+	size_t olda_size;
+	char *olda = vfs_absolutize(old, &olda_size);
+	if (olda == NULL)
+		return ENOMEM;
+
+	size_t newa_size;
+	char *newa = vfs_absolutize(new, &newa_size);
+	if (newa == NULL) {
+		free(olda);
+		return ENOMEM;
+	}
+	
+	async_exch_t *exch = vfs_exchange_begin();
+	int root = vfs_root();
+	if (root < 0) {
+		free(olda);
+		free(newa);
+		return ENOENT;
+	}
+	
+	req = async_send_1(exch, VFS_IN_RENAME, root, NULL);
+	rc = async_data_write_start(exch, olda, olda_size);
 	if (rc != EOK) {
 		vfs_exchange_end(exch);
-		
-		sysarg_t rc_orig;
+		free(olda);
+		free(newa);
+		vfs_put(root);
 		async_wait_for(req, &rc_orig);
-		
-		if (rc_orig == EOK)
-			return rc;
-		else
-			return rc_orig;
-	}
-	
-	vfs_exchange_end(exch);
-	async_wait_for(req, &rc);
-	
-	if (rc != EOK)
+		if (rc_orig != EOK)
+			rc = rc_orig;
 		return rc;
-	
-	*nread = (ssize_t) IPC_GET_ARG1(answer);
-	return EOK;
-}
-
-/** Write bytes to file.
- *
- * Write up to @a nbyte bytes from file. The actual number of bytes written
- * may be lower, but greater than zero.
- *
- * @param fildes File descriptor
- * @param buf Buffer
- * @param nbyte Maximum number of bytes to write
- * @param nread Place to store actual number of bytes written (0 or more)
- *
- * @return EOK on success, non-zero error code on error.
- */
-static int _write_short(int fildes, const void *buf, size_t nbyte,
-    ssize_t *nwritten)
-{
-	sysarg_t rc;
-	ipc_call_t answer;
-	aid_t req;
-	
-	if (nbyte > DATA_XFER_LIMIT)
-		nbyte = DATA_XFER_LIMIT;
-	
-	async_exch_t *exch = vfs_exchange_begin();
-	
-	req = async_send_1(exch, VFS_IN_WRITE, fildes, &answer);
-	rc = async_data_write_start(exch, (void *) buf, nbyte);
+	}
+	rc = async_data_write_start(exch, newa, newa_size);
 	if (rc != EOK) {
 		vfs_exchange_end(exch);
-		
-		sysarg_t rc_orig;
+		free(olda);
+		free(newa);
+		vfs_put(root);
 		async_wait_for(req, &rc_orig);
-		
-		if (rc_orig == EOK)
-			return rc;
-		else
-			return rc_orig;
-	}
-	
-	vfs_exchange_end(exch);
+		if (rc_orig != EOK)
+			rc = rc_orig;
+		return rc;
+	}
+	vfs_exchange_end(exch);
+	free(olda);
+	free(newa);
+	vfs_put(root);
 	async_wait_for(req, &rc);
-	
-	if (rc != EOK)
-		return rc;
-	
-	*nwritten = (ssize_t) IPC_GET_ARG1(answer);
-	return EOK;
-}
-
-/** Read data.
- *
- * Read up to @a nbytes bytes from file if available. This function always reads
- * all the available bytes up to @a nbytes.
- *
- * @param fildes	File descriptor
- * @param buf		Buffer, @a nbytes bytes long
- * @param nbytes	Number of bytes to read
- *
- * @return		On success, nonnegative number of bytes read.
- *			On failure, -1 and sets errno.
- */
-ssize_t read(int fildes, void *buf, size_t nbyte)
-{
-	ssize_t cnt = 0;
-	size_t nread = 0;
-	uint8_t *bp = (uint8_t *) buf;
-	int rc;
-	
-	do {
-		bp += cnt;
-		nread += cnt;
-		rc = _read_short(fildes, bp, nbyte - nread, &cnt);
-	} while (rc == EOK && cnt > 0 && (nbyte - nread - cnt) > 0);
-	
-	if (rc != EOK) {
-		errno = rc;
-		return -1;
-	}
-	
-	return nread + cnt;
-}
-
-/** Write data.
- *
- * This function fails if it cannot write exactly @a len bytes to the file.
- *
- * @param fildes	File descriptor
- * @param buf		Data, @a nbytes bytes long
- * @param nbytes	Number of bytes to write
- *
- * @return		On success, nonnegative number of bytes written.
- *			On failure, -1 and sets errno.
- */
-ssize_t write(int fildes, const void *buf, size_t nbyte)
-{
-	ssize_t cnt = 0;
-	ssize_t nwritten = 0;
-	const uint8_t *bp = (uint8_t *) buf;
-	int rc;
-
-	do {
-		bp += cnt;
-		nwritten += cnt;
-		rc = _write_short(fildes, bp, nbyte - nwritten, &cnt);
-	} while (rc == EOK && ((ssize_t )nbyte - nwritten - cnt) > 0);
-
-	if (rc != EOK) {
-		errno = rc;
-		return -1;
-	}
-
-	return nbyte;
-}
-
-/** Synchronize file.
- *
- * @param fildes File descriptor
- * @return 0 on success. On error returns -1 and sets errno.
- */
-int fsync(int fildes)
-{
-	async_exch_t *exch = vfs_exchange_begin();
-	sysarg_t rc = async_req_1_0(exch, VFS_IN_SYNC, fildes);
-	vfs_exchange_end(exch);
-	
-	if (rc != EOK) {
-		errno = rc;
-		return -1;
-	}
-	
-	return 0;
-}
-
-/** Seek to a position.
- *
- * @param fildes File descriptor
- * @param offset Offset
- * @param whence SEEK_SET, SEEK_CUR or SEEK_END
- *
- * @return On success the nonnegative offset from start of file. On error
- *         returns (off64_t)-1 and sets errno.
- */
-off64_t lseek(int fildes, off64_t offset, int whence)
-{
-	async_exch_t *exch = vfs_exchange_begin();
-	
-	sysarg_t newoff_lo;
-	sysarg_t newoff_hi;
-	sysarg_t rc = async_req_4_2(exch, VFS_IN_SEEK, fildes,
-	    LOWER32(offset), UPPER32(offset), whence,
-	    &newoff_lo, &newoff_hi);
-	
-	vfs_exchange_end(exch);
-	
-	if (rc != EOK) {
-		errno = rc;
-		return (off64_t) -1;
-	}
-	
-	return (off64_t) MERGE_LOUP32(newoff_lo, newoff_hi);
-}
-
-/** Truncate file to a specified length.
- *
- * Truncate file so that its size is exactly @a length
- *
- * @param fildes File descriptor
- * @param length Length
- *
- * @return 0 on success, -1 on error and sets errno.
- */
-int ftruncate(int fildes, aoff64_t length)
-{
-	sysarg_t rc;
-	
-	async_exch_t *exch = vfs_exchange_begin();
-	rc = async_req_3_0(exch, VFS_IN_TRUNCATE, fildes,
-	    LOWER32(length), UPPER32(length));
-	vfs_exchange_end(exch);
-	
-	if (rc != EOK) {
-		errno = rc;
-		return -1;
-	}
-	
-	return 0;
-}
-
-/** Get file status.
- *
- * @param fildes File descriptor
- * @param stat Place to store file information
- *
- * @return 0 on success, -1 on error and sets errno.
- */
-int fstat(int fildes, struct stat *stat)
+
+	return rc;
+}
+
+/** Resize file to a specified length
+ *
+ * Resize file so that its size is exactly @a length.
+ *
+ * @param file          File handle to resize
+ * @param length        New length
+ *
+ * @return              EOK on success or a negative error code
+ */
+int vfs_resize(int file, aoff64_t length)
+{
+	async_exch_t *exch = vfs_exchange_begin();
+	int rc = async_req_3_0(exch, VFS_IN_RESIZE, file, LOWER32(length),
+	    UPPER32(length));
+	vfs_exchange_end(exch);
+	
+	return rc;
+}
+
+/** Return a new file handle representing the local root
+ *
+ * @return      A clone of the local root file handle or a negative error code
+ */
+int vfs_root(void)
+{
+	fibril_mutex_lock(&root_mutex);	
+	int r;
+	if (root_fd < 0)
+		r = ENOENT;
+	else
+		r = vfs_clone(root_fd, -1, true);
+	fibril_mutex_unlock(&root_mutex);
+	return r;
+}
+
+/** Set a new local root
+ *
+ * Note that it is still possible to have file handles for other roots and pass
+ * them to the API functions. Functions like vfs_root() and vfs_lookup() will
+ * however consider the file set by this function to be the root.
+ *
+ * @param nroot The new local root file handle
+ */
+void vfs_root_set(int nroot)
+{
+	fibril_mutex_lock(&root_mutex);
+	if (root_fd >= 0)
+		vfs_put(root_fd);
+	root_fd = vfs_clone(nroot, -1, true);
+	fibril_mutex_unlock(&root_mutex);
+}
+
+/** Get file information
+ *
+ * @param file          File handle to get information about
+ * @param[out] stat     Place to store file information
+ *
+ * @return              EOK on success or a negative error code
+ */
+int vfs_stat(int file, struct stat *stat)
 {
 	sysarg_t rc;
@@ -632,5 +890,5 @@
 	async_exch_t *exch = vfs_exchange_begin();
 	
-	req = async_send_1(exch, VFS_IN_FSTAT, fildes, NULL);
+	req = async_send_1(exch, VFS_IN_STAT, file, NULL);
 	rc = async_data_read_start(exch, (void *) stat, sizeof(struct stat));
 	if (rc != EOK) {
@@ -642,10 +900,6 @@
 		if (rc_orig != EOK)
 			rc = rc_orig;
-		if (rc != EOK) {
-			errno = rc;
-			return -1;
-		}
 		
-		return 0;
+		return rc;
 	}
 	
@@ -653,592 +907,286 @@
 	async_wait_for(req, &rc);
 	
-	if (rc != EOK) {
-		errno = rc;
-		return -1;
-	}
-	
-	return 0;
-}
-
-/** Get file status.
- *
- * @param path Path to file
- * @param stat Place to store file information
- *
- * @return 0 on success, -1 on error and sets errno.
- */
-int stat(const char *path, struct stat *stat)
-{
-	sysarg_t rc;
-	sysarg_t rc_orig;
+	return rc;
+}
+
+/** Get file information 
+ *
+ * @param path          File path to get information about
+ * @param[out] stat     Place to store file information
+ *
+ * @return              EOK on success or a negative error code
+ */
+int vfs_stat_path(const char *path, struct stat *stat)
+{
+	int file = vfs_lookup(path, 0);
+	if (file < 0)
+		return file;
+	
+	int rc = vfs_stat(file, stat);
+
+	vfs_put(file);
+
+	return rc;
+}
+
+/** Get filesystem statistics
+ *
+ * @param file          File located on the queried file system
+ * @param[out] st       Buffer for storing information
+ *
+ * @return              EOK on success or a negative error code
+ */
+int vfs_statfs(int file, struct statfs *st)
+{
+	sysarg_t rc, ret;
 	aid_t req;
-	
-	size_t pa_size;
-	char *pa = vfs_absolutize(path, &pa_size);
-	if (pa == NULL) {
-		errno = ENOMEM;
-		return -1;
-	}
-	
-	async_exch_t *exch = vfs_exchange_begin();
-	
-	req = async_send_0(exch, VFS_IN_STAT, NULL);
-	rc = async_data_write_start(exch, pa, pa_size);
-	if (rc != EOK) {
-		vfs_exchange_end(exch);
-		free(pa);
-		async_wait_for(req, &rc_orig);
-		if (rc_orig != EOK)
-			rc = rc_orig;
-		if (rc != EOK) {
-			errno = rc;
-			return -1;
-		}
-	}
-	rc = async_data_read_start(exch, stat, sizeof(struct stat));
-	if (rc != EOK) {
-		vfs_exchange_end(exch);
-		free(pa);
-		async_wait_for(req, &rc_orig);
-		if (rc_orig != EOK)
-			rc = rc_orig;
-		if (rc != EOK) {
-			errno = rc;
-			return -1;
-		}
-	}
-	vfs_exchange_end(exch);
-	free(pa);
-	async_wait_for(req, &rc);
-	if (rc != EOK) {
-		errno = rc;
-		return -1;
-	}
-	return 0;
-}
-
-/** Open directory.
- *
- * @param dirname Directory pathname
- *
- * @return Non-NULL pointer on success. On error returns @c NULL and sets errno.
- */
-DIR *opendir(const char *dirname)
-{
-	DIR *dirp = malloc(sizeof(DIR));
-	int fd = -1;
-	
-	if (dirp == NULL) {
-		errno = ENOMEM;
-		return NULL;
-	}
-	
-	size_t abs_size;
-	char *abs = vfs_absolutize(dirname, &abs_size);
-	if (abs == NULL) {
-		free(dirp);
-		errno = ENOMEM;
-		return NULL;
-	}
-	
-	int rc = open_internal(abs, abs_size, L_DIRECTORY, 0, &fd);
-	free(abs);
-	
-	if (rc != EOK) {
-		free(dirp);
-		errno = rc;
-		return NULL;
-	}
-	
-	dirp->fd = fd;
-	return dirp;
-}
-
-/** Read directory entry.
- *
- * @param dirp Open directory
- * @return Non-NULL pointer to directory entry on success. On error returns
- *         @c NULL and sets errno.
- */
-struct dirent *readdir(DIR *dirp)
-{
-	int rc;
-	ssize_t len;
-	
-	rc = _read_short(dirp->fd, &dirp->res.d_name[0], NAME_MAX + 1, &len);
-	if (rc != EOK) {
-		errno = rc;
-		return NULL;
-	}
-	
-	(void) len;
-	return &dirp->res;
-}
-
-/** Rewind directory position to the beginning.
- *
- * @param dirp Open directory
- */
-void rewinddir(DIR *dirp)
-{
-	(void) lseek(dirp->fd, 0, SEEK_SET);
-}
-
-/** Close directory.
- *
- * @param dirp Open directory
- * @return 0 on success. On error returns -1 and sets errno.
- */
-int closedir(DIR *dirp)
-{
-	int rc;
-	
-	rc = close(dirp->fd);
-	free(dirp);
-
-	/* On error errno was set by close() */
-	return rc;
-}
-
-/** Create directory.
- *
- * @param path Path
- * @param mode File mode
- * @return 0 on success. On error returns -1 and sets errno.
- */
-int mkdir(const char *path, mode_t mode)
+
+	async_exch_t *exch = vfs_exchange_begin();
+
+	req = async_send_1(exch, VFS_IN_STATFS, file, NULL);
+	rc = async_data_read_start(exch, (void *) st, sizeof(*st));
+
+	vfs_exchange_end(exch);
+	async_wait_for(req, &ret);
+
+	rc = (ret != EOK ? ret : rc);
+
+	return rc;
+}
+
+/** Get filesystem statistics
+ *
+ * @param file          Path pointing to the queried file system
+ * @param[out] st       Buffer for storing information
+ *
+ * @return              EOK on success or a negative error code
+ */
+int vfs_statfs_path(const char *path, struct statfs *st)
+{
+	int file = vfs_lookup(path, 0);
+	if (file < 0)
+		return file;
+	
+	int rc = vfs_statfs(file, st);
+
+	vfs_put(file);
+
+	return rc; 
+}
+
+/** Synchronize file
+ *
+ * @param file  File handle to synchronize
+ *
+ * @return      EOK on success or a negative error code
+ */
+int vfs_sync(int file)
+{
+	async_exch_t *exch = vfs_exchange_begin();
+	int rc = async_req_1_0(exch, VFS_IN_SYNC, file);
+	vfs_exchange_end(exch);
+	
+	return rc;
+}
+
+/** Unlink a file or directory
+ *
+ * Unlink a name from a parent directory. The caller can supply the file handle
+ * of the unlinked child in order to detect a possible race with vfs_link() and
+ * avoid unlinking a wrong file. If the last link for a file or directory is
+ * removed, the FS implementation will deallocate its resources.
+ *
+ * @param parent        File handle of the parent directory node
+ * @param child         Old name to be unlinked
+ * @param expect        File handle of the unlinked child
+ *
+ * @return              EOK on success or a negative error code
+ */
+int vfs_unlink(int parent, const char *child, int expect)
 {
 	sysarg_t rc;
 	aid_t req;
 	
-	size_t pa_size;
-	char *pa = vfs_absolutize(path, &pa_size);
-	if (pa == NULL) {
-		errno = ENOMEM;
-		return -1;
-	}
-	
-	async_exch_t *exch = vfs_exchange_begin();
-	
-	req = async_send_1(exch, VFS_IN_MKDIR, mode, NULL);
-	rc = async_data_write_start(exch, pa, pa_size);
-	if (rc != EOK) {
-		vfs_exchange_end(exch);
-		free(pa);
+	async_exch_t *exch = vfs_exchange_begin();
+	
+	req = async_send_2(exch, VFS_IN_UNLINK, parent, expect, NULL);
+	rc = async_data_write_start(exch, child, str_size(child));
+	
+	vfs_exchange_end(exch);
+	
+	sysarg_t rc_orig;
+	async_wait_for(req, &rc_orig);
+	
+	if (rc_orig != EOK)
+		return (int) rc_orig;
+	return rc;
+}
+
+/** Unlink a file or directory
+ *
+ * Unlink a path. If the last link for a file or directory is removed, the FS
+ * implementation will deallocate its resources.
+ *
+ * @param path          Old path to be unlinked
+ *
+ * @return              EOK on success or a negative error code
+ */
+int vfs_unlink_path(const char *path)
+{
+	int expect = vfs_lookup(path, 0);
+	if (expect < 0)
+		return expect;
+
+	char *child;
+	int parent = get_parent_and_child(path, &child);
+	if (parent < 0) {
+		vfs_put(expect);
+		return parent;
+	}
+
+	int rc = vfs_unlink(parent, child, expect);
+	
+	free(child);
+	vfs_put(parent);
+	vfs_put(expect);
+	return rc;
+}
+
+/** Unmount a file system
+ *
+ * @param mp    File handle representing the mount-point
+ *
+ * @return      EOK on success or a negative error code
+ */
+int vfs_unmount(int mp)
+{
+	async_exch_t *exch = vfs_exchange_begin();
+	int rc = async_req_1_0(exch, VFS_IN_UNMOUNT, mp);
+	vfs_exchange_end(exch);
+	return rc;
+}
+
+/** Unmount a file system
+ *
+ * @param mpp   Mount-point path
+ *
+ * @return      EOK on success or a negative error code
+ */
+int vfs_unmount_path(const char *mpp)
+{
+	int mp = vfs_lookup(mpp, WALK_MOUNT_POINT | WALK_DIRECTORY);
+	if (mp < 0)
+		return mp;
+	
+	int rc = vfs_unmount(mp);
+	vfs_put(mp);
+	return rc;
+}
+
+/** Walk a path starting in a parent node
+ *
+ * @param parent        File handle of the parent node where the walk starts
+ * @param path          Parent-relative path to be walked
+ * @param flags         Flags influencing the walk
+ *
+ * @retrun              File handle representing the result on success or
+ *                      a negative error code on error
+ */
+int vfs_walk(int parent, const char *path, int flags)
+{
+	async_exch_t *exch = vfs_exchange_begin();
+	
+	ipc_call_t answer;
+	aid_t req = async_send_2(exch, VFS_IN_WALK, parent, flags, &answer);
+	sysarg_t rc = async_data_write_start(exch, path, str_size(path));
+	vfs_exchange_end(exch);
 		
-		sysarg_t rc_orig;
-		async_wait_for(req, &rc_orig);
+	sysarg_t rc_orig;
+	async_wait_for(req, &rc_orig);
+
+	if (rc_orig != EOK)
+		return (int) rc_orig;
 		
-		if (rc_orig != EOK)
-			rc = rc_orig;
-		
-		if (rc != EOK) {
-			errno = rc;
-			return -1;
-		}
-		
-		return 0;
-	}
-	
-	vfs_exchange_end(exch);
-	free(pa);
-	async_wait_for(req, &rc);
-	
-	if (rc != EOK) {
-		errno = rc;
-		return -1;
-	}
-	
-	return 0;
-}
-
-/** Unlink a file or directory.
- *
- * @param path Path to file or empty directory
- * @param lflag L_xxx flag (L_NONE, L_FILE or L_DIRECTORY)
- * @return EOK on success, non-zero error code on error
- */
-static int _unlink(const char *path, int lflag)
+	if (rc != EOK)
+		return (int) rc;
+	
+	return (int) IPC_GET_ARG1(answer);
+}
+
+/** Write data
+ *
+ * This function fails if it cannot write exactly @a len bytes to the file.
+ *
+ * @param file          File handle to write to
+ * @param[inout] pos    Position to write to, updated by the actual bytes
+ *                      written
+ * @param buf           Data, @a nbytes bytes long
+ * @param nbytes        Number of bytes to write
+ *
+ * @return		On success, non-negative number of bytes written
+ * @return              On failure, a negative error code
+ */
+ssize_t vfs_write(int file, aoff64_t *pos, const void *buf, size_t nbyte)
+{
+	ssize_t cnt = 0;
+	ssize_t nwritten = 0;
+	const uint8_t *bp = (uint8_t *) buf;
+	int rc;
+
+	do {
+		bp += cnt;
+		nwritten += cnt;
+		*pos += cnt;
+		rc = vfs_write_short(file, *pos, bp, nbyte - nwritten, &cnt);
+	} while (rc == EOK && ((ssize_t )nbyte - nwritten - cnt) > 0);
+
+	if (rc != EOK)
+		return rc;
+
+	*pos += cnt;
+	return nbyte;
+}
+
+/** Write bytes to a file
+ *
+ * Write up to @a nbyte bytes from file. The actual number of bytes written
+ * may be lower, but greater than zero.
+ *
+ * @param file          File handle to write to
+ * @param[in] pos       Position to write to
+ * @param buf           Buffer to write to
+ * @param nbyte         Maximum number of bytes to write
+ * @param[out] nread    Actual number of bytes written (0 or more)
+ *
+ * @return              EOK on success or a negative error code
+ */
+int vfs_write_short(int file, aoff64_t pos, const void *buf, size_t nbyte,
+    ssize_t *nwritten)
 {
 	sysarg_t rc;
+	ipc_call_t answer;
 	aid_t req;
 	
-	size_t pa_size;
-	char *pa = vfs_absolutize(path, &pa_size);
-	if (pa == NULL)
-		return ENOMEM;
-	
-	async_exch_t *exch = vfs_exchange_begin();
-	
-	req = async_send_1(exch, VFS_IN_UNLINK, lflag, NULL);
-	rc = async_data_write_start(exch, pa, pa_size);
-	if (rc != EOK) {
-		vfs_exchange_end(exch);
-		free(pa);
-
-		sysarg_t rc_orig;
-		async_wait_for(req, &rc_orig);
-
-		if (rc_orig == EOK)
-			return (int) rc;
-		else
-			return (int) rc_orig;
-	}
-	vfs_exchange_end(exch);
-	free(pa);
-	async_wait_for(req, &rc);
-	return rc;
-}
-
-/** Unlink file or directory.
- *
- * @param path Path
- * @return EOk on success, error code on error
- */
-int unlink(const char *path)
-{
-	int rc;
-
-	rc = _unlink(path, L_NONE);
-	if (rc != EOK) {
-		errno = rc;
-		return -1;
-	}
-
-	return 0;
-}
-
-/** Remove empty directory.
- *
- * @param path Path
- * @return 0 on success. On error returns -1 and sets errno.
- */
-int rmdir(const char *path)
-{
-	int rc;
-
-	rc = _unlink(path, L_DIRECTORY);
-	if (rc != EOK) {
-		errno = rc;
-		return -1;
-	}
-
-	return 0;
-}
-
-/** Rename directory entry.
- *
- * @param old Old name
- * @param new New name
- *
- * @return 0 on success. On error returns -1 and sets errno.
- */
-int rename(const char *old, const char *new)
-{
-	sysarg_t rc;
-	sysarg_t rc_orig;
-	aid_t req;
-	
-	size_t olda_size;
-	char *olda = vfs_absolutize(old, &olda_size);
-	if (olda == NULL) {
-		errno = ENOMEM;
-		return -1;
-	}
-
-	size_t newa_size;
-	char *newa = vfs_absolutize(new, &newa_size);
-	if (newa == NULL) {
-		free(olda);
-		errno = ENOMEM;
-		return -1;
-	}
-	
-	async_exch_t *exch = vfs_exchange_begin();
-	
-	req = async_send_0(exch, VFS_IN_RENAME, NULL);
-	rc = async_data_write_start(exch, olda, olda_size);
-	if (rc != EOK) {
-		vfs_exchange_end(exch);
-		free(olda);
-		free(newa);
-		async_wait_for(req, &rc_orig);
-		if (rc_orig != EOK)
-			rc = rc_orig;
-		if (rc != EOK) {
-			errno = rc;
-			return -1;
-		}
-		return 0;
-	}
-	rc = async_data_write_start(exch, newa, newa_size);
-	if (rc != EOK) {
-		vfs_exchange_end(exch);
-		free(olda);
-		free(newa);
-		async_wait_for(req, &rc_orig);
-		if (rc_orig != EOK)
-			rc = rc_orig;
-		if (rc != EOK) {
-			errno = rc;
-			return -1;
-		}
-		return 0;
-	}
-	vfs_exchange_end(exch);
-	free(olda);
-	free(newa);
-	async_wait_for(req, &rc);
-
-	if (rc != EOK) {
-		errno = rc;
-		return -1;
-	}
-
-	return 0;
-}
-
-/** Remove directory entry.
- *
- * @param path Path
- * @return 0 on success. On error returns -1 and sets errno.
- */
-int remove(const char *path)
-{
-	return unlink(path);
-}
-
-/** Change working directory.
- *
- * @param path Path
- * @return 0 on success. On error returns -1 and sets errno.
- */
-int chdir(const char *path)
-{
-	size_t abs_size;
-	char *abs = vfs_absolutize(path, &abs_size);
-	int fd = -1;
-	
-	if (abs == NULL) {
-		errno = ENOMEM;
-		return -1;
-	}
-	
-	int rc = open_internal(abs, abs_size, L_DIRECTORY, O_DESC, &fd);
-	
-	if (rc != EOK) {
-		free(abs);
-		errno = rc;
-		return -1;
-	}
-	
-	fibril_mutex_lock(&cwd_mutex);
-	
-	if (cwd_fd >= 0)
-		close(cwd_fd);
-	
-	if (cwd_path)
-		free(cwd_path);
-	
-	cwd_fd = fd;
-	cwd_path = abs;
-	cwd_size = abs_size;
-	
-	fibril_mutex_unlock(&cwd_mutex);
-	return 0;
-}
-
-/** Get current working directory path.
- *
- * @param buf Buffer
- * @param size Size of @a buf
- * @return On success returns @a buf. On failure returns @c NULL and sets errno.
- */
-char *getcwd(char *buf, size_t size)
-{
-	if (size == 0) {
-		errno = EINVAL;
-		return NULL;
-	}
-	
-	fibril_mutex_lock(&cwd_mutex);
-	
-	if ((cwd_size == 0) || (size < cwd_size + 1)) {
-		fibril_mutex_unlock(&cwd_mutex);
-		errno = ERANGE;
-		return NULL;
-	}
-	
-	str_cpy(buf, size, cwd_path);
-	fibril_mutex_unlock(&cwd_mutex);
-	
-	return buf;
-}
-
-/** Open session to service represented by a special file.
- *
- * Given that the file referred to by @a fildes represents a service,
- * open a session to that service.
- *
- * @param fildes File descriptor
- * @param iface Interface to connect to (XXX Should be automatic)
- * @return On success returns session pointer. On error returns @c NULL.
- */
-async_sess_t *vfs_fd_session(int fildes, iface_t iface)
-{
-	struct stat stat;
-	int rc = fstat(fildes, &stat);
-	if (rc != 0)
-		return NULL;
-	
-	if (stat.service == 0)
-		return NULL;
-	
-	return loc_service_connect(stat.service, iface, 0);
-}
-
-/** Duplicate open file.
- *
- * Duplicate open file under a new file descriptor.
- *
- * @param oldfd Old file descriptor
- * @param newfd New file descriptor
- * @return 0 on success. On error -1 is returned and errno is set
- */
-int dup2(int oldfd, int newfd)
-{
-	async_exch_t *exch = vfs_exchange_begin();
-	
-	sysarg_t ret;
-	sysarg_t rc = async_req_2_1(exch, VFS_IN_DUP, oldfd, newfd, &ret);
+	if (nbyte > DATA_XFER_LIMIT)
+		nbyte = DATA_XFER_LIMIT;
+	
+	async_exch_t *exch = vfs_exchange_begin();
+	
+	req = async_send_3(exch, VFS_IN_WRITE, file, LOWER32(pos),
+	    UPPER32(pos), &answer);
+	rc = async_data_write_start(exch, (void *) buf, nbyte);
 	
 	vfs_exchange_end(exch);
 	
 	if (rc == EOK)
-		rc = ret;
-	
-	if (rc != EOK) {
-		errno = rc;
-		return -1;
-	}
-	
-	return 0;
-}
-
-int vfs_fd_wait(void)
-{
-	async_exch_t *exch = vfs_exchange_begin();
-	
-	sysarg_t ret;
-	sysarg_t rc = async_req_0_1(exch, VFS_IN_WAIT_HANDLE, &ret);
-	
-	vfs_exchange_end(exch);
-	
-	if (rc == EOK)
-		return (int) ret;
-	
-	return (int) rc;
-}
-
-int vfs_get_mtab_list(list_t *mtab_list)
-{
-	sysarg_t rc;
-	aid_t req;
-	size_t i;
-	sysarg_t num_mounted_fs;
-	
-	async_exch_t *exch = vfs_exchange_begin();
-
-	req = async_send_0(exch, VFS_IN_MTAB_GET, NULL);
-
-	/* Ask VFS how many filesystems are mounted */
-	rc = async_req_0_1(exch, VFS_IN_PING, &num_mounted_fs);
+		async_wait_for(req, &rc);
+	else
+		async_forget(req);
+
 	if (rc != EOK)
-		goto exit;
-
-	for (i = 0; i < num_mounted_fs; ++i) {
-		mtab_ent_t *mtab_ent;
-
-		mtab_ent = malloc(sizeof(mtab_ent_t));
-		if (mtab_ent == NULL) {
-			rc = ENOMEM;
-			goto exit;
-		}
-
-		memset(mtab_ent, 0, sizeof(mtab_ent_t));
-
-		rc = async_data_read_start(exch, (void *) mtab_ent->mp,
-		    MAX_PATH_LEN);
-		if (rc != EOK)
-			goto exit;
-
-		rc = async_data_read_start(exch, (void *) mtab_ent->opts,
-			MAX_MNTOPTS_LEN);
-		if (rc != EOK)
-			goto exit;
-
-		rc = async_data_read_start(exch, (void *) mtab_ent->fs_name,
-			FS_NAME_MAXLEN);
-		if (rc != EOK)
-			goto exit;
-
-		sysarg_t p[2];
-
-		rc = async_req_0_2(exch, VFS_IN_PING, &p[0], &p[1]);
-		if (rc != EOK)
-			goto exit;
-
-		mtab_ent->instance = p[0];
-		mtab_ent->service_id = p[1];
-
-		link_initialize(&mtab_ent->link);
-		list_append(&mtab_ent->link, mtab_list);
-	}
-
-exit:
-	async_wait_for(req, &rc);
-	vfs_exchange_end(exch);
-	return rc;
-}
-
-/** Get filesystem statistics.
- *
- * @param path Mount point path
- * @param st Buffer for storing information
- * @return 0 on success. On error -1 is returned and errno is set.
- */
-int statfs(const char *path, struct statfs *st)
-{
-	sysarg_t rc, rc_orig;
-	aid_t req;
-	size_t pa_size;
-
-	char *pa = vfs_absolutize(path, &pa_size);
-	if (pa == NULL) {
-		errno = ENOMEM;
-		return -1;
-	}
-
-	async_exch_t *exch = vfs_exchange_begin();
-
-	req = async_send_0(exch, VFS_IN_STATFS, NULL);
-	rc = async_data_write_start(exch, pa, pa_size);
-	if (rc != EOK)
-		goto exit;
-
-	rc = async_data_read_start(exch, (void *) st, sizeof(*st));
-
-exit:
-	vfs_exchange_end(exch);
-	free(pa);
-	async_wait_for(req, &rc_orig);
-	rc = (rc_orig != EOK ? rc_orig : rc);
-
-	if (rc != EOK) {
-		errno = rc;
-		return -1;
-	}
-
-	return 0;
+		return rc;
+	
+	*nwritten = (ssize_t) IPC_GET_ARG1(answer);
+	return EOK;
 }
 
Index: uspace/lib/c/include/dirent.h
===================================================================
--- uspace/lib/c/include/dirent.h	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/lib/c/include/dirent.h	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -38,4 +38,6 @@
 #define NAME_MAX  256
 
+#include <sys/types.h>
+
 struct dirent {
 	char d_name[NAME_MAX + 1];
@@ -45,4 +47,5 @@
 	int fd;
 	struct dirent res;
+	aoff64_t pos;
 } DIR;
 
Index: uspace/lib/c/include/elf/elf_load.h
===================================================================
--- uspace/lib/c/include/elf/elf_load.h	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/lib/c/include/elf/elf_load.h	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -45,5 +45,5 @@
 } elf_info_t;
 
-extern int elf_load(const char *, elf_info_t *);
+extern int elf_load(int, elf_info_t *);
 extern void elf_set_pcb(elf_info_t *, pcb_t *);
 
Index: uspace/lib/c/include/elf/elf_mod.h
===================================================================
--- uspace/lib/c/include/elf/elf_mod.h	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/lib/c/include/elf/elf_mod.h	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -108,5 +108,6 @@
 
 extern const char *elf_error(unsigned int);
-extern int elf_load_file(const char *, size_t, eld_flags_t, elf_finfo_t *);
+extern int elf_load_file(int, size_t, eld_flags_t, elf_finfo_t *);
+extern int elf_load_file_name(const char *, size_t, eld_flags_t, elf_finfo_t *);
 
 #endif
Index: pace/lib/c/include/fcntl.h
===================================================================
--- uspace/lib/c/include/fcntl.h	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ 	(revision )
@@ -1,52 +1,0 @@
-/*
- * Copyright (c) 2007 Jakub Jermar
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup libc
- * @{
- */
-/** @file
- */
-
-#ifndef LIBC_FCNTL_H_
-#define LIBC_FCNTL_H_
-
-#define O_CREAT   1
-#define O_EXCL    2
-#define O_TRUNC   4
-#define O_APPEND  8
-#define O_RDONLY  16
-#define O_RDWR    32
-#define O_WRONLY  64
-#define O_DESC    128
-
-extern int open(const char *, int, ...);
-
-#endif
-
-/** @}
- */
Index: uspace/lib/c/include/io/logctl.h
===================================================================
--- uspace/lib/c/include/io/logctl.h	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/lib/c/include/io/logctl.h	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -38,4 +38,5 @@
 extern int logctl_set_default_level(log_level_t);
 extern int logctl_set_log_level(const char *, log_level_t);
+extern int logctl_set_root(void);
 
 #endif
Index: uspace/lib/c/include/ipc/loader.h
===================================================================
--- uspace/lib/c/include/ipc/loader.h	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/lib/c/include/ipc/loader.h	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -42,7 +42,7 @@
 	LOADER_GET_TASKID,
 	LOADER_SET_CWD,
-	LOADER_SET_PATHNAME,
+	LOADER_SET_PROGRAM,
 	LOADER_SET_ARGS,
-	LOADER_SET_FILES,
+	LOADER_ADD_INBOX,
 	LOADER_LOAD,
 	LOADER_RUN
Index: uspace/lib/c/include/ipc/logger.h
===================================================================
--- uspace/lib/c/include/ipc/logger.h	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/lib/c/include/ipc/logger.h	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -49,5 +49,11 @@
 	 * Followed by: string with full log name.
 	 */
-	LOGGER_CONTROL_SET_LOG_LEVEL
+	LOGGER_CONTROL_SET_LOG_LEVEL,
+	/** Set VFS root.
+	 *
+	 * Returns: error code
+	 * Followed by: vfs_pass_handle() request.
+	 */ 
+	LOGGER_CONTROL_SET_ROOT
 } logger_control_request_t;
 
Index: uspace/lib/c/include/ipc/vfs.h
===================================================================
--- uspace/lib/c/include/ipc/vfs.h	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/lib/c/include/ipc/vfs.h	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -41,5 +41,5 @@
 
 #define FS_NAME_MAXLEN  20
-#define MAX_PATH_LEN    (64 * 1024)
+#define MAX_PATH_LEN    (32 * 1024)
 #define MAX_MNTOPTS_LEN 256
 #define PLB_SIZE        (2 * MAX_PATH_LEN)
@@ -63,41 +63,37 @@
 
 typedef enum {
-	VFS_IN_OPEN = IPC_FIRST_USER_METHOD,
+	VFS_IN_CLONE = IPC_FIRST_USER_METHOD,
+	VFS_IN_MOUNT,
+	VFS_IN_OPEN,
+	VFS_IN_PUT,
 	VFS_IN_READ,
+	VFS_IN_REGISTER,
+	VFS_IN_RENAME,
+	VFS_IN_RESIZE,
+	VFS_IN_STAT,
+	VFS_IN_STATFS,
+	VFS_IN_SYNC,
+	VFS_IN_UNLINK,
+	VFS_IN_UNMOUNT,
+	VFS_IN_WAIT_HANDLE,
+	VFS_IN_WALK,
 	VFS_IN_WRITE,
-	VFS_IN_SEEK,
-	VFS_IN_TRUNCATE,
-	VFS_IN_FSTAT,
-	VFS_IN_CLOSE,
-	VFS_IN_PING,
-	VFS_IN_MOUNT,
-	VFS_IN_UNMOUNT,
-	VFS_IN_SYNC,
-	VFS_IN_REGISTER,
-	VFS_IN_MKDIR,
-	VFS_IN_UNLINK,
-	VFS_IN_RENAME,
-	VFS_IN_STAT,
-	VFS_IN_DUP,
-	VFS_IN_WAIT_HANDLE,
-	VFS_IN_MTAB_GET,
-	VFS_IN_STATFS
 } vfs_in_request_t;
 
 typedef enum {
-	VFS_OUT_OPEN_NODE = IPC_FIRST_USER_METHOD,
+	VFS_OUT_CLOSE = IPC_FIRST_USER_METHOD,
+	VFS_OUT_DESTROY,
+	VFS_OUT_IS_EMPTY,
+	VFS_OUT_LINK,
+	VFS_OUT_LOOKUP,
+	VFS_OUT_MOUNTED,
+	VFS_OUT_OPEN_NODE,
 	VFS_OUT_READ,
+	VFS_OUT_STAT,
+	VFS_OUT_STATFS,
+	VFS_OUT_SYNC,
+	VFS_OUT_TRUNCATE,
+	VFS_OUT_UNMOUNTED,
 	VFS_OUT_WRITE,
-	VFS_OUT_TRUNCATE,
-	VFS_OUT_CLOSE,
-	VFS_OUT_MOUNT,
-	VFS_OUT_MOUNTED,
-	VFS_OUT_UNMOUNT,
-	VFS_OUT_UNMOUNTED,
-	VFS_OUT_SYNC,
-	VFS_OUT_STAT,
-	VFS_OUT_LOOKUP,
-	VFS_OUT_DESTROY,
-	VFS_OUT_STATFS,
 	VFS_OUT_LAST
 } vfs_out_request_t;
@@ -127,12 +123,12 @@
 
 /**
- * Lookup will succeed only if the object is a root directory. The flag is
- * mutually exclusive with L_FILE and L_MP.
+ * Lookup will not cross any mount points.
+ * If the lookup would have to cross a mount point, it returns EXDEV instead.
  */
-#define L_ROOT			4
+#define L_DISABLE_MOUNTS	4
 
 /**
  * Lookup will succeed only if the object is a mount point. The flag is mutually
- * exclusive with L_FILE and L_ROOT.
+ * exclusive with L_FILE.
  */
 #define L_MP			8
@@ -151,22 +147,36 @@
 
 /**
- * L_LINK is used for linking to an already existing nodes.
- */
-#define L_LINK			64
-
-/**
  * L_UNLINK is used to remove leaves from the file system namespace. This flag
  * cannot be passed directly by the client, but will be set by VFS during
  * VFS_UNLINK.
  */
-#define L_UNLINK		128
+#define L_UNLINK		64
 
-/**
- * L_OPEN is used to indicate that the lookup operation is a part of VFS_IN_OPEN
- * call from the client. This means that the server might allocate some
- * resources for the opened file. This flag cannot be passed directly by the
- * client.
+/*
+ * Walk flags.
  */
-#define L_OPEN			256
+enum {
+	WALK_MAY_CREATE = (1 << 0),
+	WALK_MUST_CREATE = (1 << 1),
+	
+	WALK_REGULAR = (1 << 2),
+	WALK_DIRECTORY = (1 << 3),
+	WALK_MOUNT_POINT = (1 << 4),
+	
+	WALK_ALL_FLAGS = WALK_MAY_CREATE | WALK_MUST_CREATE | WALK_REGULAR |
+	    WALK_DIRECTORY | WALK_MOUNT_POINT,
+};
+
+enum {
+	VFS_MOUNT_BLOCKING = 1,
+	VFS_MOUNT_CONNECT_ONLY = 2,
+	VFS_MOUNT_NO_REF = 4,
+};
+
+enum {
+	MODE_READ = 1,
+	MODE_WRITE = 2,
+	MODE_APPEND = 4,
+};
 
 #endif
Index: uspace/lib/c/include/loader/loader.h
===================================================================
--- uspace/lib/c/include/loader/loader.h	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/lib/c/include/loader/loader.h	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -47,7 +47,8 @@
 extern int loader_get_task_id(loader_t *, task_id_t *);
 extern int loader_set_cwd(loader_t *);
-extern int loader_set_pathname(loader_t *, const char *);
+extern int loader_set_program(loader_t *, const char *, int);
+extern int loader_set_program_path(loader_t *, const char *);
 extern int loader_set_args(loader_t *, const char *const[]);
-extern int loader_set_files(loader_t *, int *const[]);
+extern int loader_add_inbox(loader_t *, const char *, int);
 extern int loader_load_program(loader_t *);
 extern int loader_run(loader_t *);
Index: uspace/lib/c/include/loader/pcb.h
===================================================================
--- uspace/lib/c/include/loader/pcb.h	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/lib/c/include/loader/pcb.h	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -41,4 +41,9 @@
 typedef void (*entry_point_t)(void);
 
+struct pcb_inbox_entry {
+	char *name;
+	int file;
+};
+
 /** Program Control Block.
  *
@@ -60,6 +65,7 @@
 	char **argv;
 	
-	/** Number of preset files. */
-	unsigned int filc;
+	/** List of inbox files. */
+	struct pcb_inbox_entry *inbox;
+	int inbox_entries;
 	
 	/*
Index: uspace/lib/c/include/stdio.h
===================================================================
--- uspace/lib/c/include/stdio.h	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/lib/c/include/stdio.h	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -44,15 +44,4 @@
 #define EOF  (-1)
 
-/** Default size for stream I/O buffers */
-#define BUFSIZ  4096
-
-#define DEBUG(fmt, ...) \
-	{ \
-		char _buf[256]; \
-		int _n = snprintf(_buf, sizeof(_buf), fmt, ##__VA_ARGS__); \
-		if (_n > 0) \
-			(void) __SYSCALL3(SYS_KIO, KIO_WRITE, (sysarg_t) _buf, str_size(_buf)); \
-	}
-
 #ifndef SEEK_SET
 	#define SEEK_SET  0
@@ -66,4 +55,15 @@
 	#define SEEK_END  2
 #endif
+
+/** Default size for stream I/O buffers */
+#define BUFSIZ  4096
+
+#define DEBUG(fmt, ...) \
+	{ \
+		char _buf[256]; \
+		int _n = snprintf(_buf, sizeof(_buf), fmt, ##__VA_ARGS__); \
+		if (_n > 0) \
+			(void) __SYSCALL3(SYS_KIO, KIO_WRITE, (sysarg_t) _buf, str_size(_buf)); \
+	}
 
 enum _buffer_type {
@@ -153,8 +153,4 @@
 extern void setbuf(FILE *, void *);
 
-/* Misc file functions */
-extern int rename(const char *, const char *);
-extern int remove(const char *);
-
 #endif
 
Index: uspace/lib/c/include/stdlib.h
===================================================================
--- uspace/lib/c/include/stdlib.h	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/lib/c/include/stdlib.h	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -49,4 +49,5 @@
 
 extern void abort(void) __attribute__((noreturn));
+extern void exit(int) __attribute__((noreturn));
 
 #endif
Index: pace/lib/c/include/sys/stat.h
===================================================================
--- uspace/lib/c/include/sys/stat.h	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ 	(revision )
@@ -1,61 +1,0 @@
-/*
- * Copyright (c) 2008 Jakub Jermar
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup libc
- * @{
- */
-/** @file
- */
-
-#ifndef LIBC_SYS_STAT_H_
-#define LIBC_SYS_STAT_H_
-
-#include <sys/types.h>
-#include <stdbool.h>
-#include <ipc/vfs.h>
-#include <ipc/loc.h>
-
-struct stat {
-	fs_handle_t fs_handle;
-	service_id_t service_id;
-	fs_index_t index;
-	unsigned int lnkcnt;
-	bool is_file;
-	bool is_directory;
-	aoff64_t size;
-	service_id_t service;
-};
-
-extern int fstat(int, struct stat *);
-extern int stat(const char *, struct stat *);
-extern int mkdir(const char *, mode_t);
-
-#endif
-
-/** @}
- */
Index: pace/lib/c/include/sys/statfs.h
===================================================================
--- uspace/lib/c/include/sys/statfs.h	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ 	(revision )
@@ -1,52 +1,0 @@
-/*
- * Copyright (c) 2013 Manuele Conti
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup libc
- * @{
- */
-/** @file
- */
-
-#ifndef LIBC_SYS_STATFS_H_
-#define LIBC_SYS_STATFS_H_
-
-#include <sys/types.h>
-
-struct statfs { 
-	uint32_t    f_type;     /* type of file system  */
-	uint32_t    f_bsize;    /* fundamental file system block size */
-	uint64_t    f_blocks;   /* total data blocks in file system */
-	uint64_t    f_bfree;    /* free blocks in fs */
-};
-
-extern int statfs(const char *, struct statfs *);
-
-#endif
-
-/** @}
- */
Index: uspace/lib/c/include/sys/types.h
===================================================================
--- uspace/lib/c/include/sys/types.h	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/lib/c/include/sys/types.h	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -38,6 +38,4 @@
 #include <libarch/types.h>
 
-typedef unsigned int mode_t;
-
 /** Relative offset */
 typedef int64_t off64_t;
Index: uspace/lib/c/include/task.h
===================================================================
--- uspace/lib/c/include/task.h	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/lib/c/include/task.h	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -57,5 +57,5 @@
     const char *const []);
 extern int task_spawnvf(task_id_t *, task_wait_t *, const char *path,
-    const char *const [], int *const []);
+    const char *const [], int, int, int);
 extern int task_spawn(task_id_t *, task_wait_t *, const char *path, int,
     va_list ap);
Index: uspace/lib/c/include/unistd.h
===================================================================
--- uspace/lib/c/include/unistd.h	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/lib/c/include/unistd.h	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -44,35 +44,6 @@
 #endif
 
-#ifndef SEEK_SET
-	#define SEEK_SET  0
-#endif
-
-#ifndef SEEK_CUR
-	#define SEEK_CUR  1
-#endif
-
-#ifndef SEEK_END
-	#define SEEK_END  2
-#endif
-
 #define getpagesize()  (PAGE_SIZE)
 
-extern int dup2(int, int);
-
-extern ssize_t write(int, const void *, size_t);
-extern ssize_t read(int, void *, size_t);
-
-extern off64_t lseek(int, off64_t, int);
-extern int ftruncate(int, aoff64_t);
-
-extern int close(int);
-extern int fsync(int);
-extern int unlink(const char *);
-
-extern char *getcwd(char *, size_t);
-extern int rmdir(const char *);
-extern int chdir(const char *);
-
-extern void exit(int) __attribute__((noreturn));
 extern int usleep(useconds_t);
 extern unsigned int sleep(unsigned int);
Index: uspace/lib/c/include/vfs/inbox.h
===================================================================
--- uspace/lib/c/include/vfs/inbox.h	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
+++ uspace/lib/c/include/vfs/inbox.h	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2013 Jiri Zarevucky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libc 
+ * @{
+ */ 
+
+/**
+ * @file
+ * @brief
+ */
+
+#ifndef LIBC_VFS_INBOX_H_
+#define LIBC_VFS_INBOX_H_
+
+enum {
+	INBOX_MAX_ENTRIES = 256,
+};
+
+extern int inbox_set(const char *name, int file);
+extern int inbox_get(const char *name);
+
+extern int inbox_list(const char **names, int capacity);
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/lib/c/include/vfs/vfs.h
===================================================================
--- uspace/lib/c/include/vfs/vfs.h	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/lib/c/include/vfs/vfs.h	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -42,6 +42,6 @@
 #include <stdio.h>
 #include <async.h>
-#include "vfs_mtab.h"
 
+#define MAX_OPEN_FILES	128
 
 enum vfs_change_state_type {
@@ -49,18 +49,66 @@
 };
 
+typedef enum {
+	KIND_FILE,
+	KIND_DIRECTORY,
+} vfs_file_kind_t;
 
-extern char *vfs_absolutize(const char *, size_t *);
 
-extern int vfs_mount(const char *, const char *, const char *, const char *,
-    unsigned int, unsigned int);
-extern int vfs_unmount(const char *);
+struct stat {
+	fs_handle_t fs_handle;
+	service_id_t service_id;
+	fs_index_t index;
+	unsigned int lnkcnt;
+	bool is_file;
+	bool is_directory;
+	aoff64_t size;
+	service_id_t service;
+};
+
+struct statfs { 
+	char fs_name[FS_NAME_MAXLEN + 1];
+	uint32_t f_bsize;    /* fundamental file system block size */
+	uint64_t f_blocks;   /* total data blocks in file system */
+	uint64_t f_bfree;    /* free blocks in fs */
+};
 
 extern int vfs_fhandle(FILE *, int *);
 
-extern int vfs_fd_wait(void);
-extern int vfs_get_mtab_list(list_t *mtab_list);
-
+extern char *vfs_absolutize(const char *, size_t *);
+extern int vfs_clone(int, int, bool);
+extern int vfs_cwd_get(char *path, size_t);
+extern int vfs_cwd_set(const char *path);
 extern async_exch_t *vfs_exchange_begin(void);
 extern void vfs_exchange_end(async_exch_t *);
+extern int vfs_link(int, const char *, vfs_file_kind_t, int *);
+extern int vfs_link_path(const char *, vfs_file_kind_t, int *);
+extern int vfs_lookup(const char *, int);
+extern int vfs_lookup_open(const char *, int, int);
+extern int vfs_mount_path(const char *, const char *, const char *,
+    const char *, unsigned int, unsigned int);
+extern int vfs_mount(int, const char *, service_id_t, const char *, unsigned,
+    unsigned, int *);
+extern int vfs_open(int, int);
+extern int vfs_pass_handle(async_exch_t *, int, async_exch_t *);
+extern int vfs_put(int);
+extern ssize_t vfs_read(int, aoff64_t *, void *, size_t);
+extern int vfs_read_short(int, aoff64_t, void *, size_t, ssize_t *);
+extern int vfs_receive_handle(bool);
+extern int vfs_rename_path(const char *, const char *);
+extern int vfs_resize(int, aoff64_t);
+extern int vfs_root(void);
+extern void vfs_root_set(int);
+extern int vfs_stat(int, struct stat *);
+extern int vfs_stat_path(const char *, struct stat *);
+extern int vfs_statfs(int, struct statfs *);
+extern int vfs_statfs_path(const char *, struct statfs *);
+extern int vfs_sync(int);
+extern int vfs_unlink(int, const char *, int);
+extern int vfs_unlink_path(const char *);
+extern int vfs_unmount(int);
+extern int vfs_unmount_path(const char *);
+extern int vfs_walk(int, const char *, int);
+extern ssize_t vfs_write(int, aoff64_t *, const void *, size_t);
+extern int vfs_write_short(int, aoff64_t, const void *, size_t, ssize_t *);
 
 #endif
Index: uspace/lib/c/include/vfs/vfs_mtab.h
===================================================================
--- uspace/lib/c/include/vfs/vfs_mtab.h	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/lib/c/include/vfs/vfs_mtab.h	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -43,9 +43,9 @@
 	link_t link;
 	char mp[MAX_PATH_LEN];
-	char opts[MAX_MNTOPTS_LEN];
 	char fs_name[FS_NAME_MAXLEN];
-	unsigned int instance;
 	service_id_t service_id;
 } mtab_ent_t;
+
+extern int vfs_get_mtab_list(list_t *);
 
 #endif
Index: uspace/lib/fs/libfs.c
===================================================================
--- uspace/lib/fs/libfs.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/lib/fs/libfs.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -36,5 +36,4 @@
 
 #include "libfs.h"
-#include "../../srv/vfs/vfs.h"
 #include <macros.h>
 #include <errno.h>
@@ -44,7 +43,9 @@
 #include <dirent.h>
 #include <mem.h>
-#include <sys/stat.h>
-#include <sys/statfs.h>
+#include <str.h>
 #include <stdlib.h>
+#include <fibril_synch.h>
+#include <ipc/vfs.h>
+#include <vfs/vfs.h>
 
 #define on_error(rc, action) \
@@ -68,6 +69,8 @@
 static libfs_ops_t *libfs_ops = NULL;
 
-static void libfs_mount(libfs_ops_t *, fs_handle_t, ipc_callid_t, ipc_call_t *);
-static void libfs_unmount(libfs_ops_t *, ipc_callid_t, ipc_call_t *);
+static char fs_name[FS_NAME_MAXLEN + 1];
+
+static void libfs_link(libfs_ops_t *, fs_handle_t, ipc_callid_t,
+    ipc_call_t *);
 static void libfs_lookup(libfs_ops_t *, fs_handle_t, ipc_callid_t,
     ipc_call_t *);
@@ -75,5 +78,6 @@
 static void libfs_open_node(libfs_ops_t *, fs_handle_t, ipc_callid_t,
     ipc_call_t *);
-static void libfs_statfs(libfs_ops_t *, fs_handle_t, ipc_callid_t, ipc_call_t *);
+static void libfs_statfs(libfs_ops_t *, fs_handle_t, ipc_callid_t,
+    ipc_call_t *);
 
 static void vfs_out_mounted(ipc_callid_t rid, ipc_call_t *req)
@@ -104,9 +108,4 @@
 }
 
-static void vfs_out_mount(ipc_callid_t rid, ipc_call_t *req)
-{
-	libfs_mount(libfs_ops, reg.fs_handle, rid, req);
-}
-
 static void vfs_out_unmounted(ipc_callid_t rid, ipc_call_t *req)
 {
@@ -119,8 +118,7 @@
 }
 
-static void vfs_out_unmount(ipc_callid_t rid, ipc_call_t *req)
-{
-		
-	libfs_unmount(libfs_ops, rid, req);
+static void vfs_out_link(ipc_callid_t rid, ipc_call_t *req)
+{
+	libfs_link(libfs_ops, reg.fs_handle, rid, req);
 }
 
@@ -159,7 +157,8 @@
 	rc = vfs_out_ops->write(service_id, index, pos, &wbytes, &nsize);
 
-	if (rc == EOK)
-		async_answer_3(rid, EOK, wbytes, LOWER32(nsize), UPPER32(nsize));
-	else
+	if (rc == EOK) {
+		async_answer_3(rid, EOK, wbytes, LOWER32(nsize),
+		    UPPER32(nsize));
+	} else
 		async_answer_0(rid, rc);
 }
@@ -193,8 +192,14 @@
 	service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
 	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req);
+
 	int rc;
-
-	rc = vfs_out_ops->destroy(service_id, index);
-
+	fs_node_t *node = NULL;
+	rc = libfs_ops->node_get(&node, service_id, index);
+	if (rc == EOK && node != NULL) {
+		bool destroy = (libfs_ops->lnkcnt_get(node) == 0);
+		libfs_ops->node_put(node);
+		if (destroy)
+			rc = vfs_out_ops->destroy(service_id, index);
+	}
 	async_answer_0(rid, rc);
 }
@@ -225,4 +230,27 @@
 	libfs_statfs(libfs_ops, reg.fs_handle, rid, req);
 }
+
+static void vfs_out_is_empty(ipc_callid_t rid, ipc_call_t *req)
+{
+	service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
+	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req);
+	int rc;
+
+	fs_node_t *node = NULL;
+	rc = libfs_ops->node_get(&node, service_id, index);
+	if (rc != EOK)
+		async_answer_0(rid, rc);
+	if (node == NULL)
+		async_answer_0(rid, EINVAL);
+	
+	bool children = false;
+	rc = libfs_ops->has_children(&children, node);
+	libfs_ops->node_put(node);
+	
+	if (rc != EOK)
+		async_answer_0(rid, rc);
+	async_answer_0(rid, children ? ENOTEMPTY : EOK);
+}
+
 static void vfs_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
 {
@@ -247,12 +275,9 @@
 			vfs_out_mounted(callid, &call);
 			break;
-		case VFS_OUT_MOUNT:
-			vfs_out_mount(callid, &call);
-			break;
 		case VFS_OUT_UNMOUNTED:
 			vfs_out_unmounted(callid, &call);
 			break;
-		case VFS_OUT_UNMOUNT:
-			vfs_out_unmount(callid, &call);
+		case VFS_OUT_LINK:
+			vfs_out_link(callid, &call);
 			break;
 		case VFS_OUT_LOOKUP:
@@ -285,4 +310,7 @@
 		case VFS_OUT_STATFS:
 			vfs_out_statfs(callid, &call);
+			break;
+		case VFS_OUT_IS_EMPTY:
+			vfs_out_is_empty(callid, &call);
 			break;
 		default:
@@ -338,4 +366,6 @@
 	vfs_out_ops = vops;
 	libfs_ops = lops;
+
+	str_cpy(fs_name, sizeof(fs_name), info->name);
 
 	/*
@@ -383,116 +413,88 @@
 }
 
-void libfs_mount(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_callid_t rid,
+static char plb_get_char(unsigned pos)
+{
+	return reg.plb_ro[pos % PLB_SIZE];
+}
+
+static int plb_get_component(char *dest, unsigned *sz, unsigned *ppos,
+    unsigned last)
+{
+	unsigned pos = *ppos;
+	unsigned size = 0;
+	
+	if (pos == last) {
+		*sz = 0;
+		return ERANGE;
+	}
+
+	char c = plb_get_char(pos); 
+	if (c == '/')
+		pos++;
+	
+	for (int i = 0; i <= NAME_MAX; i++) {
+		c = plb_get_char(pos);
+		if (pos == last || c == '/') {
+			dest[i] = 0;
+			*ppos = pos;
+			*sz = size;
+			return EOK;
+		}
+		dest[i] = c;
+		pos++;
+		size++;
+	}
+	return ENAMETOOLONG;
+}
+
+static int receive_fname(char *buffer)
+{
+	size_t size;
+	ipc_callid_t wcall;
+	
+	if (!async_data_write_receive(&wcall, &size))
+		return ENOENT;
+	if (size > NAME_MAX + 1) {
+		async_answer_0(wcall, ERANGE);
+		return ERANGE;
+	}
+	return async_data_write_finalize(wcall, buffer, size);
+}
+
+/** Link a file at a path.
+ */
+void libfs_link(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_callid_t rid,
     ipc_call_t *req)
 {
-	service_id_t mp_service_id = (service_id_t) IPC_GET_ARG1(*req);
-	fs_index_t mp_fs_index = (fs_index_t) IPC_GET_ARG2(*req);
-	fs_handle_t mr_fs_handle = (fs_handle_t) IPC_GET_ARG3(*req);
-	service_id_t mr_service_id = (service_id_t) IPC_GET_ARG4(*req);
-	
-	async_sess_t *mountee_sess = async_clone_receive(EXCHANGE_PARALLEL);
-	if (mountee_sess == NULL) {
-		async_answer_0(rid, EINVAL);
+	service_id_t parent_sid = IPC_GET_ARG1(*req);
+	fs_index_t parent_index = IPC_GET_ARG2(*req);
+	fs_index_t child_index = IPC_GET_ARG3(*req);
+	
+	char component[NAME_MAX + 1];
+	int rc = receive_fname(component);
+	if (rc != EOK) {
+		async_answer_0(rid, rc);
 		return;
 	}
-	
-	fs_node_t *fn;
-	int res = ops->node_get(&fn, mp_service_id, mp_fs_index);
-	if ((res != EOK) || (!fn)) {
-		async_hangup(mountee_sess);
-		async_data_write_void(combine_rc(res, ENOENT));
-		async_answer_0(rid, combine_rc(res, ENOENT));
+
+	fs_node_t *parent = NULL;
+	rc = ops->node_get(&parent, parent_sid, parent_index);
+	if (parent == NULL) {
+		async_answer_0(rid, rc == EOK ? EBADF : rc);
 		return;
 	}
 	
-	if (fn->mp_data.mp_active) {
-		async_hangup(mountee_sess);
-		(void) ops->node_put(fn);
-		async_data_write_void(EBUSY);
-		async_answer_0(rid, EBUSY);
+	fs_node_t *child = NULL;
+	rc = ops->node_get(&child, parent_sid, child_index);
+	if (child == NULL) {
+		async_answer_0(rid, rc == EOK ? EBADF : rc);
+		ops->node_put(parent);
 		return;
 	}
 	
-	async_exch_t *exch = async_exchange_begin(mountee_sess);
-	async_sess_t *sess = async_clone_establish(EXCHANGE_PARALLEL, exch);
-	
-	if (!sess) {
-		async_exchange_end(exch);
-		async_hangup(mountee_sess);
-		(void) ops->node_put(fn);
-		async_data_write_void(errno);
-		async_answer_0(rid, errno);
-		return;
-	}
-	
-	ipc_call_t answer;
-	int rc = async_data_write_forward_1_1(exch, VFS_OUT_MOUNTED,
-	    mr_service_id, &answer);
-	async_exchange_end(exch);
-	
-	if (rc == EOK) {
-		fn->mp_data.mp_active = true;
-		fn->mp_data.fs_handle = mr_fs_handle;
-		fn->mp_data.service_id = mr_service_id;
-		fn->mp_data.sess = mountee_sess;
-	}
-	
-	/*
-	 * Do not release the FS node so that it stays in memory.
-	 */
-	async_answer_4(rid, rc, IPC_GET_ARG1(answer), IPC_GET_ARG2(answer),
-	    IPC_GET_ARG3(answer), IPC_GET_ARG4(answer));
-}
-
-void libfs_unmount(libfs_ops_t *ops, ipc_callid_t rid, ipc_call_t *req)
-{
-	service_id_t mp_service_id = (service_id_t) IPC_GET_ARG1(*req);
-	fs_index_t mp_fs_index = (fs_index_t) IPC_GET_ARG2(*req);
-	fs_node_t *fn;
-	int res;
-
-	res = ops->node_get(&fn, mp_service_id, mp_fs_index);
-	if ((res != EOK) || (!fn)) {
-		async_answer_0(rid, combine_rc(res, ENOENT));
-		return;
-	}
-
-	/*
-	 * We are clearly expecting to find the mount point active.
-	 */
-	if (!fn->mp_data.mp_active) {
-		(void) ops->node_put(fn);
-		async_answer_0(rid, EINVAL);
-		return;
-	}
-
-	/*
-	 * Tell the mounted file system to unmount.
-	 */
-	async_exch_t *exch = async_exchange_begin(fn->mp_data.sess);
-	res = async_req_1_0(exch, VFS_OUT_UNMOUNTED, fn->mp_data.service_id);
-	async_exchange_end(exch);
-
-	/*
-	 * If everything went well, perform the clean-up on our side.
-	 */
-	if (res == EOK) {
-		async_hangup(fn->mp_data.sess);
-		fn->mp_data.mp_active = false;
-		fn->mp_data.fs_handle = 0;
-		fn->mp_data.service_id = 0;
-		fn->mp_data.sess = NULL;
-		
-		/* Drop the reference created in libfs_mount(). */
-		(void) ops->node_put(fn);
-	}
-
-	(void) ops->node_put(fn);
-	async_answer_0(rid, res);
-}
-
-static char plb_get_char(unsigned pos)
-{
-	return reg.plb_ro[pos % PLB_SIZE];
+	rc = ops->link(parent, child, component);
+	ops->node_put(parent);
+	ops->node_put(child);
+	async_answer_0(rid, rc);
 }
 
@@ -513,284 +515,171 @@
     ipc_call_t *req)
 {
-	unsigned int first = IPC_GET_ARG1(*req);
-	unsigned int last = IPC_GET_ARG2(*req);
-	unsigned int next = first;
+	unsigned first = IPC_GET_ARG1(*req);
+	unsigned len = IPC_GET_ARG2(*req);
 	service_id_t service_id = IPC_GET_ARG3(*req);
-	int lflag = IPC_GET_ARG4(*req);
-	fs_index_t index = IPC_GET_ARG5(*req);
+	fs_index_t index = IPC_GET_ARG4(*req);
+	int lflag = IPC_GET_ARG5(*req);
+	
+	// TODO: Validate flags.
+	
+	unsigned next = first;
+	unsigned last = first + len;
+	
 	char component[NAME_MAX + 1];
-	int len;
 	int rc;
-	
-	if (last < next)
-		last += PLB_SIZE;
 	
 	fs_node_t *par = NULL;
 	fs_node_t *cur = NULL;
 	fs_node_t *tmp = NULL;
-	
-	rc = ops->root_get(&cur, service_id);
-	on_error(rc, goto out_with_answer);
-	
-	if (cur->mp_data.mp_active) {
-		async_exch_t *exch = async_exchange_begin(cur->mp_data.sess);
-		async_forward_slow(rid, exch, VFS_OUT_LOOKUP, next, last,
-		    cur->mp_data.service_id, lflag, index,
-		    IPC_FF_ROUTE_FROM_ME);
-		async_exchange_end(exch);
+	unsigned clen = 0;
+	
+	rc = ops->node_get(&cur, service_id, index);
+	if (rc != EOK) {
+		async_answer_0(rid, rc);
+		goto out;
+	}
+	
+	assert(cur != NULL);
+	
+	/* Find the file and its parent. */
+	
+	unsigned last_next = 0;
+	
+	while (next != last) {
+		if (cur == NULL) {
+			assert(par != NULL);
+			goto out1;
+		}
+
+		if (!ops->is_directory(cur)) {
+			async_answer_0(rid, ENOTDIR);
+			goto out;
+		}
 		
-		(void) ops->node_put(cur);
-		return;
-	}
-	
-	/* Eat slash */
-	if (plb_get_char(next) == '/')
-		next++;
-	
-	while (next <= last) {
-		bool has_children;
+		last_next = next;
+		/* Collect the component */
+		rc = plb_get_component(component, &clen, &next, last);
+		assert(rc != ERANGE);
+		if (rc != EOK) {
+			async_answer_0(rid, rc);
+			goto out;
+		}
 		
-		rc = ops->has_children(&has_children, cur);
-		on_error(rc, goto out_with_answer);
-		if (!has_children)
-			break;
+		if (clen == 0) {
+			/* The path is just "/". */
+			break;
+		}
 		
-		/* Collect the component */
-		len = 0;
-		while ((next <= last) && (plb_get_char(next) != '/')) {
-			if (len + 1 == NAME_MAX) {
-				/* Component length overflow */
-				async_answer_0(rid, ENAMETOOLONG);
-				goto out;
-			}
-			component[len++] = plb_get_char(next);
-			/* Process next character */
-			next++;
-		}
-		
-		assert(len);
-		component[len] = '\0';
-		/* Eat slash */
-		next++;
+		assert(component[clen] == 0);
 		
 		/* Match the component */
 		rc = ops->match(&tmp, cur, component);
-		on_error(rc, goto out_with_answer);
+		if (rc != EOK) {
+			async_answer_0(rid, rc);
+			goto out;
+		}
 		
-		/*
-		 * If the matching component is a mount point, there are two
-		 * legitimate semantics of the lookup operation. The first is
-		 * the commonly used one in which the lookup crosses each mount
-		 * point into the mounted file system. The second semantics is
-		 * used mostly during unmount() and differs from the first one
-		 * only in that the last mount point in the looked up path,
-		 * which is also its last component, is not crossed.
-		 */
-
-		if ((tmp) && (tmp->mp_data.mp_active) &&
-		    (!(lflag & L_MP) || (next <= last))) {
-			if (next > last)
-				next = last = first;
-			else
-				next--;
-			
-			async_exch_t *exch = async_exchange_begin(tmp->mp_data.sess);
-			async_forward_slow(rid, exch, VFS_OUT_LOOKUP, next,
-			    last, tmp->mp_data.service_id, lflag, index,
-			    IPC_FF_ROUTE_FROM_ME);
-			async_exchange_end(exch);
-			
-			(void) ops->node_put(cur);
-			(void) ops->node_put(tmp);
-			if (par)
-				(void) ops->node_put(par);
-			return;
+		/* Descend one level */
+		if (par) {
+			rc = ops->node_put(par);
+			if (rc != EOK) {
+				async_answer_0(rid, rc);
+				goto out;
+			}
 		}
 		
-		/* Handle miss: match amongst siblings */
-		if (!tmp) {
-			if (next <= last) {
-				/* There are unprocessed components */
-				async_answer_0(rid, ENOENT);
+		par = cur;
+		cur = tmp;
+		tmp = NULL;
+	}
+	
+	/* At this point, par is either NULL or a directory.
+	 * If cur is NULL, the looked up file does not exist yet.
+	 */
+	 
+	assert(par == NULL || ops->is_directory(par));
+	assert(par != NULL || cur != NULL);
+	
+	/* Check for some error conditions. */
+	
+	if (cur && (lflag & L_FILE) && (ops->is_directory(cur))) {
+		async_answer_0(rid, EISDIR);
+		goto out;
+	}
+	
+	if (cur && (lflag & L_DIRECTORY) && (ops->is_file(cur))) {
+		async_answer_0(rid, ENOTDIR);
+		goto out;
+	}
+	
+	/* Unlink. */
+	
+	if (lflag & L_UNLINK) {
+		if (!cur) {
+			async_answer_0(rid, ENOENT);
+			goto out;
+		}
+		if (!par) {
+			async_answer_0(rid, EINVAL);
+			goto out;
+		}
+		
+		rc = ops->unlink(par, cur, component);
+		if (rc == EOK) {
+			aoff64_t size = ops->size_get(cur);
+			async_answer_5(rid, fs_handle, service_id,
+			    ops->index_get(cur),
+			    (ops->is_directory(cur) << 16) | last,
+			    LOWER32(size), UPPER32(size));
+		} else {
+			async_answer_0(rid, rc);
+		}
+		goto out;
+	}
+	
+	/* Create. */
+	
+	if (lflag & L_CREATE) {
+		if (cur && (lflag & L_EXCLUSIVE)) {
+			async_answer_0(rid, EEXIST);
+			goto out;
+		}
+	
+		if (!cur) {
+			rc = ops->create(&cur, service_id,
+			    lflag & (L_FILE | L_DIRECTORY));
+			if (rc != EOK) {
+				async_answer_0(rid, rc);
+				goto out;
+			}
+			if (!cur) {
+				async_answer_0(rid, ENOSPC);
 				goto out;
 			}
 			
-			/* Miss in the last component */
-			if (lflag & (L_CREATE | L_LINK)) {
-				/* Request to create a new link */
-				if (!ops->is_directory(cur)) {
-					async_answer_0(rid, ENOTDIR);
-					goto out;
-				}
-				
-				fs_node_t *fn;
-				if (lflag & L_CREATE)
-					rc = ops->create(&fn, service_id,
-					    lflag);
-				else
-					rc = ops->node_get(&fn, service_id,
-					    index);
-				on_error(rc, goto out_with_answer);
-				
-				if (fn) {
-					rc = ops->link(cur, fn, component);
-					if (rc != EOK) {
-						if (lflag & L_CREATE)
-							(void) ops->destroy(fn);
-						else
-							(void) ops->node_put(fn);
-						async_answer_0(rid, rc);
-					} else {
-						(void) ops->node_put(cur);
-						cur = fn;
-						goto out_with_answer;
-					}
-				} else
-					async_answer_0(rid, ENOSPC);
-				
+			rc = ops->link(par, cur, component);
+			if (rc != EOK) {
+				(void) ops->destroy(cur);
+				cur = NULL;
+				async_answer_0(rid, rc);
 				goto out;
 			}
-			
-			async_answer_0(rid, ENOENT);
-			goto out;
-		}
-		
-		if (par) {
-			rc = ops->node_put(par);
-			on_error(rc, goto out_with_answer);
-		}
-		
-		/* Descend one level */
-		par = cur;
-		cur = tmp;
-		tmp = NULL;
-	}
-	
-	/* Handle miss: excessive components */
-	if (next <= last) {
-		bool has_children;
-		rc = ops->has_children(&has_children, cur);
-		on_error(rc, goto out_with_answer);
-		
-		if (has_children)
-			goto skip_miss;
-		
-		if (lflag & (L_CREATE | L_LINK)) {
-			if (!ops->is_directory(cur)) {
-				async_answer_0(rid, ENOTDIR);
-				goto out;
-			}
-			
-			/* Collect next component */
-			len = 0;
-			while (next <= last) {
-				if (plb_get_char(next) == '/') {
-					/* More than one component */
-					async_answer_0(rid, ENOENT);
-					goto out;
-				}
-				
-				if (len + 1 == NAME_MAX) {
-					/* Component length overflow */
-					async_answer_0(rid, ENAMETOOLONG);
-					goto out;
-				}
-				
-				component[len++] = plb_get_char(next);
-				/* Process next character */
-				next++;
-			}
-			
-			assert(len);
-			component[len] = '\0';
-			
-			fs_node_t *fn;
-			if (lflag & L_CREATE)
-				rc = ops->create(&fn, service_id, lflag);
-			else
-				rc = ops->node_get(&fn, service_id, index);
-			on_error(rc, goto out_with_answer);
-			
-			if (fn) {
-				rc = ops->link(cur, fn, component);
-				if (rc != EOK) {
-					if (lflag & L_CREATE)
-						(void) ops->destroy(fn);
-					else
-						(void) ops->node_put(fn);
-					async_answer_0(rid, rc);
-				} else {
-					(void) ops->node_put(cur);
-					cur = fn;
-					goto out_with_answer;
-				}
-			} else
-				async_answer_0(rid, ENOSPC);
-			
-			goto out;
-		}
-		
-		async_answer_0(rid, ENOENT);
+		}
+	}
+	
+	/* Return. */
+out1:
+	if (!cur) {
+		async_answer_5(rid, fs_handle, service_id, ops->index_get(par),
+		    last_next, -1, true);
 		goto out;
 	}
 	
-skip_miss:
-	
-	/* Handle hit */
-	if (lflag & L_UNLINK) {
-		unsigned int old_lnkcnt = ops->lnkcnt_get(cur);
-		rc = ops->unlink(par, cur, component);
-		
-		if (rc == EOK) {
-			aoff64_t size = ops->size_get(cur);
-			async_answer_5(rid, fs_handle, service_id,
-			    ops->index_get(cur), LOWER32(size), UPPER32(size),
-			    old_lnkcnt);
-		} else
-			async_answer_0(rid, rc);
-		
-		goto out;
-	}
-	
-	if (((lflag & (L_CREATE | L_EXCLUSIVE)) == (L_CREATE | L_EXCLUSIVE)) ||
-	    (lflag & L_LINK)) {
-		async_answer_0(rid, EEXIST);
-		goto out;
-	}
-	
-	if ((lflag & L_FILE) && (ops->is_directory(cur))) {
-		async_answer_0(rid, EISDIR);
-		goto out;
-	}
-	
-	if ((lflag & L_DIRECTORY) && (ops->is_file(cur))) {
-		async_answer_0(rid, ENOTDIR);
-		goto out;
-	}
-
-	if ((lflag & L_ROOT) && par) {
-		async_answer_0(rid, EINVAL);
-		goto out;
-	}
-	
-out_with_answer:
-	
-	if (rc == EOK) {
-		if (lflag & L_OPEN)
-			rc = ops->node_open(cur);
-		
-		if (rc == EOK) {
-			aoff64_t size = ops->size_get(cur);
-			async_answer_5(rid, fs_handle, service_id,
-			    ops->index_get(cur), LOWER32(size), UPPER32(size),
-			    ops->lnkcnt_get(cur));
-		} else
-			async_answer_0(rid, rc);
-		
-	} else
-		async_answer_0(rid, rc);
+	aoff64_t size = ops->size_get(cur);
+	async_answer_5(rid, fs_handle, service_id, ops->index_get(cur),
+	    (ops->is_directory(cur) << 16) | last, LOWER32(size),
+	    UPPER32(size));
 	
 out:
-	
 	if (par)
 		(void) ops->node_put(par);
@@ -862,4 +751,6 @@
 	memset(&st, 0, sizeof(struct statfs));
 
+	str_cpy(st.fs_name, sizeof(st.fs_name), fs_name);
+
 	if (ops->size_block != NULL) {
 		rc = ops->size_block(service_id, &st.f_bsize);
@@ -919,5 +810,6 @@
 	async_answer_4(rid, rc, LOWER32(size), UPPER32(size),
 	    ops->lnkcnt_get(fn),
-	    (ops->is_file(fn) ? L_FILE : 0) | (ops->is_directory(fn) ? L_DIRECTORY : 0));
+	    (ops->is_file(fn) ? L_FILE : 0) |
+	    (ops->is_directory(fn) ? L_DIRECTORY : 0));
 	
 	(void) ops->node_put(fn);
Index: uspace/lib/fs/libfs.h
===================================================================
--- uspace/lib/fs/libfs.h	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/lib/fs/libfs.h	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -56,12 +56,4 @@
 
 typedef struct {
-	bool mp_active;
-	async_sess_t *sess;
-	fs_handle_t fs_handle;
-	service_id_t service_id;
-} mp_data_t;
-
-typedef struct {
-	mp_data_t mp_data;  /**< Mount point info. */
 	void *data;         /**< Data of the file system implementation. */
 } fs_node_t;
Index: uspace/lib/gui/window.c
===================================================================
--- uspace/lib/gui/window.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/lib/gui/window.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -37,4 +37,5 @@
 #include <errno.h>
 #include <stdio.h>
+#include <stdlib.h>
 
 #include <as.h>
Index: uspace/lib/pcut/src/os/generic.c
===================================================================
--- uspace/lib/pcut/src/os/generic.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/lib/pcut/src/os/generic.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -137,5 +137,5 @@
 	fread(extra_output_buffer, 1, OUTPUT_BUFFER_SIZE, tempfile);
 	fclose(tempfile);
-	remove(tempfile_name);
+	unlink(tempfile_name);
 
 	pcut_report_test_done_unparsed(test, rc, extra_output_buffer, OUTPUT_BUFFER_SIZE);
Index: uspace/lib/pcut/src/os/helenos.c
===================================================================
--- uspace/lib/pcut/src/os/helenos.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/lib/pcut/src/os/helenos.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -41,6 +41,6 @@
 #include <stdio.h>
 #include <task.h>
-#include <fcntl.h>
 #include <fibril_synch.h>
+#include <vfs/vfs.h>
 #include "../internal.h"
 
@@ -161,5 +161,5 @@
 	char tempfile_name[PCUT_TEMP_FILENAME_BUFFER_SIZE];
 	snprintf(tempfile_name, PCUT_TEMP_FILENAME_BUFFER_SIZE - 1, "pcut_%lld.tmp", (unsigned long long) task_get_id());
-	int tempfile = open(tempfile_name, O_CREAT | O_RDWR);
+	int tempfile = vfs_lookup_open(tempfile_name, WALK_REGULAR | WALK_MAY_CREATE, MODE_READ | MODE_WRITE);
 	if (tempfile < 0) {
 		pcut_report_test_done(test, TEST_OUTCOME_ERROR, "Failed to create temporary file.", NULL, NULL);
@@ -169,11 +169,4 @@
 	char test_number_argument[MAX_TEST_NUMBER_WIDTH];
 	snprintf(test_number_argument, MAX_TEST_NUMBER_WIDTH, "-t%d", test->id);
-
-	int *files[4];
-	int fd_stdin = fileno(stdin);
-	files[0] = &fd_stdin;
-	files[1] = &tempfile;
-	files[2] = &tempfile;
-	files[3] = NULL;
 
 	const char *const arguments[3] = {
@@ -186,5 +179,6 @@
 
 	task_wait_t test_task_wait;
-	int rc = task_spawnvf(&test_task_id, &test_task_wait, self_path, arguments, files);
+	int rc = task_spawnvf(&test_task_id, &test_task_wait, self_path, arguments,
+	    fileno(stdin), tempfile, tempfile);
 	if (rc != EOK) {
 		status = TEST_OUTCOME_ERROR;
@@ -220,9 +214,10 @@
 	fibril_mutex_unlock(&forced_termination_mutex);
 
-	read(tempfile, extra_output_buffer, OUTPUT_BUFFER_SIZE);
+	aoff64_t pos = 0;
+	vfs_read(tempfile, &pos, extra_output_buffer, OUTPUT_BUFFER_SIZE);
 
 leave_close_tempfile:
-	close(tempfile);
-	unlink(tempfile_name);
+	vfs_put(tempfile);
+	vfs_unlink_path(tempfile_name);
 
 	pcut_report_test_done_unparsed(test, status, extra_output_buffer, OUTPUT_BUFFER_SIZE);
Index: uspace/lib/posix/include/posix/fcntl.h
===================================================================
--- uspace/lib/posix/include/posix/fcntl.h	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/lib/posix/include/posix/fcntl.h	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -41,6 +41,20 @@
 
 #include "sys/types.h"
-#include "libc/fcntl.h"
 #include "errno.h"
+
+#undef O_CREAT
+#undef O_EXCL
+#undef O_TRUNC
+#undef O_APPEND
+#undef O_RDONLY
+#undef O_RDWR
+#undef O_WRONLY
+#define O_CREAT   1
+#define O_EXCL    2
+#define O_TRUNC   4
+#define O_APPEND  8
+#define O_RDONLY  16
+#define O_RDWR    32
+#define O_WRONLY  64
 
 /* Mask for file access modes. */
Index: uspace/lib/posix/include/posix/sys/stat.h
===================================================================
--- uspace/lib/posix/include/posix/sys/stat.h	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/lib/posix/include/posix/sys/stat.h	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -115,5 +115,5 @@
 	__POSIX_DEF__(dev_t)     st_dev;     /* ID of device containing file */
 	__POSIX_DEF__(ino_t)     st_ino;     /* inode number */
-	mode_t          st_mode;    /* protection */
+	__POSIX_DEF__(mode_t)    st_mode;    /* protection */
 	__POSIX_DEF__(nlink_t)   st_nlink;   /* number of hard links */
 	__POSIX_DEF__(uid_t)     st_uid;     /* user ID of owner */
@@ -131,7 +131,7 @@
 extern int __POSIX_DEF__(lstat)(const char *restrict path, struct __POSIX_DEF__(stat) *restrict st);
 extern int __POSIX_DEF__(stat)(const char *restrict path, struct __POSIX_DEF__(stat) *restrict st);
-extern int __POSIX_DEF__(chmod)(const char *path, mode_t mode);
-extern mode_t __POSIX_DEF__(umask)(mode_t mask);
-extern int mkdir(const char *, mode_t);
+extern int __POSIX_DEF__(chmod)(const char *path, __POSIX_DEF__(mode_t) mode);
+extern __POSIX_DEF__(mode_t) __POSIX_DEF__(umask)(__POSIX_DEF__(mode_t) mask);
+extern int __POSIX_DEF__(mkdir)(const char *path, __POSIX_DEF__(mode_t) mode);
 
 
Index: uspace/lib/posix/include/posix/sys/types.h
===================================================================
--- uspace/lib/posix/include/posix/sys/types.h	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/lib/posix/include/posix/sys/types.h	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -53,4 +53,5 @@
 typedef int64_t __POSIX_DEF__(pid_t);
 typedef sysarg_t __POSIX_DEF__(dev_t);
+typedef unsigned int __POSIX_DEF__(mode_t);
 
 /* PThread Types */
Index: uspace/lib/posix/source/fcntl.c
===================================================================
--- uspace/lib/posix/source/fcntl.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/lib/posix/source/fcntl.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -100,19 +100,64 @@
  *
  * @param pathname Path to the file.
- * @param flags Access mode flags.
+ * @param posix_flags Access mode flags.
  */
-int posix_open(const char *pathname, int flags, ...)
+int posix_open(const char *pathname, int posix_flags, ...)
 {
-	mode_t mode = 0;
-	if ((flags & O_CREAT) > 0) {
+	int rc;
+	posix_mode_t posix_mode = 0;
+	if (posix_flags & O_CREAT) {
 		va_list args;
-		va_start(args, flags);
-		mode = va_arg(args, mode_t);
+		va_start(args, posix_flags);
+		posix_mode = va_arg(args, posix_mode_t);
 		va_end(args);
+		(void) posix_mode;
 	}
 
-	return negerrno(open, pathname, flags, mode);
+	if (((posix_flags & (O_RDONLY | O_WRONLY | O_RDWR)) == 0) ||
+	    ((posix_flags & (O_RDONLY | O_WRONLY)) == (O_RDONLY | O_WRONLY)) ||
+	    ((posix_flags & (O_RDONLY | O_RDWR)) == (O_RDONLY | O_RDWR)) ||
+	    ((posix_flags & (O_WRONLY | O_RDWR)) == (O_WRONLY | O_RDWR))) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	int flags = WALK_REGULAR;
+	if (posix_flags & O_CREAT) {
+		if (posix_flags & O_EXCL)
+			flags |= WALK_MUST_CREATE;
+		else
+			flags |= WALK_MAY_CREATE;
+	}
+
+	int mode =
+	    ((posix_flags & O_RDWR) ? MODE_READ | MODE_WRITE : 0) |
+	    ((posix_flags & O_RDONLY) ? MODE_READ : 0) |
+	    ((posix_flags & O_WRONLY) ? MODE_WRITE : 0) |
+	    ((posix_flags & O_APPEND) ? MODE_APPEND : 0);
+
+	int file = rcerrno(vfs_lookup, pathname, flags);
+	if (file < 0)
+		return -1;
+
+	rc = rcerrno(vfs_open, file, mode);
+	if (rc != EOK) {
+		vfs_put(file);
+		return -1;
+	}
+
+	if (posix_flags & O_TRUNC) {
+		if (posix_flags & (O_RDWR | O_WRONLY)) {
+			rc = rcerrno(vfs_resize, file, 0);
+			if (rc != EOK) {
+				vfs_put(file);
+				return -1;
+			}
+		}
+	}
+
+	return file;
 }
 
 /** @}
  */
+
Index: uspace/lib/posix/source/internal/common.h
===================================================================
--- uspace/lib/posix/source/internal/common.h	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/lib/posix/source/internal/common.h	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -38,4 +38,6 @@
 #include <stdio.h>
 #include <stdlib.h>
+#include <sys/types.h>
+#include <vfs/vfs.h>
 
 #define not_implemented() do { \
@@ -57,4 +59,14 @@
 })
 
+/* Convert error code to positive errno and -1 return value */
+#define rcerrno(func, ...) ({ \
+	int rc = func(__VA_ARGS__); \
+	if (rc < 0) \
+		errno = -rc; \
+	rc; \
+})
+
+extern aoff64_t posix_pos[MAX_OPEN_FILES];
+
 #endif /* LIBPOSIX_COMMON_H_ */
 
Index: uspace/lib/posix/source/stdio.c
===================================================================
--- uspace/lib/posix/source/stdio.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/lib/posix/source/stdio.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -53,5 +53,4 @@
 #include "libc/malloc.h"
 #include "libc/adt/list.h"
-#include "libc/sys/stat.h"
 
 /** Clears the stream's error and end-of-file indicators.
@@ -344,7 +343,8 @@
 static int _dprintf_str_write(const char *str, size_t size, void *fd)
 {
-	ssize_t wr = write(*(int *) fd, str, size);
+	const int fildes = *(int *) fd;
+	ssize_t wr = vfs_write(fildes, &posix_pos[fildes], str, size);
 	if (wr < 0)
-		return errno;
+		return wr;
 	return str_nlength(str, wr);
 }
@@ -371,7 +371,7 @@
 		}
 		
-		if (write(*(int *) fd, buf, sz) != (ssize_t) sz) {
+		const int fildes = *(int *) fd;
+		if (vfs_write(fildes, &posix_pos[fildes], buf, sz) < 0)
 			break;
-		}
 		
 		chars++;
@@ -575,5 +575,8 @@
 int posix_remove(const char *path)
 {
-	return negerrno(remove, path);
+	if (rcerrno(vfs_unlink_path, path) != EOK)
+		return -1;
+	else
+		return 0;
 }
 
@@ -587,5 +590,9 @@
 int posix_rename(const char *old, const char *new)
 {
-	return negerrno(rename, old, new);
+	int rc = rcerrno(vfs_rename_path, old, new);
+	if (rc != EOK)
+		return -1;
+	else
+		return 0;
 }
 
Index: uspace/lib/posix/source/stdlib.c
===================================================================
--- uspace/lib/posix/source/stdlib.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/lib/posix/source/stdlib.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -431,5 +431,5 @@
 		}
 		
-		fd = open(tmpl, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
+		fd = posix_open(tmpl, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
 		
 		if (fd == -1) {
Index: uspace/lib/posix/source/sys/stat.c
===================================================================
--- uspace/lib/posix/source/sys/stat.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/lib/posix/source/sys/stat.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -39,5 +39,5 @@
 #include "../internal/common.h"
 #include "posix/sys/stat.h"
-#include "libc/sys/stat.h"
+#include "libc/vfs/vfs.h"
 
 #include "posix/errno.h"
@@ -49,6 +49,8 @@
  * @param dest POSIX stat struct.
  * @param src HelenOS stat struct.
+ *
+ * @return 0 on success, -1 on error.
  */
-static void stat_to_posix(struct posix_stat *dest, struct stat *src)
+static int stat_to_posix(struct posix_stat *dest, struct stat *src)
 {
 	memset(dest, 0, sizeof(struct posix_stat));
@@ -68,4 +70,11 @@
 	dest->st_nlink = src->lnkcnt;
 	dest->st_size = src->size;
+
+	if (src->size > INT64_MAX) {
+		errno = ERANGE;
+		return -1;
+	}
+
+	return 0;
 }
 
@@ -80,9 +89,8 @@
 {
 	struct stat hst;
-	int rc = negerrno(fstat, fd, &hst);
+	int rc = rcerrno(vfs_stat, fd, &hst);
 	if (rc < 0)
-		return rc;
-	stat_to_posix(st, &hst);
-	return 0;
+		return -1;
+	return stat_to_posix(st, &hst);
 }
 
@@ -110,9 +118,8 @@
 {
 	struct stat hst;
-	int rc = negerrno(stat, path, &hst);
+	int rc = rcerrno(vfs_stat_path, path, &hst);
 	if (rc < 0)
-		return rc;
-	stat_to_posix(st, &hst);
-	return 0;
+		return -1;
+	return stat_to_posix(st, &hst);
 }
 
@@ -124,5 +131,5 @@
  * @return Zero on success, -1 otherwise.
  */
-int posix_chmod(const char *path, mode_t mode)
+int posix_chmod(const char *path, posix_mode_t mode)
 {
 	/* HelenOS doesn't support permissions, return success. */
@@ -137,5 +144,5 @@
  * @return Previous file mode creation mask.
  */
-mode_t posix_umask(mode_t mask)
+posix_mode_t posix_umask(posix_mode_t mask)
 {
 	/* HelenOS doesn't support permissions, return empty mask. */
@@ -143,4 +150,20 @@
 }
 
+/**
+ * Create a directory.
+ * 
+ * @param path Path to the new directory.
+ * @param mode Permission bits to be set.
+ * @return Zero on success, -1 otherwise.
+ */
+int posix_mkdir(const char *path, posix_mode_t mode)
+{
+	int rc = rcerrno(vfs_link_path, path, KIND_DIRECTORY, NULL);
+	if (rc != EOK)
+		return -1;
+	else
+		return 0;
+}
+
 /** @}
  */
Index: uspace/lib/posix/source/unistd.c
===================================================================
--- uspace/lib/posix/source/unistd.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/lib/posix/source/unistd.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -47,4 +47,7 @@
 #include "libc/stats.h"
 #include "libc/malloc.h"
+#include "libc/vfs/vfs.h"
+
+aoff64_t posix_pos[MAX_OPEN_FILES];
 
 /* Array of environment variable strings (NAME=VALUE). */
@@ -105,12 +108,8 @@
 char *posix_getcwd(char *buf, size_t size)
 {
-	char *p = getcwd(buf, size);
-
-	if (p == NULL) {
-		errno = -errno;
+	int rc = rcerrno(vfs_cwd_get, buf, size);
+	if (rc != EOK) 
 		return NULL;
-	}
-
-	return p;
+	return buf;
 }
 
@@ -122,5 +121,8 @@
 int posix_chdir(const char *path)
 {
-	return negerrno(chdir, path);
+	int rc = rcerrno(vfs_cwd_set, path);
+	if (rc != EOK)
+		return -1;
+	return 0;
 }
 
@@ -175,5 +177,10 @@
 int posix_close(int fildes)
 {
-	return negerrno(close, fildes);
+	posix_pos[fildes] = 0;
+	int rc = rcerrno(vfs_put, fildes);
+	if (rc != EOK)
+		return -1;
+	else
+		return 0;
 }
 
@@ -188,5 +195,8 @@
 ssize_t posix_read(int fildes, void *buf, size_t nbyte)
 {
-	return negerrno(read, fildes, buf, nbyte);
+	ssize_t size = rcerrno(vfs_read, fildes, &posix_pos[fildes], buf, nbyte);
+	if (size < 0)
+		return -1;
+	return size;
 }
 
@@ -201,5 +211,8 @@
 ssize_t posix_write(int fildes, const void *buf, size_t nbyte)
 {
-	return negerrno(write, fildes, buf, nbyte);
+	ssize_t size = rcerrno(vfs_write, fildes, &posix_pos[fildes], buf, nbyte);
+	if (size < 0)
+		return -1;
+	return size;
 }
 
@@ -215,5 +228,27 @@
 posix_off_t posix_lseek(int fildes, posix_off_t offset, int whence)
 {
-	return negerrno(lseek, fildes, offset, whence);
+	struct stat st;
+	int rc;
+
+	switch (whence) {
+	case SEEK_SET:
+		posix_pos[fildes] = offset;
+		break;
+	case SEEK_CUR:
+		posix_pos[fildes] += offset;
+		break;
+	case SEEK_END:
+		rc = rcerrno(vfs_stat, fildes, &st);
+		if (rc != EOK)
+			return -1;
+		posix_pos[fildes] = st.size + offset;
+		break;
+	}
+	if (posix_pos[fildes] > INT64_MAX) {
+		/* The native width is too large for the POSIX interface. */
+		errno = ERANGE;
+		return -1;
+	}
+	return posix_pos[fildes];
 }
 
@@ -226,5 +261,8 @@
 int posix_fsync(int fildes)
 {
-	return negerrno(fsync, fildes);
+	if (rcerrno(vfs_sync, fildes) != EOK)
+		return -1;
+	else
+		return 0;
 }
 
@@ -238,5 +276,8 @@
 int posix_ftruncate(int fildes, posix_off_t length)
 {
-	return negerrno(ftruncate, fildes, (aoff64_t) length);
+	if (rcerrno(vfs_resize, fildes, (aoff64_t) length) != EOK)
+		return -1;
+	else
+		return 0;
 }
 
@@ -249,5 +290,8 @@
 int posix_rmdir(const char *path)
 {
-	return negerrno(rmdir, path);
+	if (rcerrno(vfs_unlink_path, path) != EOK)
+		return -1;
+	else
+		return 0;
 }
 
@@ -260,5 +304,8 @@
 int posix_unlink(const char *path)
 {
-	return negerrno(unlink, path);
+	if (rcerrno(vfs_unlink_path, path) != EOK)
+		return -1;
+	else
+		return 0;
 }
 
@@ -284,5 +331,5 @@
 int posix_dup2(int fildes, int fildes2)
 {
-	return negerrno(dup2, fildes, fildes2);
+	return negerrno(vfs_clone, fildes, fildes2, false);
 }
 
@@ -302,10 +349,8 @@
 		 * Check file existence by attempting to open it.
 		 */
-		int fd = negerrno(open, path, O_RDONLY);
-		if (fd < 0) {
-			/* errno was set by open() */
+		int fd = posix_open(path, O_RDONLY);
+		if (fd < 0)
 			return -1;
-		}
-		close(fd);
+		posix_close(fd);
 		return 0;
 	} else {
Index: uspace/srv/devman/driver.c
===================================================================
--- uspace/srv/devman/driver.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/srv/devman/driver.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -33,7 +33,6 @@
 #include <dirent.h>
 #include <errno.h>
-#include <fcntl.h>
-#include <sys/stat.h>
 #include <io/log.h>
+#include <vfs/vfs.h>
 #include <loc.h>
 #include <str_error.h>
@@ -142,5 +141,5 @@
 	/* Check whether the driver's binary exists. */
 	struct stat s;
-	if (stat(drv->binary_path, &s) != 0) {
+	if (vfs_stat_path(drv->binary_path, &s) != EOK) {
 		log_msg(LOG_DEFAULT, LVL_ERROR, "Driver not found at path `%s'.",
 		    drv->binary_path);
Index: uspace/srv/devman/match.c
===================================================================
--- uspace/srv/devman/match.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/srv/devman/match.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -32,10 +32,9 @@
 
 #include <errno.h>
-#include <fcntl.h>
 #include <io/log.h>
 #include <str.h>
 #include <str_error.h>
 #include <sys/types.h>
-#include <sys/stat.h>
+#include <vfs/vfs.h>
 
 #include "devman.h"
@@ -201,6 +200,7 @@
 	int fd;
 	size_t len = 0;
-	
-	fd = open(conf_path, O_RDONLY);
+	struct stat st;
+	
+	fd = vfs_lookup_open(conf_path, WALK_REGULAR, MODE_READ);
 	if (fd < 0) {
 		log_msg(LOG_DEFAULT, LVL_ERROR, "Unable to open `%s' for reading: %s.",
@@ -210,6 +210,10 @@
 	opened = true;
 	
-	len = lseek(fd, 0, SEEK_END);
-	lseek(fd, 0, SEEK_SET);
+	if (vfs_stat(fd, &st) != EOK) {
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Unable to fstat %d: %s.", fd,
+		    str_error(errno));
+		goto cleanup;
+	}
+	len = st.size;
 	if (len == 0) {
 		log_msg(LOG_DEFAULT, LVL_ERROR, "Configuration file '%s' is empty.",
@@ -225,5 +229,5 @@
 	}
 	
-	ssize_t read_bytes = read(fd, buf, len);
+	ssize_t read_bytes = vfs_read(fd, (aoff64_t []) {0}, buf, len);
 	if (read_bytes <= 0) {
 		log_msg(LOG_DEFAULT, LVL_ERROR, "Unable to read file '%s' (%d).", conf_path,
@@ -239,5 +243,5 @@
 	
 	if (opened)
-		close(fd);
+		vfs_put(fd);
 	
 	return suc;
Index: uspace/srv/fs/fat/fat.h
===================================================================
--- uspace/srv/fs/fat/fat.h	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/srv/fs/fat/fat.h	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -41,4 +41,5 @@
 #include <sys/types.h>
 #include <stdbool.h>
+#include <macros.h>
 #include "../../vfs/vfs.h"
 
@@ -46,6 +47,4 @@
 #define dprintf(...)	printf(__VA_ARGS__)
 #endif
-
-#define min(a, b)	((a) < (b) ? (a) : (b))
 
 /*
Index: uspace/srv/fs/locfs/locfs_ops.c
===================================================================
--- uspace/srv/fs/locfs/locfs_ops.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/srv/fs/locfs/locfs_ops.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -45,5 +45,4 @@
 #include <adt/hash_table.h>
 #include <ipc/loc.h>
-#include <sys/stat.h>
 #include <assert.h>
 #include "locfs.h"
Index: uspace/srv/fs/mfs/mfs.h
===================================================================
--- uspace/srv/fs/mfs/mfs.h	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/srv/fs/mfs/mfs.h	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -45,4 +45,5 @@
 #include <assert.h>
 #include <stdbool.h>
+#include <macros.h>
 #include "../../vfs/vfs.h"
 
@@ -50,6 +51,4 @@
 
 /* #define DEBUG_MODE */
-
-#define min(a, b)	((a) < (b) ? (a) : (b))
 
 #ifdef DEBUG_MODE
Index: uspace/srv/fs/tmpfs/tmpfs_ops.c
===================================================================
--- uspace/srv/fs/tmpfs/tmpfs_ops.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/srv/fs/tmpfs/tmpfs_ops.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -54,7 +54,4 @@
 #include <libfs.h>
 
-#define min(a, b)		((a) < (b) ? (a) : (b))
-#define max(a, b)		((a) > (b) ? (a) : (b))
-
 /** All root nodes have index 0. */
 #define TMPFS_SOME_ROOT		0
Index: uspace/srv/hid/input/ctl/kbdev.c
===================================================================
--- uspace/srv/hid/input/ctl/kbdev.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/srv/hid/input/ctl/kbdev.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -39,5 +39,4 @@
 #include <stdbool.h>
 #include <errno.h>
-#include <fcntl.h>
 #include <io/console.h>
 #include <io/keycode.h>
Index: uspace/srv/hid/input/port/adb.c
===================================================================
--- uspace/srv/hid/input/port/adb.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/srv/hid/input/port/adb.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -38,5 +38,4 @@
 #include <async.h>
 #include <vfs/vfs.h>
-#include <fcntl.h>
 #include <errno.h>
 #include <loc.h>
Index: uspace/srv/hid/input/proto/mousedev.c
===================================================================
--- uspace/srv/hid/input/proto/mousedev.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/srv/hid/input/proto/mousedev.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -37,5 +37,4 @@
 
 #include <stdio.h>
-#include <fcntl.h>
 #include <vfs/vfs_sess.h>
 #include <malloc.h>
Index: uspace/srv/loader/main.c
===================================================================
--- uspace/srv/loader/main.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/srv/loader/main.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -48,5 +48,4 @@
 #include <unistd.h>
 #include <stdbool.h>
-#include <fcntl.h>
 #include <sys/types.h>
 #include <ipc/services.h>
@@ -62,9 +61,11 @@
 #include <elf/elf_load.h>
 #include <vfs/vfs.h>
+#include <vfs/inbox.h>
 
 #define DPRINTF(...)
 
-/** Pathname of the file that will be loaded */
-static char *pathname = NULL;
+/** File that will be loaded */
+static char *progname = NULL;
+static int program_fd = -1;
 
 /** The Program control block */
@@ -81,6 +82,7 @@
 static char *arg_buf = NULL;
 
-/** Number of preset files */
-static unsigned int filc = 0;
+/** Inbox entries. */
+static struct pcb_inbox_entry inbox[INBOX_MAX_ENTRIES];
+static int inbox_entries = 0;
 
 static elf_info_t prog_info;
@@ -130,22 +132,34 @@
 }
 
-/** Receive a call setting pathname of the program to execute.
- *
- * @param rid
- * @param request
- */
-static void ldr_set_pathname(ipc_callid_t rid, ipc_call_t *request)
-{
-	char *buf;
-	int rc = async_data_write_accept((void **) &buf, true, 0, 0, 0, NULL);
-	
-	if (rc == EOK) {
-		if (pathname != NULL)
-			free(pathname);
-		
-		pathname = buf;
-	}
-	
-	async_answer_0(rid, rc);
+/** Receive a call setting the program to execute.
+ *
+ * @param rid
+ * @param request
+ */
+static void ldr_set_program(ipc_callid_t rid, ipc_call_t *request)
+{
+	ipc_callid_t writeid;
+	size_t namesize;
+	if (!async_data_write_receive(&writeid, &namesize)) {
+		async_answer_0(rid, EINVAL);
+		return;
+	}
+
+	char* name = malloc(namesize);
+	int rc = async_data_write_finalize(writeid, name, namesize);
+	if (rc != EOK) {
+		async_answer_0(rid, EINVAL);
+		return;
+	}
+
+	int file = vfs_receive_handle(true);
+	if (file < 0) {
+		async_answer_0(rid, EINVAL);
+		return;
+	}
+	
+	progname = name;
+	program_fd = file;
+	async_answer_0(rid, EOK);
 }
 
@@ -215,30 +229,46 @@
 }
 
-/** Receive a call setting preset files of the program to execute.
- *
- * @param rid
- * @param request
- */
-static void ldr_set_files(ipc_callid_t rid, ipc_call_t *request)
-{
-	size_t count = IPC_GET_ARG1(*request);
-
-	async_exch_t *vfs_exch = vfs_exchange_begin();
-
-	for (filc = 0; filc < count; filc++) {
-		ipc_callid_t callid;
-		int fd;
-
-		if (!async_state_change_receive(&callid, NULL, NULL, NULL)) {
-			async_answer_0(callid, EINVAL);
-			break;
-		}
-		async_state_change_finalize(callid, vfs_exch);
-		fd = vfs_fd_wait();
-		assert(fd == (int) filc);
-	}
-
-	vfs_exchange_end(vfs_exch);
-
+/** Receive a call setting inbox files of the program to execute.
+ *
+ * @param rid
+ * @param request
+ */
+static void ldr_add_inbox(ipc_callid_t rid, ipc_call_t *request)
+{
+	if (inbox_entries == INBOX_MAX_ENTRIES) {
+		async_answer_0(rid, ERANGE);
+		return;
+	}
+
+	ipc_callid_t writeid;
+	size_t namesize;
+	if (!async_data_write_receive(&writeid, &namesize)) {
+		async_answer_0(rid, EINVAL);
+		return;
+	}
+
+	char* name = malloc(namesize);
+	int rc = async_data_write_finalize(writeid, name, namesize);
+	if (rc != EOK) {
+		async_answer_0(rid, EINVAL);
+		return;
+	}
+
+	int file = vfs_receive_handle(true);
+	if (file < 0) {
+		async_answer_0(rid, EINVAL);
+		return;
+	}
+
+	/*
+	 * We need to set the root early for dynamically linked binaries so
+	 * that the loader can use it too.
+	 */
+	if (str_cmp(name, "root") == 0)
+		vfs_root_set(file);
+
+	inbox[inbox_entries].name = name;
+	inbox[inbox_entries].file = file;
+	inbox_entries++;
 	async_answer_0(rid, EOK);
 }
@@ -252,9 +282,7 @@
 static int ldr_load(ipc_callid_t rid, ipc_call_t *request)
 {
-	int rc;
-	
-	rc = elf_load(pathname, &prog_info);
+	int rc = elf_load(program_fd, &prog_info);
 	if (rc != EE_OK) {
-		DPRINTF("Failed to load executable '%s'.\n", pathname);
+		DPRINTF("Failed to load executable for '%s'.\n", progname);
 		async_answer_0(rid, EINVAL);
 		return 1;
@@ -268,5 +296,6 @@
 	pcb.argv = argv;
 	
-	pcb.filc = filc;
+	pcb.inbox = inbox;
+	pcb.inbox_entries = inbox_entries;
 	
 	async_answer_0(rid, rc);
@@ -282,12 +311,8 @@
 static void ldr_run(ipc_callid_t rid, ipc_call_t *request)
 {
-	const char *cp;
-	
 	DPRINTF("Set task name\n");
 
 	/* Set the task name. */
-	cp = str_rchr(pathname, '/');
-	cp = (cp == NULL) ? pathname : (cp + 1);
-	task_set_name(cp);
+	task_set_name(progname);
 	
 	/* Run program */
@@ -336,12 +361,12 @@
 			ldr_set_cwd(callid, &call);
 			continue;
-		case LOADER_SET_PATHNAME:
-			ldr_set_pathname(callid, &call);
+		case LOADER_SET_PROGRAM:
+			ldr_set_program(callid, &call);
 			continue;
 		case LOADER_SET_ARGS:
 			ldr_set_args(callid, &call);
 			continue;
-		case LOADER_SET_FILES:
-			ldr_set_files(callid, &call);
+		case LOADER_ADD_INBOX:
+			ldr_add_inbox(callid, &call);
 			continue;
 		case LOADER_LOAD:
Index: uspace/srv/logger/ctl.c
===================================================================
--- uspace/srv/logger/ctl.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/srv/logger/ctl.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -41,4 +41,5 @@
 #include <io/logctl.h>
 #include <ipc/logger.h>
+#include <vfs/vfs.h>
 #include "logger.h"
 
@@ -86,4 +87,10 @@
 			break;
 		}
+		case LOGGER_CONTROL_SET_ROOT: {
+			int fd = vfs_receive_handle(true);
+			vfs_root_set(fd);
+			async_answer_0(callid, fd >= 0 ? EOK : fd);
+			break;
+		}
 		default:
 			async_answer_0(callid, EINVAL);
Index: uspace/srv/vfs/Makefile
===================================================================
--- uspace/srv/vfs/Makefile	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/srv/vfs/Makefile	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -39,4 +39,5 @@
 	vfs_lookup.c \
 	vfs_register.c \
+	vfs_ipc.c \
 	vfs_pager.c
 
Index: uspace/srv/vfs/vfs.c
===================================================================
--- uspace/srv/vfs/vfs.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/srv/vfs/vfs.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -76,96 +76,8 @@
 }
 
-static void vfs_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
-{
-	bool cont = true;
-	
-	/*
-	 * The connection was opened via the IPC_CONNECT_ME_TO call.
-	 * This call needs to be answered.
-	 */
-	async_answer_0(iid, EOK);
-	
-	while (cont) {
-		ipc_call_t call;
-		ipc_callid_t callid = async_get_call(&call);
-		
-		if (!IPC_GET_IMETHOD(call))
-			break;
-		
-		switch (IPC_GET_IMETHOD(call)) {
-		case VFS_IN_REGISTER:
-			vfs_register(callid, &call);
-			cont = false;
-			break;
-		case VFS_IN_MOUNT:
-			vfs_mount_srv(callid, &call);
-			break;
-		case VFS_IN_UNMOUNT:
-			vfs_unmount_srv(callid, &call);
-			break;
-		case VFS_IN_OPEN:
-			vfs_open(callid, &call);
-			break;
-		case VFS_IN_CLOSE:
-			vfs_close(callid, &call);
-			break;
-		case VFS_IN_READ:
-			vfs_read(callid, &call);
-			break;
-		case VFS_IN_WRITE:
-			vfs_write(callid, &call);
-			break;
-		case VFS_IN_SEEK:
-			vfs_seek(callid, &call);
-			break;
-		case VFS_IN_TRUNCATE:
-			vfs_truncate(callid, &call);
-			break;
-		case VFS_IN_FSTAT:
-			vfs_fstat(callid, &call);
-			break;
-		case VFS_IN_STAT:
-			vfs_stat(callid, &call);
-			break;
-		case VFS_IN_MKDIR:
-			vfs_mkdir(callid, &call);
-			break;
-		case VFS_IN_UNLINK:
-			vfs_unlink(callid, &call);
-			break;
-		case VFS_IN_RENAME:
-			vfs_rename(callid, &call);
-			break;
-		case VFS_IN_SYNC:
-			vfs_sync(callid, &call);
-			break;
-		case VFS_IN_DUP:
-			vfs_dup(callid, &call);
-			break;
-		case VFS_IN_WAIT_HANDLE:
-			vfs_wait_handle(callid, &call);
-			break;
-		case VFS_IN_MTAB_GET:
-			vfs_get_mtab(callid, &call);
-			break;
-		case VFS_IN_STATFS:
-			vfs_statfs(callid, &call);
-			break;
-		default:
-			async_answer_0(callid, ENOTSUP);
-			break;
-		}
-	}
-	
-	/*
-	 * Open files for this client will be cleaned up when its last
-	 * connection fibril terminates.
-	 */
-}
-
 static void notification_handler(ipc_callid_t callid, ipc_call_t *call, void *arg)
 {
 	if (IPC_GET_ARG1(*call) == VFS_PASS_HANDLE)
-		vfs_pass_handle(
+		vfs_op_pass_handle(
 		    (task_id_t) MERGE_LOUP32(IPC_GET_ARG4(*call),
 		    IPC_GET_ARG5(*call)), call->in_task_id,
Index: uspace/srv/vfs/vfs.h
===================================================================
--- uspace/srv/vfs/vfs.h	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/srv/vfs/vfs.h	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -94,5 +94,4 @@
 	vfs_node_type_t type;
 	aoff64_t size;
-	unsigned int lnkcnt;
 } vfs_lookup_res_t;
 
@@ -101,5 +100,5 @@
  * which may be associated with it.
  */
-typedef struct {
+typedef struct _vfs_node {
 	VFS_TRIPLET;		/**< Identity of the node. */
 
@@ -110,7 +109,4 @@
 	unsigned refcnt;
 	
-	/** Number of names this node has in the file system namespace. */
-	unsigned lnkcnt;
-
 	ht_link_t nh_link;		/**< Node hash-table link. */
 
@@ -123,4 +119,6 @@
 	 */
 	fibril_rwlock_t contents_rwlock;
+	
+	struct _vfs_node *mount;
 } vfs_node_t;
 
@@ -131,5 +129,5 @@
 typedef struct {
 	/** Serializes access to this open file. */
-	fibril_mutex_t lock;
+	fibril_mutex_t _lock;
 
 	vfs_node_t *node;
@@ -138,9 +136,10 @@
 	unsigned refcnt;
 
+	int permissions;
+	bool open_read;
+	bool open_write;
+
 	/** Append on write. */
 	bool append;
-
-	/** Current absolute position in the file. */
-	aoff64_t pos;
 } vfs_file_t;
 
@@ -173,29 +172,29 @@
 extern void vfs_exchange_release(async_exch_t *);
 
-extern fs_handle_t fs_name_to_handle(unsigned int instance, char *, bool);
+extern fs_handle_t fs_name_to_handle(unsigned int instance, const char *, bool);
 extern vfs_info_t *fs_handle_to_info(fs_handle_t);
 
-extern int vfs_lookup_internal(char *, int, vfs_lookup_res_t *,
-    vfs_pair_t *, ...);
+extern int vfs_lookup_internal(vfs_node_t *, char *, int, vfs_lookup_res_t *);
+extern int vfs_link_internal(vfs_node_t *, char *, vfs_triplet_t *);
 
 extern bool vfs_nodes_init(void);
 extern vfs_node_t *vfs_node_get(vfs_lookup_res_t *);
+extern vfs_node_t *vfs_node_peek(vfs_lookup_res_t *result);
 extern void vfs_node_put(vfs_node_t *);
 extern void vfs_node_forget(vfs_node_t *);
 extern unsigned vfs_nodes_refcount_sum_get(fs_handle_t, service_id_t);
 
-
-#define MAX_OPEN_FILES	128
+extern bool vfs_node_has_children(vfs_node_t *node);
 
 extern void *vfs_client_data_create(void);
 extern void vfs_client_data_destroy(void *);
 
-extern void vfs_pass_handle(task_id_t, task_id_t, int);
-extern int vfs_wait_handle_internal(void);
+extern void vfs_op_pass_handle(task_id_t, task_id_t, int);
+extern int vfs_wait_handle_internal(bool);
 
 extern vfs_file_t *vfs_file_get(int);
 extern void vfs_file_put(vfs_file_t *);
 extern int vfs_fd_assign(vfs_file_t *, int);
-extern int vfs_fd_alloc(bool desc);
+extern int vfs_fd_alloc(vfs_file_t **file, bool desc);
 extern int vfs_fd_free(int);
 
@@ -204,23 +203,22 @@
 extern int vfs_open_node_remote(vfs_node_t *);
 
+extern int vfs_op_clone(int oldfd, int newfd, bool desc);
+extern int vfs_op_mount(int mpfd, unsigned servid, unsigned flags, unsigned instance, const char *opts, const char *fsname, int *outfd);
+extern int vfs_op_mtab_get(void);
+extern int vfs_op_open(int fd, int flags);
+extern int vfs_op_put(int fd);
+extern int vfs_op_read(int fd, aoff64_t, size_t *out_bytes);
+extern int vfs_op_rename(int basefd, char *old, char *new);
+extern int vfs_op_resize(int fd, int64_t size);
+extern int vfs_op_stat(int fd);
+extern int vfs_op_statfs(int fd);
+extern int vfs_op_sync(int fd);
+extern int vfs_op_unlink(int parentfd, int expectfd, char *path);
+extern int vfs_op_unmount(int mpfd);
+extern int vfs_op_wait_handle(bool high_fd);
+extern int vfs_op_walk(int parentfd, int flags, char *path, int *out_fd);
+extern int vfs_op_write(int fd, aoff64_t, size_t *out_bytes);
+
 extern void vfs_register(ipc_callid_t, ipc_call_t *);
-extern void vfs_mount_srv(ipc_callid_t, ipc_call_t *);
-extern void vfs_unmount_srv(ipc_callid_t, ipc_call_t *);
-extern void vfs_open(ipc_callid_t, ipc_call_t *);
-extern void vfs_sync(ipc_callid_t, ipc_call_t *);
-extern void vfs_dup(ipc_callid_t, ipc_call_t *);
-extern void vfs_close(ipc_callid_t, ipc_call_t *);
-extern void vfs_read(ipc_callid_t, ipc_call_t *);
-extern void vfs_write(ipc_callid_t, ipc_call_t *);
-extern void vfs_seek(ipc_callid_t, ipc_call_t *);
-extern void vfs_truncate(ipc_callid_t, ipc_call_t *);
-extern void vfs_fstat(ipc_callid_t, ipc_call_t *);
-extern void vfs_stat(ipc_callid_t, ipc_call_t *);
-extern void vfs_mkdir(ipc_callid_t, ipc_call_t *);
-extern void vfs_unlink(ipc_callid_t, ipc_call_t *);
-extern void vfs_rename(ipc_callid_t, ipc_call_t *);
-extern void vfs_wait_handle(ipc_callid_t, ipc_call_t *);
-extern void vfs_get_mtab(ipc_callid_t, ipc_call_t *);
-extern void vfs_statfs(ipc_callid_t, ipc_call_t *);
 
 extern void vfs_page_in(ipc_callid_t, ipc_call_t *);
@@ -231,5 +229,7 @@
 } rdwr_io_chunk_t;
 
-extern int vfs_rdwr_internal(int, bool, rdwr_io_chunk_t *);
+extern int vfs_rdwr_internal(int, aoff64_t, bool, rdwr_io_chunk_t *);
+
+extern void vfs_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg);
 
 #endif
Index: uspace/srv/vfs/vfs_file.c
===================================================================
--- uspace/srv/vfs/vfs_file.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/srv/vfs/vfs_file.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -45,4 +45,5 @@
 #include <adt/list.h>
 #include <task.h>
+#include <vfs/vfs.h>
 #include "vfs.h"
 
@@ -59,5 +60,6 @@
 typedef struct {
 	link_t link;
-	int handle;
+	vfs_node_t *node;
+	int permissions;
 } vfs_boxed_handle_t;
 
@@ -177,6 +179,11 @@
 		 * endpoint FS and drop our reference to the underlying VFS node.
 		 */
-		rc = vfs_file_close_remote(file);
-		vfs_node_delref(file->node);
+		
+		if (file->node != NULL) {
+			if (file->open_read || file->open_write) {
+				rc = vfs_file_close_remote(file);
+			}
+			vfs_node_delref(file->node);
+ 		}
 		free(file);
 	}
@@ -185,5 +192,5 @@
 }
 
-static int _vfs_fd_alloc(vfs_client_data_t *vfs_data, bool desc)
+static int _vfs_fd_alloc(vfs_client_data_t *vfs_data, vfs_file_t **file, bool desc)
 {
 	if (!vfs_files_init(vfs_data))
@@ -205,7 +212,14 @@
 			}
 			
+			
 			memset(vfs_data->files[i], 0, sizeof(vfs_file_t));
-			fibril_mutex_initialize(&vfs_data->files[i]->lock);
+			
+			fibril_mutex_initialize(&vfs_data->files[i]->_lock);
+			fibril_mutex_lock(&vfs_data->files[i]->_lock);
 			vfs_file_addref(vfs_data, vfs_data->files[i]);
+			
+			*file = vfs_data->files[i];
+			vfs_file_addref(vfs_data, *file);
+			
 			fibril_mutex_unlock(&vfs_data->lock);
 			return (int) i;
@@ -231,4 +245,5 @@
 /** Allocate a file descriptor.
  *
+ * @param file Is set to point to the newly created file structure. Must be put afterwards.
  * @param desc If true, look for an available file descriptor
  *             in a descending order.
@@ -237,7 +252,7 @@
  *         code.
  */
-int vfs_fd_alloc(bool desc)
-{
-	return _vfs_fd_alloc(VFS_DATA, desc);
+int vfs_fd_alloc(vfs_file_t **file, bool desc)
+{
+	return _vfs_fd_alloc(VFS_DATA, file, desc);
 }
 
@@ -289,7 +304,11 @@
 
 	fibril_mutex_lock(&VFS_DATA->lock);	
-	if ((fd < 0) || (fd >= MAX_OPEN_FILES) || (FILES[fd] != NULL)) {
+	if ((fd < 0) || (fd >= MAX_OPEN_FILES)) {
 		fibril_mutex_unlock(&VFS_DATA->lock);
-		return EINVAL;
+		return EBADF;
+	}
+	if (FILES[fd] != NULL) {
+		fibril_mutex_unlock(&VFS_DATA->lock);
+		return EEXIST;
 	}
 	
@@ -299,4 +318,13 @@
 	
 	return EOK;
+}
+
+static void _vfs_file_put(vfs_client_data_t *vfs_data, vfs_file_t *file)
+{
+	fibril_mutex_unlock(&file->_lock);
+	
+	fibril_mutex_lock(&vfs_data->lock);
+	vfs_file_delref(vfs_data, file);
+	fibril_mutex_unlock(&vfs_data->lock);
 }
 
@@ -312,4 +340,12 @@
 			vfs_file_addref(vfs_data, file);
 			fibril_mutex_unlock(&vfs_data->lock);
+			
+			fibril_mutex_lock(&file->_lock);
+			if (file->node == NULL) {
+				_vfs_file_put(vfs_data, file);
+				return NULL;
+			}
+			assert(file != NULL);
+			assert(file->node != NULL);
 			return file;
 		}
@@ -331,11 +367,4 @@
 }
 
-static void _vfs_file_put(vfs_client_data_t *vfs_data, vfs_file_t *file)
-{
-	fibril_mutex_lock(&vfs_data->lock);
-	vfs_file_delref(vfs_data, file);
-	fibril_mutex_unlock(&vfs_data->lock);
-}
-
 /** Stop using a file structure.
  *
@@ -347,12 +376,10 @@
 }
 
-void vfs_pass_handle(task_id_t donor_id, task_id_t acceptor_id, int donor_fd)
+void vfs_op_pass_handle(task_id_t donor_id, task_id_t acceptor_id, int donor_fd)
 {
 	vfs_client_data_t *donor_data = NULL;
 	vfs_client_data_t *acceptor_data = NULL;
 	vfs_file_t *donor_file = NULL;
-	vfs_file_t *acceptor_file = NULL;
 	vfs_boxed_handle_t *bh;
-	int acceptor_fd;
 
 	acceptor_data = async_get_client_data_by_id(acceptor_id);
@@ -364,5 +391,5 @@
 
 	link_initialize(&bh->link);
-	bh->handle = -1;
+	bh->node = NULL;
 
 	donor_data = async_get_client_data_by_id(donor_id);
@@ -373,10 +400,4 @@
 	if (!donor_file)
 		goto out;
-
-	acceptor_fd = _vfs_fd_alloc(acceptor_data, false);
-	if (acceptor_fd < 0)
-		goto out;
-
-	bh->handle = acceptor_fd;
 
 	/*
@@ -384,15 +405,6 @@
 	 */
 	vfs_node_addref(donor_file->node);
-	(void) vfs_open_node_remote(donor_file->node);
-
-	acceptor_file = _vfs_file_get(acceptor_data, acceptor_fd);
-	assert(acceptor_file);
-
-	/*
-	 * Inherit attributes from the donor.
-	 */
-	acceptor_file->node = donor_file->node;
-	acceptor_file->append = donor_file->append;
-	acceptor_file->pos = donor_file->pos;
+	bh->node = donor_file->node;
+	bh->permissions = donor_file->permissions;
 
 out:
@@ -408,13 +420,9 @@
 	if (donor_file)
 		_vfs_file_put(donor_data, donor_file);
-	if (acceptor_file)
-		_vfs_file_put(acceptor_data, acceptor_file);
-
-}
-
-int vfs_wait_handle_internal(void)
+}
+
+int vfs_wait_handle_internal(bool high_fd)
 {
 	vfs_client_data_t *vfs_data = VFS_DATA;	
-	int fd;
 	
 	fibril_mutex_lock(&vfs_data->lock);
@@ -426,7 +434,17 @@
 
 	vfs_boxed_handle_t *bh = list_get_instance(lnk, vfs_boxed_handle_t, link);
-	fd = bh->handle;
+
+	vfs_file_t *file;
+	int fd = _vfs_fd_alloc(vfs_data, &file, high_fd);
+	if (fd < 0) {
+		vfs_node_delref(bh->node);
+		free(bh);
+		return fd;
+	}
+	
+	file->node = bh->node;
+	file->permissions = bh->permissions;
+	vfs_file_put(file);
 	free(bh);
-
 	return fd;
 }
Index: uspace/srv/vfs/vfs_ipc.c
===================================================================
--- uspace/srv/vfs/vfs_ipc.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
+++ uspace/srv/vfs/vfs_ipc.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -0,0 +1,326 @@
+/*
+ * Copyright (c) 2008 Jakub Jermar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "vfs.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <str.h>
+#include <vfs/canonify.h>
+
+static void vfs_in_clone(ipc_callid_t rid, ipc_call_t *request)
+{
+	int oldfd = IPC_GET_ARG1(*request);
+	int newfd = IPC_GET_ARG2(*request);
+	bool desc = IPC_GET_ARG3(*request);
+	
+	int ret = vfs_op_clone(oldfd, newfd, desc);
+	async_answer_0(rid, ret);
+}
+
+static void vfs_in_mount(ipc_callid_t rid, ipc_call_t *request)
+{
+	int mpfd = IPC_GET_ARG1(*request);
+	
+	/*
+	 * We expect the library to do the device-name to device-handle
+	 * translation for us, thus the device handle will arrive as ARG1
+	 * in the request.
+	 */
+	service_id_t service_id = (service_id_t) IPC_GET_ARG2(*request);
+	
+	unsigned int flags = (unsigned int) IPC_GET_ARG3(*request);
+	unsigned int instance = IPC_GET_ARG4(*request);
+	
+	char *opts = NULL;
+	char *fs_name = NULL;
+	
+	/* Now we expect to receive the mount options. */
+	int rc = async_data_write_accept((void **) &opts, true, 0,
+	    MAX_MNTOPTS_LEN, 0, NULL);
+	if (rc != EOK) {
+		async_answer_0(rid, rc);
+		return;
+	}
+	
+	/* Now, we expect the client to send us data with the name of the file 
+	 * system.
+	 */
+	rc = async_data_write_accept((void **) &fs_name, true, 0,
+	    FS_NAME_MAXLEN, 0, NULL);
+	if (rc != EOK) {
+		free(opts);
+		async_answer_0(rid, rc);
+		return;
+	}
+	
+	int outfd = 0;
+	rc = vfs_op_mount(mpfd, service_id, flags, instance, opts, fs_name,
+	     &outfd);
+	async_answer_1(rid, rc, outfd);
+	
+	free(opts);
+	free(fs_name);
+}
+
+static void vfs_in_open(ipc_callid_t rid, ipc_call_t *request)
+{
+	int fd = IPC_GET_ARG1(*request);
+	int mode = IPC_GET_ARG2(*request);
+
+	int rc = vfs_op_open(fd, mode);
+	async_answer_0(rid, rc);
+}
+
+static void vfs_in_put(ipc_callid_t rid, ipc_call_t *request)
+{
+	int fd = IPC_GET_ARG1(*request);
+	int rc = vfs_op_put(fd);
+	async_answer_0(rid, rc);
+}
+
+static void vfs_in_read(ipc_callid_t rid, ipc_call_t *request)
+{
+	int fd = IPC_GET_ARG1(*request);
+	aoff64_t pos = MERGE_LOUP32(IPC_GET_ARG2(*request),
+	    IPC_GET_ARG3(*request));
+
+	size_t bytes = 0;
+	int rc = vfs_op_read(fd, pos, &bytes);
+	async_answer_1(rid, rc, bytes);
+}
+
+static void vfs_in_rename(ipc_callid_t rid, ipc_call_t *request)
+{
+	/* The common base directory. */
+	int basefd;
+	char *old = NULL;
+	char *new = NULL;
+	int rc;
+	
+	basefd = IPC_GET_ARG1(*request);
+	
+	/* Retrieve the old path. */
+	rc = async_data_write_accept((void **) &old, true, 0, 0, 0, NULL);
+	if (rc != EOK)
+		goto out;
+	
+	/* Retrieve the new path. */
+	rc = async_data_write_accept((void **) &new, true, 0, 0, 0, NULL);
+	if (rc != EOK)
+		goto out;
+	
+	size_t olen;
+	size_t nlen;
+	char *oldc = canonify(old, &olen);
+	char *newc = canonify(new, &nlen);
+	
+	if ((!oldc) || (!newc)) {
+		rc = EINVAL;
+		goto out;
+	}
+	
+	assert(oldc[olen] == '\0');
+	assert(newc[nlen] == '\0');
+	
+	rc = vfs_op_rename(basefd, oldc, newc);
+
+out:
+	async_answer_0(rid, rc);
+
+	if (old)
+		free(old);
+	if (new)
+		free(new);
+}
+
+static void vfs_in_resize(ipc_callid_t rid, ipc_call_t *request)
+{
+	int fd = IPC_GET_ARG1(*request);
+	int64_t size = MERGE_LOUP32(IPC_GET_ARG2(*request), IPC_GET_ARG3(*request));
+	int rc = vfs_op_resize(fd, size);
+	async_answer_0(rid, rc);
+}
+
+static void vfs_in_stat(ipc_callid_t rid, ipc_call_t *request)
+{
+	int fd = IPC_GET_ARG1(*request);
+	int rc = vfs_op_stat(fd);
+	async_answer_0(rid, rc);
+}
+
+static void vfs_in_statfs(ipc_callid_t rid, ipc_call_t *request)
+{
+	int fd = (int) IPC_GET_ARG1(*request);
+	
+	int rc = vfs_op_statfs(fd);
+	async_answer_0(rid, rc);
+}
+
+static void vfs_in_sync(ipc_callid_t rid, ipc_call_t *request)
+{
+	int fd = IPC_GET_ARG1(*request);
+	int rc = vfs_op_sync(fd);
+	async_answer_0(rid, rc);
+}
+
+static void vfs_in_unlink(ipc_callid_t rid, ipc_call_t *request)
+{
+	int parentfd = IPC_GET_ARG1(*request);
+	int expectfd = IPC_GET_ARG2(*request);
+	
+	char *path;
+	int rc = async_data_write_accept((void **) &path, true, 0, 0, 0, NULL);
+	if (rc == EOK)
+		rc = vfs_op_unlink(parentfd, expectfd, path);
+	
+	async_answer_0(rid, rc);
+}
+
+static void vfs_in_unmount(ipc_callid_t rid, ipc_call_t *request)
+{
+	int mpfd = IPC_GET_ARG1(*request);
+	int rc = vfs_op_unmount(mpfd);
+	async_answer_0(rid, rc);
+}
+
+static void vfs_in_wait_handle(ipc_callid_t rid, ipc_call_t *request)
+{
+	bool high_fd = IPC_GET_ARG1(*request);
+	int fd = vfs_op_wait_handle(high_fd);
+	async_answer_1(rid, EOK, fd);
+}
+
+static void vfs_in_walk(ipc_callid_t rid, ipc_call_t *request)
+{
+	/*
+	 * Parent is our relative root for file lookup.
+	 * For defined flags, see <ipc/vfs.h>.
+	 */
+	int parentfd = IPC_GET_ARG1(*request);
+	int flags = IPC_GET_ARG2(*request);
+	
+	int fd = 0;
+	char *path;
+	int rc = async_data_write_accept((void **)&path, true, 0, 0, 0, NULL);
+	if (rc == EOK) {
+		rc = vfs_op_walk(parentfd, flags, path, &fd);
+		free(path);
+	}
+	async_answer_1(rid, rc, fd);
+}
+
+static void vfs_in_write(ipc_callid_t rid, ipc_call_t *request)
+{
+	int fd = IPC_GET_ARG1(*request);
+	aoff64_t pos = MERGE_LOUP32(IPC_GET_ARG2(*request),
+	    IPC_GET_ARG3(*request));
+
+	size_t bytes = 0;
+	int rc = vfs_op_write(fd, pos, &bytes);
+	async_answer_1(rid, rc, bytes);
+}
+
+void vfs_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
+{
+	bool cont = true;
+	
+	/*
+	 * The connection was opened via the IPC_CONNECT_ME_TO call.
+	 * This call needs to be answered.
+	 */
+	async_answer_0(iid, EOK);
+	
+	while (cont) {
+		ipc_call_t call;
+		ipc_callid_t callid = async_get_call(&call);
+		
+		if (!IPC_GET_IMETHOD(call))
+			break;
+		
+		switch (IPC_GET_IMETHOD(call)) {
+		case VFS_IN_CLONE:
+			vfs_in_clone(callid, &call);
+			break;
+		case VFS_IN_MOUNT:
+			vfs_in_mount(callid, &call);
+			break;
+		case VFS_IN_OPEN:
+			vfs_in_open(callid, &call);
+			break;
+		case VFS_IN_PUT:
+			vfs_in_put(callid, &call);
+			break;
+		case VFS_IN_READ:
+			vfs_in_read(callid, &call);
+			break;
+		case VFS_IN_REGISTER:
+			vfs_register(callid, &call);
+			cont = false;
+			break;
+		case VFS_IN_RENAME:
+			vfs_in_rename(callid, &call);
+			break;
+		case VFS_IN_RESIZE:
+			vfs_in_resize(callid, &call);
+			break;
+		case VFS_IN_STAT:
+			vfs_in_stat(callid, &call);
+			break;
+		case VFS_IN_STATFS:
+			vfs_in_statfs(callid, &call);
+			break;
+		case VFS_IN_SYNC:
+			vfs_in_sync(callid, &call);
+			break;
+		case VFS_IN_UNLINK:
+			vfs_in_unlink(callid, &call);
+			break;
+		case VFS_IN_UNMOUNT:
+			vfs_in_unmount(callid, &call);
+			break;
+		case VFS_IN_WAIT_HANDLE:
+			vfs_in_wait_handle(callid, &call);
+			break;
+		case VFS_IN_WALK:
+			vfs_in_walk(callid, &call);
+			break;
+		case VFS_IN_WRITE:
+			vfs_in_write(callid, &call);
+			break;
+		default:
+			async_answer_0(callid, ENOTSUP);
+			break;
+		}
+	}
+	
+	/*
+	 * Open files for this client will be cleaned up when its last
+	 * connection fibril terminates.
+	 */
+}
Index: uspace/srv/vfs/vfs_lookup.c
===================================================================
--- uspace/srv/vfs/vfs_lookup.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/srv/vfs/vfs_lookup.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -46,6 +46,6 @@
 #include <adt/list.h>
 #include <vfs/canonify.h>
-
-#define min(a, b)  ((a) < (b) ? (a) : (b))
+#include <dirent.h>
+#include <assert.h>
 
 FIBRIL_MUTEX_INITIALIZE(plb_mutex);
@@ -53,49 +53,11 @@
 uint8_t *plb = NULL;
 
-/** Perform a path lookup.
- *
- * @param path    Path to be resolved; it must be a NULL-terminated
- *                string.
- * @param lflag   Flags to be used during lookup.
- * @param result  Empty structure where the lookup result will be stored.
- *                Can be NULL.
- * @param altroot If non-empty, will be used instead of rootfs as the root
- *                of the whole VFS tree.
- *
- * @return EOK on success or an error code from errno.h.
- *
- */
-int vfs_lookup_internal(char *path, int lflag, vfs_lookup_res_t *result,
-    vfs_pair_t *altroot, ...)
-{
-	vfs_pair_t *root;
-
-	if (altroot)
-		root = altroot;
-	else
-		root = &rootfs;
-
-	if (!root->fs_handle)
-		return ENOENT;
-	
-	size_t len;
-	path = canonify(path, &len);
-	if (!path)
-		return EINVAL;
-	
-	fs_index_t index = 0;
-	if (lflag & L_LINK) {
-		va_list ap;
-
-		va_start(ap, altroot);
-		index = va_arg(ap, fs_index_t);
-		va_end(ap);
-	}
-	
+static int plb_insert_entry(plb_entry_t *entry, char *path, size_t *start,
+    size_t len)
+{
 	fibril_mutex_lock(&plb_mutex);
 
-	plb_entry_t entry;
-	link_initialize(&entry.plb_link);
-	entry.len = len;
+	link_initialize(&entry->plb_link);
+	entry->len = len;
 
 	size_t first;	/* the first free index */
@@ -138,6 +100,6 @@
 	 */
 
-	entry.index = first;
-	entry.len = len;
+	entry->index = first;
+	entry->len = len;
 
 	/*
@@ -145,5 +107,5 @@
 	 * buffer.
 	 */
-	list_append(&entry.plb_link, &plb_entries);
+	list_append(&entry->plb_link, &plb_entries);
 	
 	fibril_mutex_unlock(&plb_mutex);
@@ -158,45 +120,278 @@
 	memcpy(plb, &path[cnt1], cnt2);
 
-	ipc_call_t answer;
-	async_exch_t *exch = vfs_exchange_grab(root->fs_handle);
-	aid_t req = async_send_5(exch, VFS_OUT_LOOKUP, (sysarg_t) first,
-	    (sysarg_t) (first + len - 1) % PLB_SIZE,
-	    (sysarg_t) root->service_id, (sysarg_t) lflag, (sysarg_t) index,
-	    &answer);
-	
-	sysarg_t rc;
-	async_wait_for(req, &rc);
-	vfs_exchange_release(exch);
-	
+	*start = first;
+	return EOK;
+}
+
+static void plb_clear_entry(plb_entry_t *entry, size_t first, size_t len)
+{
 	fibril_mutex_lock(&plb_mutex);
-	list_remove(&entry.plb_link);
+	list_remove(&entry->plb_link);
 	/*
 	 * Erasing the path from PLB will come handy for debugging purposes.
 	 */
+	size_t cnt1 = min(len, (PLB_SIZE - first) + 1);
+	size_t cnt2 = len - cnt1;
 	memset(&plb[first], 0, cnt1);
 	memset(plb, 0, cnt2);
 	fibril_mutex_unlock(&plb_mutex);
-	
-	if ((int) rc < EOK)
+}
+
+int vfs_link_internal(vfs_node_t *base, char *path, vfs_triplet_t *child)
+{
+	assert(base != NULL);
+	assert(child != NULL);
+	assert(base->fs_handle);
+	assert(child->fs_handle);
+	assert(path != NULL);
+	
+	vfs_lookup_res_t res;
+	char component[NAME_MAX + 1];
+	int rc;
+	
+	size_t len;
+	char *npath = canonify(path, &len);
+	if (!npath) {
+		rc = EINVAL;
+		goto out;
+	}
+	path = npath;
+	
+	vfs_triplet_t *triplet;
+	
+	char *slash = str_rchr(path, L'/');
+	if (slash && slash != path) {
+		if (slash[1] == 0) {
+			rc = EINVAL;
+			goto out;
+		}
+		
+		memcpy(component, slash + 1, str_size(slash));
+		*slash = 0;
+		
+		rc = vfs_lookup_internal(base, path, L_DIRECTORY, &res);
+		if (rc != EOK)
+			goto out;
+		triplet = &res.triplet;
+		
+		*slash = '/';
+	} else {
+		if (base->mount != NULL) {
+			rc = EINVAL;
+			goto out;
+		}
+		
+		memcpy(component, path + 1, str_size(path));
+		triplet = (vfs_triplet_t *) base;
+	}
+	
+	if (triplet->fs_handle != child->fs_handle ||
+	    triplet->service_id != child->service_id) {
+		rc = EXDEV;
+		goto out;
+	}
+	
+	async_exch_t *exch = vfs_exchange_grab(triplet->fs_handle);
+	aid_t req = async_send_3(exch, VFS_OUT_LINK, triplet->service_id,
+	    triplet->index, child->index, NULL);
+	
+	rc = async_data_write_start(exch, component, str_size(component) + 1);
+	sysarg_t orig_rc;
+	async_wait_for(req, &orig_rc);
+	vfs_exchange_release(exch);
+	if (orig_rc != EOK)
+		rc = orig_rc;
+	
+out:
+	return rc;
+}
+
+static int out_lookup(vfs_triplet_t *base, size_t *pfirst, size_t *plen,
+    int lflag, vfs_lookup_res_t *result)
+{
+	assert(base);
+	assert(result);
+	
+	sysarg_t rc;
+	ipc_call_t answer;
+	async_exch_t *exch = vfs_exchange_grab(base->fs_handle);
+	aid_t req = async_send_5(exch, VFS_OUT_LOOKUP, (sysarg_t) *pfirst,
+	    (sysarg_t) *plen, (sysarg_t) base->service_id,
+	    (sysarg_t) base->index, (sysarg_t) lflag, &answer);
+	async_wait_for(req, &rc);
+	vfs_exchange_release(exch);
+	
+	if ((int) rc < 0)
 		return (int) rc;
-
-	if (!result)
-		return EOK;
+	
+	unsigned last = *pfirst + *plen;
+	*pfirst = IPC_GET_ARG3(answer) & 0xffff;
+	*plen = last - *pfirst;
 	
 	result->triplet.fs_handle = (fs_handle_t) rc;
 	result->triplet.service_id = (service_id_t) IPC_GET_ARG1(answer);
 	result->triplet.index = (fs_index_t) IPC_GET_ARG2(answer);
-	result->size =
-	    (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(answer), IPC_GET_ARG4(answer));
-	result->lnkcnt = (unsigned int) IPC_GET_ARG5(answer);
-	
-	if (lflag & L_FILE)
-		result->type = VFS_NODE_FILE;
-	else if (lflag & L_DIRECTORY)
-		result->type = VFS_NODE_DIRECTORY;
-	else
-		result->type = VFS_NODE_UNKNOWN;
-	
+	result->size = MERGE_LOUP32(IPC_GET_ARG4(answer), IPC_GET_ARG5(answer));
+	result->type = (IPC_GET_ARG3(answer) >> 16) ?
+	    VFS_NODE_DIRECTORY : VFS_NODE_FILE;
 	return EOK;
+}
+
+static int _vfs_lookup_internal(vfs_node_t *base, char *path, int lflag,
+    vfs_lookup_res_t *result, size_t len)
+{
+	size_t first;
+	int rc;
+
+	plb_entry_t entry;
+	rc = plb_insert_entry(&entry, path, &first, len);
+	if (rc != EOK)
+		return rc;
+	
+	size_t next = first;
+	size_t nlen = len;
+	
+	vfs_lookup_res_t res;
+	
+	/* Resolve path as long as there are mount points to cross. */
+	while (nlen > 0) {
+		while (base->mount) {
+			if (lflag & L_DISABLE_MOUNTS) {
+				rc = EXDEV;
+				goto out;
+			}
+			
+			base = base->mount;
+		}
+		
+		rc = out_lookup((vfs_triplet_t *) base, &next, &nlen, lflag,
+		    &res);
+		if (rc != EOK)
+			goto out;
+		
+		if (nlen > 0) {
+			base = vfs_node_peek(&res);
+			if (!base) {
+				rc = ENOENT;
+				goto out;
+			}
+	       		if (!base->mount) {
+				vfs_node_put(base);
+				rc = ENOENT;
+				goto out;
+			}
+			vfs_node_put(base);
+			if (lflag & L_DISABLE_MOUNTS) {
+				rc = EXDEV;
+				goto out;
+			}
+		}
+	}
+	
+	assert(nlen == 0);
+	rc = EOK;
+	
+	if (result != NULL) {
+		/* The found file may be a mount point. Try to cross it. */
+		if (!(lflag & (L_MP | L_DISABLE_MOUNTS))) {
+			base = vfs_node_peek(&res);
+			if (base && base->mount) {
+				while (base->mount) {
+					vfs_node_addref(base->mount);
+					vfs_node_t *nbase = base->mount;
+					vfs_node_put(base);
+					base = nbase;
+				}
+				
+				result->triplet = *((vfs_triplet_t *) base);
+				result->type = base->type;
+				result->size = base->size;
+				vfs_node_put(base);
+				goto out;
+			}
+			if (base)
+				vfs_node_put(base);
+		}
+
+		*result = res;
+	}
+	
+out:
+	plb_clear_entry(&entry, first, len);
+	return rc;
+}
+
+/** Perform a path lookup.
+ *
+ * @param base    The file from which to perform the lookup.
+ * @param path    Path to be resolved; it must be a NULL-terminated
+ *                string.
+ * @param lflag   Flags to be used during lookup.
+ * @param result  Empty structure where the lookup result will be stored.
+ *                Can be NULL.
+ *
+ * @return EOK on success or an error code from errno.h.
+ *
+ */
+int vfs_lookup_internal(vfs_node_t *base, char *path, int lflag,
+    vfs_lookup_res_t *result)
+{
+	assert(base != NULL);
+	assert(path != NULL);
+	
+	size_t len;
+	int rc;
+	char *npath = canonify(path, &len);
+	if (!npath) {
+		rc = EINVAL;
+		return rc;
+	}
+	path = npath;
+	
+	assert(path[0] == '/');
+
+
+	if (lflag & (L_CREATE | L_UNLINK)) {
+
+		/*
+		 * Creation and destruction of names must be done in two
+		 * separate steps: lookup of the parent node and the name
+		 * link/unlink operation itself.  Otherwise the parent
+		 * filesystem would not be able to tell when a mountpoint is
+		 * crossed. It would attempt to perform the link/unlink in
+		 * itself instead of letting the mounted filesystem do it,
+		 * resulting in wrong behavior. This is the wages of server-side
+		 * mountpoints.
+		 */
+
+		char *slash = str_rchr(path, L'/');
+		vfs_node_t *parent = base;
+		
+		if (slash != path) {
+			int tflag = lflag;
+			vfs_lookup_res_t tres;
+
+			tflag &= ~(L_CREATE | L_EXCLUSIVE | L_UNLINK | L_FILE);
+			tflag |= L_DIRECTORY;
+			rc = _vfs_lookup_internal(base, path, tflag, &tres,
+			    slash - path);
+			if (rc != EOK)
+				return rc;
+			parent = vfs_node_get(&tres);
+			if (!parent)
+				return ENOMEM;
+		} else
+			vfs_node_addref(parent);
+
+		rc = _vfs_lookup_internal(parent, slash, lflag, result,
+		    len - (slash - path));
+
+		vfs_node_put(parent);
+
+	} else {
+		rc = _vfs_lookup_internal(base, path, lflag, result, len);
+	}
+	
+	return rc;
 }
 
Index: uspace/srv/vfs/vfs_node.c
===================================================================
--- uspace/srv/vfs/vfs_node.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/srv/vfs/vfs_node.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -45,4 +45,5 @@
 #include <async.h>
 #include <errno.h>
+#include <macros.h>
 
 /** Mutex protecting the VFS node hash table. */
@@ -106,11 +107,10 @@
 void vfs_node_delref(vfs_node_t *node)
 {
-	bool free_vfs_node = false;
-	bool free_fs_node = false;
-	
-	fibril_mutex_lock(&nodes_mutex);
-	
-	if (node->refcnt-- == 1) {
-		
+	bool free_node = false;
+	
+	fibril_mutex_lock(&nodes_mutex);
+	
+	node->refcnt--;
+	if (node->refcnt == 0) {
 		/*
 		 * We are dropping the last reference to this node.
@@ -119,29 +119,22 @@
 		
 		hash_table_remove_item(&nodes, &node->nh_link);
-		free_vfs_node = true;
-		
-		if (!node->lnkcnt)
-			free_fs_node = true;
+		free_node = true;
 	}
 	
 	fibril_mutex_unlock(&nodes_mutex);
 	
-	if (free_fs_node) {
-		
+	if (free_node) {
 		/*
-		 * The node is not visible in the file system namespace.
-		 * Free up its resources.
+		 * VFS_OUT_DESTROY will free up the file's resources if there
+		 * are no more hard links.
 		 */
 		
 		async_exch_t *exch = vfs_exchange_grab(node->fs_handle);
-		sysarg_t rc = async_req_2_0(exch, VFS_OUT_DESTROY,
-		    (sysarg_t) node->service_id, (sysarg_t)node->index);
-		
-		assert(rc == EOK);
+		async_msg_2(exch, VFS_OUT_DESTROY, (sysarg_t) node->service_id,
+		    (sysarg_t)node->index);
 		vfs_exchange_release(exch);
+
+		free(node);
 	}
-	
-	if (free_vfs_node)
-		free(node);
 }
 
@@ -190,5 +183,4 @@
 		node->index = result->triplet.index;
 		node->size = result->size;
-		node->lnkcnt = result->lnkcnt;
 		node->type = result->type;
 		fibril_rwlock_initialize(&node->contents_rwlock);
@@ -196,16 +188,22 @@
 	} else {
 		node = hash_table_get_inst(tmp, vfs_node_t, nh_link);
-		if (node->type == VFS_NODE_UNKNOWN &&
-		    result->type != VFS_NODE_UNKNOWN) {
-			/* Upgrade the node type. */
-			node->type = result->type;
-		}
 	}
 
-	assert(node->size == result->size || node->type != VFS_NODE_FILE);
-	assert(node->lnkcnt == result->lnkcnt);
-	assert(node->type == result->type || result->type == VFS_NODE_UNKNOWN);
-
 	_vfs_node_addref(node);
+	fibril_mutex_unlock(&nodes_mutex);
+
+	return node;
+}
+
+vfs_node_t *vfs_node_peek(vfs_lookup_res_t *result)
+{
+	vfs_node_t *node = NULL;
+
+	fibril_mutex_lock(&nodes_mutex);
+	ht_link_t *tmp = hash_table_find(&nodes, &result->triplet);
+	if (tmp) {
+		node = hash_table_get_inst(tmp, vfs_node_t, nh_link);
+		_vfs_node_addref(node);
+	}
 	fibril_mutex_unlock(&nodes_mutex);
 
@@ -302,7 +300,6 @@
 	vfs_triplet_t *tri = key;
 	vfs_node_t *node = hash_table_get_inst(item, vfs_node_t, nh_link);
-	return node->fs_handle == tri->fs_handle 
-		&& node->service_id == tri->service_id
-		&& node->index == tri->index;
+	return node->fs_handle == tri->fs_handle &&
+	    node->service_id == tri->service_id && node->index == tri->index;
 }
 
@@ -318,4 +315,13 @@
 }
 
+bool vfs_node_has_children(vfs_node_t *node)
+{
+	async_exch_t *exch = vfs_exchange_grab(node->fs_handle);
+	int rc = async_req_2_0(exch, VFS_OUT_IS_EMPTY, node->service_id,
+	    node->index);
+	vfs_exchange_release(exch);
+	return rc == ENOTEMPTY;
+}
+
 /**
  * @}
Index: uspace/srv/vfs/vfs_ops.c
===================================================================
--- uspace/srv/vfs/vfs_ops.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/srv/vfs/vfs_ops.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -49,12 +49,6 @@
 #include <unistd.h>
 #include <ctype.h>
-#include <fcntl.h>
 #include <assert.h>
 #include <vfs/canonify.h>
-#include <vfs/vfs_mtab.h>
-
-FIBRIL_MUTEX_INITIALIZE(mtab_list_lock);
-LIST_INITIALIZE(mtab_list);
-static size_t mtab_size = 0;
 
 /* Forward declarations of static functions. */
@@ -68,674 +62,264 @@
 FIBRIL_RWLOCK_INITIALIZE(namespace_rwlock);
 
-vfs_pair_t rootfs = {
-	.fs_handle = 0,
-	.service_id = 0
-};
-
-static int vfs_mount_internal(ipc_callid_t rid, service_id_t service_id,
-    fs_handle_t fs_handle, char *mp, char *opts)
-{
-	vfs_lookup_res_t mp_res;
-	vfs_lookup_res_t mr_res;
-	vfs_node_t *mp_node = NULL;
-	vfs_node_t *mr_node;
-	fs_index_t rindex;
-	aoff64_t rsize;
-	unsigned rlnkcnt;
-	async_exch_t *exch;
-	sysarg_t rc;
-	aid_t msg;
+static size_t shared_path(char *a, char *b)
+{
+	size_t res = 0;
+	
+	while (a[res] == b[res] && a[res] != 0)
+		res++;
+	
+	if (a[res] == b[res])
+		return res;
+	
+	res--;
+	while (a[res] != '/')
+		res--;
+	return res;
+}
+
+/* This call destroys the file if and only if there are no hard links left. */
+static void out_destroy(vfs_triplet_t *file)
+{
+	async_exch_t *exch = vfs_exchange_grab(file->fs_handle);
+	async_msg_2(exch, VFS_OUT_DESTROY, (sysarg_t) file->service_id,
+	    (sysarg_t) file->index);
+	vfs_exchange_release(exch);
+}
+
+int vfs_op_clone(int oldfd, int newfd, bool desc)
+{
+	int rc;
+
+	/* If the file descriptors are the same, do nothing. */
+	if (oldfd == newfd)
+		return EOK;
+	
+	/* Lookup the file structure corresponding to fd. */
+	vfs_file_t *oldfile = vfs_file_get(oldfd);
+	if (oldfile == NULL)
+		return EBADF;
+
+	assert(oldfile->node != NULL);
+
+	if (newfd != -1) {
+		/* Make sure newfd is closed. */
+		(void) vfs_fd_free(newfd);
+		/* Assign the old file to newfd. */
+		rc = vfs_fd_assign(oldfile, newfd);
+	} else {
+		vfs_file_t *newfile;
+		int newfd = vfs_fd_alloc(&newfile, desc);
+		if (newfd >= 0) {
+			newfile->node = oldfile->node;
+			newfile->permissions = oldfile->permissions;
+			vfs_node_addref(newfile->node);
+	
+			vfs_file_put(newfile);
+		}
+		rc = newfd;
+	}
+	vfs_file_put(oldfile);
+	
+	return rc;
+}
+
+int vfs_op_put(int fd)
+{
+	return vfs_fd_free(fd);
+}
+
+static int vfs_connect_internal(service_id_t service_id, unsigned flags,
+    unsigned instance, const char *options, const char *fsname,
+    vfs_node_t **root)
+{
+	fs_handle_t fs_handle = 0;
+	
+	fibril_mutex_lock(&fs_list_lock);
+	while (true) {
+		fs_handle = fs_name_to_handle(instance, fsname, false);
+		
+		if (fs_handle != 0 || !(flags & VFS_MOUNT_BLOCKING))
+			break;
+		
+		fibril_condvar_wait(&fs_list_cv, &fs_list_lock);
+	}
+	fibril_mutex_unlock(&fs_list_lock);
+
+	if (fs_handle == 0)
+		return ENOENT;
+	
+	/* Tell the mountee that it is being mounted. */
 	ipc_call_t answer;
-	
-	/* Resolve the path to the mountpoint. */
-	fibril_rwlock_write_lock(&namespace_rwlock);
-	if (rootfs.fs_handle) {
-		/* We already have the root FS. */
-		if (str_cmp(mp, "/") == 0) {
-			/* Trying to mount root FS over root FS */
-			fibril_rwlock_write_unlock(&namespace_rwlock);
-			async_answer_0(rid, EBUSY);
-			return EBUSY;
-		}
-		
-		rc = vfs_lookup_internal(mp, L_MP, &mp_res, NULL);
-		if (rc != EOK) {
-			/* The lookup failed for some reason. */
-			fibril_rwlock_write_unlock(&namespace_rwlock);
-			async_answer_0(rid, rc);
-			return rc;
-		}
-		
-		mp_node = vfs_node_get(&mp_res);
-		if (!mp_node) {
-			fibril_rwlock_write_unlock(&namespace_rwlock);
-			async_answer_0(rid, ENOMEM);
-			return ENOMEM;
-		}
-		
-		/*
-		 * Now we hold a reference to mp_node.
-		 * It will be dropped upon the corresponding VFS_IN_UNMOUNT.
-		 * This prevents the mount point from being deleted.
-		 */
-	} else {
-		/* We still don't have the root file system mounted. */
-		if (str_cmp(mp, "/") == 0) {
-			/*
-			 * For this simple, but important case,
-			 * we are almost done.
-			 */
-			
-			/* Tell the mountee that it is being mounted. */
-			exch = vfs_exchange_grab(fs_handle);
-			msg = async_send_1(exch, VFS_OUT_MOUNTED,
-			    (sysarg_t) service_id, &answer);
-			/* Send the mount options */
-			rc = async_data_write_start(exch, (void *)opts,
-			    str_size(opts));
-			vfs_exchange_release(exch);
-			
-			if (rc != EOK) {
-				async_forget(msg);
-				fibril_rwlock_write_unlock(&namespace_rwlock);
-				async_answer_0(rid, rc);
-				return rc;
-			}
-			async_wait_for(msg, &rc);
-			
-			if (rc != EOK) {
-				fibril_rwlock_write_unlock(&namespace_rwlock);
-				async_answer_0(rid, rc);
-				return rc;
-			}
-
-			rindex = (fs_index_t) IPC_GET_ARG1(answer);
-			rsize = (aoff64_t) MERGE_LOUP32(IPC_GET_ARG2(answer),
-			    IPC_GET_ARG3(answer));
-			rlnkcnt = (unsigned) IPC_GET_ARG4(answer);
-			
-			mr_res.triplet.fs_handle = fs_handle;
-			mr_res.triplet.service_id = service_id;
-			mr_res.triplet.index = rindex;
-			mr_res.size = rsize;
-			mr_res.lnkcnt = rlnkcnt;
-			mr_res.type = VFS_NODE_DIRECTORY;
-			
-			rootfs.fs_handle = fs_handle;
-			rootfs.service_id = service_id;
-			
-			/* Add reference to the mounted root. */
-			mr_node = vfs_node_get(&mr_res); 
-			assert(mr_node);
-			
-			fibril_rwlock_write_unlock(&namespace_rwlock);
-			async_answer_0(rid, rc);
-			return rc;
-		} else {
-			/*
-			 * We can't resolve this without the root filesystem
-			 * being mounted first.
-			 */
-			fibril_rwlock_write_unlock(&namespace_rwlock);
-			async_answer_0(rid, ENOENT);
-			return ENOENT;
-		}
-	}
-	
-	/*
-	 * At this point, we have all necessary pieces: file system handle
-	 * and service ID, and we know the mount point VFS node.
-	 */
-	
-	async_exch_t *mountee_exch = vfs_exchange_grab(fs_handle);
-	assert(mountee_exch);
-	
-	exch = vfs_exchange_grab(mp_res.triplet.fs_handle);
-	msg = async_send_4(exch, VFS_OUT_MOUNT,
-	    (sysarg_t) mp_res.triplet.service_id,
-	    (sysarg_t) mp_res.triplet.index,
-	    (sysarg_t) fs_handle,
-	    (sysarg_t) service_id, &answer);
-	
-	/* Send connection */
-	rc = async_exchange_clone(exch, mountee_exch);
-	vfs_exchange_release(mountee_exch);
-	
+	async_exch_t *exch = vfs_exchange_grab(fs_handle);
+	aid_t msg = async_send_1(exch, VFS_OUT_MOUNTED, (sysarg_t) service_id,
+	    &answer);
+	/* Send the mount options */
+	sysarg_t rc = async_data_write_start(exch, options, str_size(options));
+	if (rc != EOK) {
+		async_forget(msg);
+		vfs_exchange_release(exch);
+		return rc;
+	}
+
+	async_wait_for(msg, &rc);
 	if (rc != EOK) {
 		vfs_exchange_release(exch);
+		return rc;
+	}
+	
+	vfs_lookup_res_t res;
+	res.triplet.fs_handle = fs_handle;
+	res.triplet.service_id = service_id;
+	res.triplet.index = (fs_index_t) IPC_GET_ARG1(answer);
+	res.size = (int64_t) MERGE_LOUP32(IPC_GET_ARG2(answer),
+	    IPC_GET_ARG3(answer));
+	res.type = VFS_NODE_DIRECTORY;
+	
+	/* Add reference to the mounted root. */
+	*root = vfs_node_get(&res); 
+	if (!*root) {
+		aid_t msg = async_send_1(exch, VFS_OUT_UNMOUNTED,
+		    (sysarg_t) service_id, NULL);
 		async_forget(msg);
-		
-		/* Mount failed, drop reference to mp_node. */
-		if (mp_node)
-			vfs_node_put(mp_node);
-		
-		async_answer_0(rid, rc);
-		fibril_rwlock_write_unlock(&namespace_rwlock);
+		vfs_exchange_release(exch);
+		return ENOMEM;
+	}
+			
+	vfs_exchange_release(exch);
+
+	return EOK;
+}
+
+int vfs_op_mount(int mpfd, unsigned service_id, unsigned flags,
+    unsigned instance, const char *opts, const char *fs_name, int *outfd)
+{
+	int rc;
+	vfs_file_t *mp = NULL;
+	vfs_file_t *file = NULL;
+	int fd = -1;
+	
+	if (!(flags & VFS_MOUNT_CONNECT_ONLY)) {
+		mp = vfs_file_get(mpfd);
+		if (mp == NULL) {
+			rc = EBADF;
+			goto out;
+		}
+		
+		if (mp->node->mount != NULL) {
+			rc = EBUSY;
+			goto out;
+		}
+		
+		if (mp->node->type != VFS_NODE_DIRECTORY) {
+			rc = ENOTDIR;
+			goto out;
+		}
+		
+		if (vfs_node_has_children(mp->node)) {
+			rc = ENOTEMPTY;
+			goto out;
+		}
+	}
+	
+	if (!(flags & VFS_MOUNT_NO_REF)) {
+		fd = vfs_fd_alloc(&file, false);
+		if (fd < 0) {
+			rc = fd;
+			goto out;
+		}
+	}
+	
+	vfs_node_t *root = NULL;
+	
+	fibril_rwlock_write_lock(&namespace_rwlock);
+
+	rc = vfs_connect_internal(service_id, flags, instance, opts, fs_name,
+	     &root);
+	if (rc == EOK && !(flags & VFS_MOUNT_CONNECT_ONLY)) {
+		vfs_node_addref(mp->node);
+		vfs_node_addref(root);
+		mp->node->mount = root;
+	}
+	
+	fibril_rwlock_write_unlock(&namespace_rwlock);
+	
+	if (rc != EOK)
+		goto out;
+	
+	if (flags & VFS_MOUNT_NO_REF) {
+		vfs_node_delref(root);
+	} else {
+		assert(file != NULL);
+		
+		file->node = root;
+		file->permissions = MODE_READ | MODE_WRITE | MODE_APPEND;
+		file->open_read = false;
+		file->open_write = false;
+	}
+	
+out:
+	if (mp)
+		vfs_file_put(mp);
+	if (file)
+		vfs_file_put(file);
+
+	if (rc != EOK && fd >= 0) {
+		vfs_fd_free(fd);
+		fd = 0;
+	}
+	
+	*outfd = fd;
+	return rc;
+}
+
+int vfs_op_open(int fd, int mode)
+{
+	if (mode == 0)
+		return EINVAL;
+
+	vfs_file_t *file = vfs_file_get(fd);
+	if (!file)
+		return EBADF;
+	
+	if ((mode & ~file->permissions) != 0) {
+		vfs_file_put(file);
+		return EPERM;
+	}
+	
+	if (file->open_read || file->open_write) {
+		vfs_file_put(file);
+		return EBUSY;
+	}
+	
+	file->open_read = (mode & MODE_READ) != 0;
+	file->open_write = (mode & (MODE_WRITE | MODE_APPEND)) != 0;
+	file->append = (mode & MODE_APPEND) != 0;
+	
+	if (!file->open_read && !file->open_write) {
+		vfs_file_put(file);
+		return EINVAL;
+	}
+	
+	if (file->node->type == VFS_NODE_DIRECTORY && file->open_write) {
+		file->open_read = file->open_write = false;
+		vfs_file_put(file);
+		return EINVAL;
+	}
+	
+	int rc = vfs_open_node_remote(file->node);
+	if (rc != EOK) {
+		file->open_read = file->open_write = false;
+		vfs_file_put(file);
 		return rc;
 	}
 	
-	/* send the mount options */
-	rc = async_data_write_start(exch, (void *) opts, str_size(opts));
-	if (rc != EOK) {
-		vfs_exchange_release(exch);
-		async_forget(msg);
-		
-		/* Mount failed, drop reference to mp_node. */
-		if (mp_node)
-			vfs_node_put(mp_node);
-		
-		fibril_rwlock_write_unlock(&namespace_rwlock);
-		async_answer_0(rid, rc);
-		return rc;
-	}
-	
-	/*
-	 * Wait for the answer before releasing the exchange to avoid deadlock
-	 * in case the answer depends on further calls to the same file system.
-	 * Think of a case when mounting a FS on a file_bd backed by a file on
-	 * the same FS. 
-	 */
-	async_wait_for(msg, &rc);
-	vfs_exchange_release(exch);
-	
-	if (rc == EOK) {
-		rindex = (fs_index_t) IPC_GET_ARG1(answer);
-		rsize = (aoff64_t) MERGE_LOUP32(IPC_GET_ARG2(answer),
-		    IPC_GET_ARG3(answer));
-		rlnkcnt = (unsigned) IPC_GET_ARG4(answer);
-		
-		mr_res.triplet.fs_handle = fs_handle;
-		mr_res.triplet.service_id = service_id;
-		mr_res.triplet.index = rindex;
-		mr_res.size = rsize;
-		mr_res.lnkcnt = rlnkcnt;
-		mr_res.type = VFS_NODE_DIRECTORY;
-		
-		/* Add reference to the mounted root. */
-		mr_node = vfs_node_get(&mr_res); 
-		assert(mr_node);
-	} else {
-		/* Mount failed, drop reference to mp_node. */
-		if (mp_node)
-			vfs_node_put(mp_node);
-	}
-	
-	async_answer_0(rid, rc);
-	fibril_rwlock_write_unlock(&namespace_rwlock);
-	return rc;
-}
-
-void vfs_mount_srv(ipc_callid_t rid, ipc_call_t *request)
-{
-	service_id_t service_id;
-
-	/*
-	 * We expect the library to do the device-name to device-handle
-	 * translation for us, thus the device handle will arrive as ARG1
-	 * in the request.
-	 */
-	service_id = (service_id_t) IPC_GET_ARG1(*request);
-	
-	/*
-	 * Mount flags are passed as ARG2.
-	 */
-	unsigned int flags = (unsigned int) IPC_GET_ARG2(*request);
-	
-	/*
-	 * Instance number is passed as ARG3.
-	 */
-	unsigned int instance = IPC_GET_ARG3(*request);
-
-	/* We want the client to send us the mount point. */
-	char *mp;
-	int rc = async_data_write_accept((void **) &mp, true, 0, MAX_PATH_LEN,
-	    0, NULL);
-	if (rc != EOK) {
-		async_answer_0(rid, rc);
-		return;
-	}
-	
-	/* Now we expect to receive the mount options. */
-	char *opts;
-	rc = async_data_write_accept((void **) &opts, true, 0, MAX_MNTOPTS_LEN,
-	    0, NULL);
-	if (rc != EOK) {
-		free(mp);
-		async_answer_0(rid, rc);
-		return;
-	}
-	
-	/*
-	 * Now, we expect the client to send us data with the name of the file
-	 * system.
-	 */
-	char *fs_name;
-	rc = async_data_write_accept((void **) &fs_name, true, 0,
-	    FS_NAME_MAXLEN, 0, NULL);
-	if (rc != EOK) {
-		free(mp);
-		free(opts);
-		async_answer_0(rid, rc);
-		return;
-	}
-	
-	/*
-	 * Wait for VFS_IN_PING so that we can return an error if we don't know
-	 * fs_name.
-	 */
-	ipc_call_t data;
-	ipc_callid_t callid = async_get_call(&data);
-	if (IPC_GET_IMETHOD(data) != VFS_IN_PING) {
-		async_answer_0(callid, ENOTSUP);
-		async_answer_0(rid, ENOTSUP);
-		free(mp);
-		free(opts);
-		free(fs_name);
-		return;
-	}
-
-	/*
-	 * Check if we know a file system with the same name as is in fs_name.
-	 * This will also give us its file system handle.
-	 */
-	fibril_mutex_lock(&fs_list_lock);
-	fs_handle_t fs_handle;
-recheck:
-	fs_handle = fs_name_to_handle(instance, fs_name, false);
-	if (!fs_handle) {
-		if (flags & IPC_FLAG_BLOCKING) {
-			fibril_condvar_wait(&fs_list_cv, &fs_list_lock);
-			goto recheck;
-		}
-		
-		fibril_mutex_unlock(&fs_list_lock);
-		async_answer_0(callid, ENOENT);
-		async_answer_0(rid, ENOENT);
-		free(mp);
-		free(fs_name);
-		free(opts);
-		return;
-	}
-	fibril_mutex_unlock(&fs_list_lock);
-
-	/* Add the filesystem info to the list of mounted filesystems */
-	mtab_ent_t *mtab_ent = malloc(sizeof(mtab_ent_t));
-	if (!mtab_ent) {
-		async_answer_0(callid, ENOMEM);
-		async_answer_0(rid, ENOMEM);
-		free(mp);
-		free(fs_name);
-		free(opts);
-		return;
-	}
-
-	/* Do the mount */
-	rc = vfs_mount_internal(rid, service_id, fs_handle, mp, opts);
-	if (rc != EOK) {
-		async_answer_0(callid, ENOTSUP);
-		async_answer_0(rid, ENOTSUP);
-		free(mtab_ent);
-		free(mp);
-		free(opts);
-		free(fs_name);
-		return;
-	}
-
-	/* Add the filesystem info to the list of mounted filesystems */
-
-	str_cpy(mtab_ent->mp, MAX_PATH_LEN, mp);
-	str_cpy(mtab_ent->fs_name, FS_NAME_MAXLEN, fs_name);
-	str_cpy(mtab_ent->opts, MAX_MNTOPTS_LEN, opts);
-	mtab_ent->instance = instance;
-	mtab_ent->service_id = service_id;
-
-	link_initialize(&mtab_ent->link);
-
-	fibril_mutex_lock(&mtab_list_lock);
-	list_append(&mtab_ent->link, &mtab_list);
-	mtab_size++;
-	fibril_mutex_unlock(&mtab_list_lock);
-
-	free(mp);
-	free(fs_name);
-	free(opts);
-
-	/* Acknowledge that we know fs_name. */
-	async_answer_0(callid, EOK);
-}
-
-void vfs_unmount_srv(ipc_callid_t rid, ipc_call_t *request)
-{
-	int rc;
-	char *mp;
-	vfs_lookup_res_t mp_res;
-	vfs_lookup_res_t mr_res;
-	vfs_node_t *mr_node;
-	async_exch_t *exch;
-	
-	/*
-	 * Receive the mount point path.
-	 */
-	rc = async_data_write_accept((void **) &mp, true, 0, MAX_PATH_LEN,
-	    0, NULL);
-	if (rc != EOK)
-		async_answer_0(rid, rc);
-	
-	/*
-	 * Taking the namespace lock will do two things for us. First, it will
-	 * prevent races with other lookup operations. Second, it will stop new
-	 * references to already existing VFS nodes and creation of new VFS
-	 * nodes. This is because new references are added as a result of some
-	 * lookup operation or at least of some operation which is protected by
-	 * the namespace lock.
-	 */
-	fibril_rwlock_write_lock(&namespace_rwlock);
-	
-	/*
-	 * Lookup the mounted root and instantiate it.
-	 */
-	rc = vfs_lookup_internal(mp, L_ROOT, &mr_res, NULL);
-	if (rc != EOK) {
-		fibril_rwlock_write_unlock(&namespace_rwlock);
-		free(mp);
-		async_answer_0(rid, rc);
-		return;
-	}
-	mr_node = vfs_node_get(&mr_res);
-	if (!mr_node) {
-		fibril_rwlock_write_unlock(&namespace_rwlock);
-		free(mp);
-		async_answer_0(rid, ENOMEM);
-		return;
-	}
-	
-	/*
-	 * Count the total number of references for the mounted file system. We
-	 * are expecting at least two. One which we got above and one which we
-	 * got when the file system was mounted. If we find more, it means that
-	 * the file system cannot be gracefully unmounted at the moment because
-	 * someone is working with it.
-	 */
-	if (vfs_nodes_refcount_sum_get(mr_node->fs_handle,
-	    mr_node->service_id) != 2) {
-		fibril_rwlock_write_unlock(&namespace_rwlock);
-		vfs_node_put(mr_node);
-		free(mp);
-		async_answer_0(rid, EBUSY);
-		return;
-	}
-	
-	if (str_cmp(mp, "/") == 0) {
-		
-		/*
-		 * Unmounting the root file system.
-		 *
-		 * In this case, there is no mount point node and we send
-		 * VFS_OUT_UNMOUNTED directly to the mounted file system.
-		 */
-		
-		exch = vfs_exchange_grab(mr_node->fs_handle);
-		rc = async_req_1_0(exch, VFS_OUT_UNMOUNTED,
-		    mr_node->service_id);
-		vfs_exchange_release(exch);
-		
-		if (rc != EOK) {
-			fibril_rwlock_write_unlock(&namespace_rwlock);
-			free(mp);
-			vfs_node_put(mr_node);
-			async_answer_0(rid, rc);
-			return;
-		}
-		
-		rootfs.fs_handle = 0;
-		rootfs.service_id = 0;
-	} else {
-		
-		/*
-		 * Unmounting a non-root file system.
-		 *
-		 * We have a regular mount point node representing the parent
-		 * file system, so we delegate the operation to it.
-		 */
-		
-		rc = vfs_lookup_internal(mp, L_MP, &mp_res, NULL);
-		if (rc != EOK) {
-			fibril_rwlock_write_unlock(&namespace_rwlock);
-			free(mp);
-			vfs_node_put(mr_node);
-			async_answer_0(rid, rc);
-			return;
-		}
-		
-		vfs_node_t *mp_node = vfs_node_get(&mp_res);
-		if (!mp_node) {
-			fibril_rwlock_write_unlock(&namespace_rwlock);
-			free(mp);
-			vfs_node_put(mr_node);
-			async_answer_0(rid, ENOMEM);
-			return;
-		}
-		
-		exch = vfs_exchange_grab(mp_node->fs_handle);
-		rc = async_req_2_0(exch, VFS_OUT_UNMOUNT,
-		    mp_node->service_id, mp_node->index);
-		vfs_exchange_release(exch);
-		
-		if (rc != EOK) {
-			fibril_rwlock_write_unlock(&namespace_rwlock);
-			free(mp);
-			vfs_node_put(mp_node);
-			vfs_node_put(mr_node);
-			async_answer_0(rid, rc);
-			return;
-		}
-		
-		/* Drop the reference we got above. */
-		vfs_node_put(mp_node);
-		/* Drop the reference from when the file system was mounted. */
-		vfs_node_put(mp_node);
-	}
-	
-	/*
-	 * All went well, the mounted file system was successfully unmounted.
-	 * The only thing left is to forget the unmounted root VFS node.
-	 */
-	vfs_node_forget(mr_node);
-	fibril_rwlock_write_unlock(&namespace_rwlock);
-
-	fibril_mutex_lock(&mtab_list_lock);
-
-	int found = 0;
-
-	list_foreach(mtab_list, link, mtab_ent_t, mtab_ent) {
-		if (str_cmp(mtab_ent->mp, mp) == 0) {
-			list_remove(&mtab_ent->link);
-			mtab_size--;
-			free(mtab_ent);
-			found = 1;
-			break;
-		}
-	}
-	assert(found);
-	fibril_mutex_unlock(&mtab_list_lock);
-
-	free(mp);
-
-	async_answer_0(rid, EOK);
-}
-
-void vfs_open(ipc_callid_t rid, ipc_call_t *request)
-{
-	/*
-	 * The POSIX interface is open(path, oflag, mode).
-	 * We can receive oflags and mode along with the VFS_IN_OPEN call;
-	 * the path will need to arrive in another call.
-	 *
-	 * We also receive one private, non-POSIX set of flags called lflag
-	 * used to pass information to vfs_lookup_internal().
-	 */
-	int lflag = IPC_GET_ARG1(*request);
-	int oflag = IPC_GET_ARG2(*request);
-	int mode = IPC_GET_ARG3(*request);
-
-	/* Ignore mode for now. */
-	(void) mode;
-	
-	/*
-	 * Make sure that we are called with exactly one of L_FILE and
-	 * L_DIRECTORY. Make sure that the user does not pass L_OPEN,
-	 * L_ROOT or L_MP.
-	 */
-	if (((lflag & (L_FILE | L_DIRECTORY)) == 0) ||
-	    ((lflag & (L_FILE | L_DIRECTORY)) == (L_FILE | L_DIRECTORY)) ||
-	    (lflag & (L_OPEN | L_ROOT | L_MP))) {
-		async_answer_0(rid, EINVAL);
-		return;
-	}
-	
-	if (oflag & O_CREAT)
-		lflag |= L_CREATE;
-	if (oflag & O_EXCL)
-		lflag |= L_EXCLUSIVE;
-	
-	char *path;
-	int rc = async_data_write_accept((void **) &path, true, 0, 0, 0, NULL);
-	if (rc != EOK) {
-		async_answer_0(rid, rc);
-		return;
-	}
-	
-	/*
-	 * Avoid the race condition in which the file can be deleted before we
-	 * find/create-and-lock the VFS node corresponding to the looked-up
-	 * triplet.
-	 */
-	if (lflag & L_CREATE)
-		fibril_rwlock_write_lock(&namespace_rwlock);
-	else
-		fibril_rwlock_read_lock(&namespace_rwlock);
-	
-	/* The path is now populated and we can call vfs_lookup_internal(). */
-	vfs_lookup_res_t lr;
-	rc = vfs_lookup_internal(path, lflag | L_OPEN, &lr, NULL);
-	if (rc != EOK) {
-		if (lflag & L_CREATE)
-			fibril_rwlock_write_unlock(&namespace_rwlock);
-		else
-			fibril_rwlock_read_unlock(&namespace_rwlock);
-		async_answer_0(rid, rc);
-		free(path);
-		return;
-	}
-	
-	/* Path is no longer needed. */
-	free(path);
-	
-	vfs_node_t *node = vfs_node_get(&lr);
-	if (lflag & L_CREATE)
-		fibril_rwlock_write_unlock(&namespace_rwlock);
-	else
-		fibril_rwlock_read_unlock(&namespace_rwlock);
-
-	if (!node) {
-		async_answer_0(rid, ENOMEM);
-		return;
-	}
-	
-	/* Truncate the file if requested and if necessary. */
-	if (oflag & O_TRUNC) {
-		fibril_rwlock_write_lock(&node->contents_rwlock);
-		if (node->size) {
-			rc = vfs_truncate_internal(node->fs_handle,
-			    node->service_id, node->index, 0);
-			if (rc) {
-				fibril_rwlock_write_unlock(&node->contents_rwlock);
-				vfs_node_put(node);
-				async_answer_0(rid, rc);
-				return;
-			}
-			node->size = 0;
-		}
-		fibril_rwlock_write_unlock(&node->contents_rwlock);
-	}
-	
-	/*
-	 * Get ourselves a file descriptor and the corresponding vfs_file_t
-	 * structure.
-	 */
-	int fd = vfs_fd_alloc((oflag & O_DESC) != 0);
-	if (fd < 0) {
-		vfs_node_put(node);
-		async_answer_0(rid, fd);
-		return;
-	}
-	vfs_file_t *file = vfs_file_get(fd);
-	assert(file);
-	file->node = node;
-	if (oflag & O_APPEND)
-		file->append = true;
-	
-	/*
-	 * The following increase in reference count is for the fact that the
-	 * file is being opened and that a file structure is pointing to it.
-	 * It is necessary so that the file will not disappear when
-	 * vfs_node_put() is called. The reference will be dropped by the
-	 * respective VFS_IN_CLOSE.
-	 */
-	vfs_node_addref(node);
-	vfs_node_put(node);
 	vfs_file_put(file);
-	
-	/* Success! Return the new file descriptor to the client. */
-	async_answer_1(rid, EOK, fd);
-}
-
-void vfs_sync(ipc_callid_t rid, ipc_call_t *request)
-{
-	int fd = IPC_GET_ARG1(*request);
-	
-	/* Lookup the file structure corresponding to the file descriptor. */
-	vfs_file_t *file = vfs_file_get(fd);
-	if (!file) {
-		async_answer_0(rid, ENOENT);
-		return;
-	}
-	
-	/*
-	 * Lock the open file structure so that no other thread can manipulate
-	 * the same open file at a time.
-	 */
-	fibril_mutex_lock(&file->lock);
-	async_exch_t *fs_exch = vfs_exchange_grab(file->node->fs_handle);
-	
-	/* Make a VFS_OUT_SYMC request at the destination FS server. */
-	aid_t msg;
-	ipc_call_t answer;
-	msg = async_send_2(fs_exch, VFS_OUT_SYNC, file->node->service_id,
-	    file->node->index, &answer);
-	
-	vfs_exchange_release(fs_exch);
-	
-	/* Wait for reply from the FS server. */
-	sysarg_t rc;
-	async_wait_for(msg, &rc);
-	
-	fibril_mutex_unlock(&file->lock);
-	
-	vfs_file_put(file);
-	async_answer_0(rid, rc);
-}
-
-void vfs_close(ipc_callid_t rid, ipc_call_t *request)
-{
-	int fd = IPC_GET_ARG1(*request);
-	int ret = vfs_fd_free(fd);
-	async_answer_0(rid, ret);
-}
-
-typedef int (* rdwr_ipc_cb_t)(async_exch_t *, vfs_file_t *, ipc_call_t *,
-    bool, void *);
-
-static int rdwr_ipc_client(async_exch_t *exch, vfs_file_t *file,
+	return EOK;
+}
+
+typedef int (* rdwr_ipc_cb_t)(async_exch_t *, vfs_file_t *, aoff64_t,
+    ipc_call_t *, bool, void *);
+
+static int rdwr_ipc_client(async_exch_t *exch, vfs_file_t *file, aoff64_t pos,
     ipc_call_t *answer, bool read, void *data)
 {
@@ -754,9 +338,9 @@
 		rc = async_data_read_forward_4_1(exch, VFS_OUT_READ,
 		    file->node->service_id, file->node->index,
-		    LOWER32(file->pos), UPPER32(file->pos), answer);
+		    LOWER32(pos), UPPER32(pos), answer);
 	} else {
 		rc = async_data_write_forward_4_1(exch, VFS_OUT_WRITE,
 		    file->node->service_id, file->node->index,
-		    LOWER32(file->pos), UPPER32(file->pos), answer);
+		    LOWER32(pos), UPPER32(pos), answer);
 	}
 
@@ -765,5 +349,5 @@
 }
 
-static int rdwr_ipc_internal(async_exch_t *exch, vfs_file_t *file,
+static int rdwr_ipc_internal(async_exch_t *exch, vfs_file_t *file, aoff64_t pos,
     ipc_call_t *answer, bool read, void *data)
 {
@@ -774,6 +358,6 @@
 	
 	aid_t msg = async_send_fast(exch, read ? VFS_OUT_READ : VFS_OUT_WRITE,
-	    file->node->service_id, file->node->index, LOWER32(file->pos),
-	    UPPER32(file->pos), answer);
+	    file->node->service_id, file->node->index, LOWER32(pos),
+	    UPPER32(pos), answer);
 	if (msg == 0)
 		return EINVAL;
@@ -793,5 +377,6 @@
 }
 
-static int vfs_rdwr(int fd, bool read, rdwr_ipc_cb_t ipc_cb, void *ipc_cb_data)
+static int vfs_rdwr(int fd, aoff64_t pos, bool read, rdwr_ipc_cb_t ipc_cb,
+    void *ipc_cb_data)
 {
 	/*
@@ -808,14 +393,16 @@
 	vfs_file_t *file = vfs_file_get(fd);
 	if (!file)
-		return ENOENT;
-	
-	/*
-	 * Lock the open file structure so that no other thread can manipulate
-	 * the same open file at a time.
-	 */
-	fibril_mutex_lock(&file->lock);
+		return EBADF;
+	
+	if ((read && !file->open_read) || (!read && !file->open_write)) {
+		vfs_file_put(file);
+		return EINVAL;
+	}
 	
 	vfs_info_t *fs_info = fs_handle_to_info(file->node->fs_handle);
 	assert(fs_info);
+	
+	bool rlock = read ||
+	    (fs_info->concurrent_read_write && fs_info->write_retains_size);
 	
 	/*
@@ -824,6 +411,5 @@
 	 * write implementation does not modify the file size.
 	 */
-	if ((read) ||
-	    ((fs_info->concurrent_read_write) && (fs_info->write_retains_size)))
+	if (rlock)
 		fibril_rwlock_read_lock(&file->node->contents_rwlock);
 	else
@@ -835,5 +421,17 @@
 		 * while we are in readdir().
 		 */
-		assert(read);
+		
+		if (!read) {
+			if (rlock) {
+				fibril_rwlock_read_unlock(
+				    &file->node->contents_rwlock);
+			} else {
+				fibril_rwlock_write_unlock(
+				    &file->node->contents_rwlock);
+			}
+			vfs_file_put(file);
+			return EINVAL;
+		}
+		
 		fibril_rwlock_read_lock(&namespace_rwlock);
 	}
@@ -842,5 +440,5 @@
 	
 	if (!read && file->append)
-		file->pos = file->node->size;
+		pos = file->node->size;
 	
 	/*
@@ -848,9 +446,7 @@
 	 */
 	ipc_call_t answer;
-	int rc = ipc_cb(fs_exch, file, &answer, read, ipc_cb_data);
+	int rc = ipc_cb(fs_exch, file, pos, &answer, read, ipc_cb_data);
 	
 	vfs_exchange_release(fs_exch);
-	
-	size_t bytes = IPC_GET_ARG1(answer);
 	
 	if (file->node->type == VFS_NODE_DIRECTORY)
@@ -858,133 +454,207 @@
 	
 	/* Unlock the VFS node. */
-	if ((read) ||
-	    ((fs_info->concurrent_read_write) && (fs_info->write_retains_size)))
+	if (rlock) {
 		fibril_rwlock_read_unlock(&file->node->contents_rwlock);
-	else {
+	} else {
 		/* Update the cached version of node's size. */
-		if (rc == EOK)
+		if (rc == EOK) {
 			file->node->size = MERGE_LOUP32(IPC_GET_ARG2(answer),
 			    IPC_GET_ARG3(answer));
+		}
 		fibril_rwlock_write_unlock(&file->node->contents_rwlock);
 	}
 	
-	/* Update the position pointer and unlock the open file. */
+	vfs_file_put(file);	
+
+	return rc;
+}
+
+int vfs_rdwr_internal(int fd, aoff64_t pos, bool read, rdwr_io_chunk_t *chunk)
+{
+	return vfs_rdwr(fd, pos, read, rdwr_ipc_internal, chunk);
+}
+
+int vfs_op_read(int fd, aoff64_t pos, size_t *out_bytes)
+{
+	return vfs_rdwr(fd, pos, true, rdwr_ipc_client, out_bytes);
+}
+
+int vfs_op_rename(int basefd, char *old, char *new)
+{
+	vfs_file_t *base_file = vfs_file_get(basefd);
+	if (!base_file)
+		return EBADF;
+
+	vfs_node_t *base = base_file->node;
+	vfs_node_addref(base);
+	vfs_file_put(base_file);
+	
+	vfs_lookup_res_t base_lr;
+	vfs_lookup_res_t old_lr;
+	vfs_lookup_res_t new_lr_orig;
+	bool orig_unlinked = false;
+	
+	int rc;
+	
+	size_t shared = shared_path(old, new);
+	
+	/* Do not allow one path to be a prefix of the other. */
+	if (old[shared] == 0 || new[shared] == 0) {
+		vfs_node_put(base);
+		return EINVAL;
+	}
+	assert(old[shared] == '/');
+	assert(new[shared] == '/');
+	
+	fibril_rwlock_write_lock(&namespace_rwlock);
+	
+	/* Resolve the shared portion of the path first. */
+	if (shared != 0) {
+		old[shared] = 0;
+		rc = vfs_lookup_internal(base, old, L_DIRECTORY, &base_lr);
+		if (rc != EOK) {
+			vfs_node_put(base);
+			fibril_rwlock_write_unlock(&namespace_rwlock);
+			return rc;
+		}
+		
+		vfs_node_put(base);
+		base = vfs_node_get(&base_lr);
+		if (!base) {
+			fibril_rwlock_write_unlock(&namespace_rwlock);
+			return ENOMEM;
+		}
+		old[shared] = '/';
+		old += shared;
+		new += shared;
+	}
+
+	rc = vfs_lookup_internal(base, old, L_DISABLE_MOUNTS, &old_lr);
+	if (rc != EOK) {
+		vfs_node_put(base);
+		fibril_rwlock_write_unlock(&namespace_rwlock);
+		return rc;
+	}
+		
+	rc = vfs_lookup_internal(base, new, L_UNLINK | L_DISABLE_MOUNTS,
+	    &new_lr_orig);
+	if (rc == EOK) {
+		orig_unlinked = true;
+	} else if (rc != ENOENT) {
+		vfs_node_put(base);
+		fibril_rwlock_write_unlock(&namespace_rwlock);
+		return rc;
+	}
+
+	rc = vfs_link_internal(base, new, &old_lr.triplet);
+	if (rc != EOK) {
+		vfs_link_internal(base, old, &old_lr.triplet);
+		if (orig_unlinked)
+			vfs_link_internal(base, new, &new_lr_orig.triplet);
+		vfs_node_put(base);
+		fibril_rwlock_write_unlock(&namespace_rwlock);
+		return rc;
+	}
+
+	rc = vfs_lookup_internal(base, old, L_UNLINK | L_DISABLE_MOUNTS,
+	    &old_lr);
+	if (rc != EOK) {
+		if (orig_unlinked)
+			vfs_link_internal(base, new, &new_lr_orig.triplet);
+		vfs_node_put(base);
+		fibril_rwlock_write_unlock(&namespace_rwlock);
+		return rc;
+	}
+	
+	/* If the node is not held by anyone, try to destroy it. */
+	if (orig_unlinked) {
+		vfs_node_t *node = vfs_node_peek(&new_lr_orig);
+		if (!node)
+			out_destroy(&new_lr_orig.triplet);
+		else
+			vfs_node_put(node);
+	}
+	
+	vfs_node_put(base);
+	fibril_rwlock_write_unlock(&namespace_rwlock);
+	return EOK;
+}
+
+int vfs_op_resize(int fd, int64_t size)
+{
+	vfs_file_t *file = vfs_file_get(fd);
+	if (!file)
+		return EBADF;
+
+	fibril_rwlock_write_lock(&file->node->contents_rwlock);
+	
+	int rc = vfs_truncate_internal(file->node->fs_handle,
+	    file->node->service_id, file->node->index, size);
 	if (rc == EOK)
-		file->pos += bytes;
-	fibril_mutex_unlock(&file->lock);
-	vfs_file_put(file);	
-
+		file->node->size = size;
+	
+	fibril_rwlock_write_unlock(&file->node->contents_rwlock);
+	vfs_file_put(file);
 	return rc;
 }
-	
-static void vfs_rdwr_client(ipc_callid_t rid, ipc_call_t *request, bool read)
-{
-	size_t bytes = 0;	
-	int rc = vfs_rdwr(IPC_GET_ARG1(*request), read, rdwr_ipc_client,
-	    &bytes);
-	async_answer_1(rid, rc, bytes);
-}
-
-int vfs_rdwr_internal(int fd, bool read, rdwr_io_chunk_t *chunk)
-{
-	return vfs_rdwr(fd, read, rdwr_ipc_internal, chunk);
-}
-
-void vfs_read(ipc_callid_t rid, ipc_call_t *request)
-{
-	vfs_rdwr_client(rid, request, true);
-}
-
-void vfs_write(ipc_callid_t rid, ipc_call_t *request)
-{
-	vfs_rdwr_client(rid, request, false);
-}
-
-void vfs_seek(ipc_callid_t rid, ipc_call_t *request)
-{
-	int fd = (int) IPC_GET_ARG1(*request);
-	off64_t off = (off64_t) MERGE_LOUP32(IPC_GET_ARG2(*request),
-	    IPC_GET_ARG3(*request));
-	int whence = (int) IPC_GET_ARG4(*request);
-	
-	/* Lookup the file structure corresponding to the file descriptor. */
+
+int vfs_op_stat(int fd)
+{
 	vfs_file_t *file = vfs_file_get(fd);
-	if (!file) {
-		async_answer_0(rid, ENOENT);
-		return;
-	}
-	
-	fibril_mutex_lock(&file->lock);
-	
-	off64_t newoff;
-	switch (whence) {
-	case SEEK_SET:
-		if (off >= 0) {
-			file->pos = (aoff64_t) off;
-			fibril_mutex_unlock(&file->lock);
-			vfs_file_put(file);
-			async_answer_1(rid, EOK, off);
-			return;
-		}
-		break;
-	case SEEK_CUR:
-		if ((off >= 0) && (file->pos + off < file->pos)) {
-			fibril_mutex_unlock(&file->lock);
-			vfs_file_put(file);
-			async_answer_0(rid, EOVERFLOW);
-			return;
-		}
-		
-		if ((off < 0) && (file->pos < (aoff64_t) -off)) {
-			fibril_mutex_unlock(&file->lock);
-			vfs_file_put(file);
-			async_answer_0(rid, EOVERFLOW);
-			return;
-		}
-		
-		file->pos += off;
-		newoff = (file->pos > OFF64_MAX) ? OFF64_MAX : file->pos;
-		
-		fibril_mutex_unlock(&file->lock);
-		vfs_file_put(file);
-		async_answer_2(rid, EOK, LOWER32(newoff),
-		    UPPER32(newoff));
-		return;
-	case SEEK_END:
-		fibril_rwlock_read_lock(&file->node->contents_rwlock);
-		aoff64_t size = file->node->size;
-		
-		if ((off >= 0) && (size + off < size)) {
-			fibril_rwlock_read_unlock(&file->node->contents_rwlock);
-			fibril_mutex_unlock(&file->lock);
-			vfs_file_put(file);
-			async_answer_0(rid, EOVERFLOW);
-			return;
-		}
-		
-		if ((off < 0) && (size < (aoff64_t) -off)) {
-			fibril_rwlock_read_unlock(&file->node->contents_rwlock);
-			fibril_mutex_unlock(&file->lock);
-			vfs_file_put(file);
-			async_answer_0(rid, EOVERFLOW);
-			return;
-		}
-		
-		file->pos = size + off;
-		newoff = (file->pos > OFF64_MAX) ?  OFF64_MAX : file->pos;
-		
-		fibril_rwlock_read_unlock(&file->node->contents_rwlock);
-		fibril_mutex_unlock(&file->lock);
-		vfs_file_put(file);
-		async_answer_2(rid, EOK, LOWER32(newoff), UPPER32(newoff));
-		return;
-	}
-	
-	fibril_mutex_unlock(&file->lock);
+	if (!file)
+		return EBADF;
+
+	vfs_node_t *node = file->node;
+
+	async_exch_t *exch = vfs_exchange_grab(node->fs_handle);
+	int rc = async_data_read_forward_fast(exch, VFS_OUT_STAT,
+	    node->service_id, node->index, true, 0, NULL);
+	vfs_exchange_release(exch);
+	
 	vfs_file_put(file);
-	async_answer_0(rid, EINVAL);
-}
-
-int vfs_truncate_internal(fs_handle_t fs_handle, service_id_t service_id,
+	return rc;
+}
+
+int vfs_op_statfs(int fd)
+{
+	vfs_file_t *file = vfs_file_get(fd);
+	if (!file)
+		return EBADF;
+
+	vfs_node_t *node = file->node;
+
+	async_exch_t *exch = vfs_exchange_grab(node->fs_handle);
+	int rc = async_data_read_forward_fast(exch, VFS_OUT_STATFS,
+	    node->service_id, node->index, false, 0, NULL);
+	vfs_exchange_release(exch);
+
+	vfs_file_put(file);
+	return rc;
+}
+
+int vfs_op_sync(int fd)
+{
+	vfs_file_t *file = vfs_file_get(fd);
+	if (!file)
+		return EBADF;
+	
+	async_exch_t *fs_exch = vfs_exchange_grab(file->node->fs_handle);
+	
+	aid_t msg;
+	ipc_call_t answer;
+	msg = async_send_2(fs_exch, VFS_OUT_SYNC, file->node->service_id,
+	    file->node->index, &answer);
+	
+	vfs_exchange_release(fs_exch);
+	
+	sysarg_t rc;
+	async_wait_for(msg, &rc);
+	
+	vfs_file_put(file);
+	return rc;
+	
+}
+
+static int vfs_truncate_internal(fs_handle_t fs_handle, service_id_t service_id,
     fs_index_t index, aoff64_t size)
 {
@@ -998,526 +668,222 @@
 }
 
-void vfs_truncate(ipc_callid_t rid, ipc_call_t *request)
-{
-	int fd = IPC_GET_ARG1(*request);
-	aoff64_t size = (aoff64_t) MERGE_LOUP32(IPC_GET_ARG2(*request),
-	    IPC_GET_ARG3(*request));
-	int rc;
-
-	vfs_file_t *file = vfs_file_get(fd);
-	if (!file) {
-		async_answer_0(rid, ENOENT);
-		return;
-	}
-	fibril_mutex_lock(&file->lock);
-
-	fibril_rwlock_write_lock(&file->node->contents_rwlock);
-	rc = vfs_truncate_internal(file->node->fs_handle,
-	    file->node->service_id, file->node->index, size);
-	if (rc == EOK)
-		file->node->size = size;
-	fibril_rwlock_write_unlock(&file->node->contents_rwlock);
-
-	fibril_mutex_unlock(&file->lock);
-	vfs_file_put(file);
-	async_answer_0(rid, (sysarg_t)rc);
-}
-
-void vfs_fstat(ipc_callid_t rid, ipc_call_t *request)
-{
-	int fd = IPC_GET_ARG1(*request);
-	sysarg_t rc;
-
-	vfs_file_t *file = vfs_file_get(fd);
-	if (!file) {
-		async_answer_0(rid, ENOENT);
-		return;
-	}
-
-	ipc_callid_t callid;
-	if (!async_data_read_receive(&callid, NULL)) {
-		vfs_file_put(file);
-		async_answer_0(callid, EINVAL);
-		async_answer_0(rid, EINVAL);
-		return;
-	}
-
-	fibril_mutex_lock(&file->lock);
-
-	async_exch_t *exch = vfs_exchange_grab(file->node->fs_handle);
-	
-	aid_t msg;
-	msg = async_send_3(exch, VFS_OUT_STAT, file->node->service_id,
-	    file->node->index, true, NULL);
-	async_forward_fast(callid, exch, 0, 0, 0, IPC_FF_ROUTE_FROM_ME);
-	
+int vfs_op_unlink(int parentfd, int expectfd, char *path)
+{
+	int rc = EOK;
+	vfs_file_t *parent = NULL;
+	vfs_file_t *expect = NULL;
+	
+	if (parentfd == expectfd)
+		return EINVAL;
+	
+	fibril_rwlock_write_lock(&namespace_rwlock);
+	
+	/* 
+	 * Files are retrieved in order of file descriptors, to prevent
+	 * deadlock.
+	 */
+	if (parentfd < expectfd) {
+		parent = vfs_file_get(parentfd);
+		if (!parent) {
+			rc = EBADF;
+			goto exit;
+		}
+	}
+	
+	if (expectfd >= 0) {
+		expect = vfs_file_get(expectfd);
+		if (!expect) {
+			rc = EBADF;
+			goto exit;
+		}
+	}
+	
+	if (parentfd > expectfd) {
+		parent = vfs_file_get(parentfd);
+		if (!parent) {
+			rc = EBADF;
+			goto exit;
+		}
+	}
+	
+	assert(parent != NULL);
+	
+	if (expectfd >= 0) {
+		vfs_lookup_res_t lr;
+		rc = vfs_lookup_internal(parent->node, path, 0, &lr);
+		if (rc != EOK)
+			goto exit;
+		
+		vfs_node_t *found_node = vfs_node_peek(&lr);
+		vfs_node_put(found_node);
+		if (expect->node != found_node) {
+			rc = ENOENT;
+			goto exit;
+		}
+		
+		vfs_file_put(expect);
+		expect = NULL;
+	}
+	
+	vfs_lookup_res_t lr;
+	rc = vfs_lookup_internal(parent->node, path, L_UNLINK, &lr);
+	if (rc != EOK)
+		goto exit;
+
+	/* If the node is not held by anyone, try to destroy it. */
+	vfs_node_t *node = vfs_node_peek(&lr);
+	if (!node)
+		out_destroy(&lr.triplet);
+	else
+		vfs_node_put(node);
+
+exit:
+	if (path)
+		free(path);
+	if (parent)
+		vfs_file_put(parent);
+	if (expect)
+		vfs_file_put(expect);
+	fibril_rwlock_write_unlock(&namespace_rwlock);
+	return rc;
+}
+
+int vfs_op_unmount(int mpfd)
+{
+	vfs_file_t *mp = vfs_file_get(mpfd);
+	if (mp == NULL)
+		return EBADF;
+	
+	if (mp->node->mount == NULL) {
+		vfs_file_put(mp);
+		return ENOENT;
+	}
+	
+	fibril_rwlock_write_lock(&namespace_rwlock);
+	
+	/*
+	 * Count the total number of references for the mounted file system. We
+	 * are expecting at least one, which is held by the mount point.
+	 * If we find more, it means that
+	 * the file system cannot be gracefully unmounted at the moment because
+	 * someone is working with it.
+	 */
+	if (vfs_nodes_refcount_sum_get(mp->node->mount->fs_handle,
+	    mp->node->mount->service_id) != 1) {
+		vfs_file_put(mp);
+		fibril_rwlock_write_unlock(&namespace_rwlock);
+		return EBUSY;
+	}
+	
+	async_exch_t *exch = vfs_exchange_grab(mp->node->mount->fs_handle);
+	int rc = async_req_1_0(exch, VFS_OUT_UNMOUNTED,
+	    mp->node->mount->service_id);
 	vfs_exchange_release(exch);
 	
-	async_wait_for(msg, &rc);
-	
-	fibril_mutex_unlock(&file->lock);
-	vfs_file_put(file);
-	async_answer_0(rid, rc);
-}
-
-void vfs_stat(ipc_callid_t rid, ipc_call_t *request)
-{
-	char *path;
-	int rc = async_data_write_accept((void **) &path, true, 0, 0, 0, NULL);
 	if (rc != EOK) {
-		async_answer_0(rid, rc);
-		return;
-	}
-	
-	ipc_callid_t callid;
-	if (!async_data_read_receive(&callid, NULL)) {
-		free(path);
-		async_answer_0(callid, EINVAL);
-		async_answer_0(rid, EINVAL);
-		return;
-	}
-
+		vfs_file_put(mp);
+		fibril_rwlock_write_unlock(&namespace_rwlock);
+		return rc;
+	}
+	
+	vfs_node_forget(mp->node->mount);
+	vfs_node_put(mp->node);
+	mp->node->mount = NULL;
+	
+	fibril_rwlock_write_unlock(&namespace_rwlock);
+	
+	vfs_file_put(mp);
+	return EOK;
+}
+
+int vfs_op_wait_handle(bool high_fd)
+{
+	return vfs_wait_handle_internal(high_fd);
+}
+
+static inline bool walk_flags_valid(int flags)
+{
+	if ((flags & ~WALK_ALL_FLAGS) != 0)
+		return false;
+	if ((flags & WALK_MAY_CREATE) && (flags & WALK_MUST_CREATE))
+		return false;
+	if ((flags & WALK_REGULAR) && (flags & WALK_DIRECTORY))
+		return false;
+	if ((flags & WALK_MAY_CREATE) || (flags & WALK_MUST_CREATE)) {
+		if (!(flags & WALK_DIRECTORY) && !(flags & WALK_REGULAR))
+			return false;
+	}
+	return true;
+}
+
+static inline int walk_lookup_flags(int flags)
+{
+	int lflags = 0;
+	if ((flags & WALK_MAY_CREATE) || (flags & WALK_MUST_CREATE))
+		lflags |= L_CREATE;
+	if (flags & WALK_MUST_CREATE)
+		lflags |= L_EXCLUSIVE;
+	if (flags & WALK_REGULAR)
+		lflags |= L_FILE;
+	if (flags & WALK_DIRECTORY)
+		lflags |= L_DIRECTORY;
+	if (flags & WALK_MOUNT_POINT)
+		lflags |= L_MP;
+	return lflags;
+}
+
+int vfs_op_walk(int parentfd, int flags, char *path, int *out_fd)
+{
+	if (!walk_flags_valid(flags))
+		return EINVAL;
+	
+	vfs_file_t *parent = vfs_file_get(parentfd);
+	if (!parent)
+		return EBADF;
+	
+	fibril_rwlock_read_lock(&namespace_rwlock);
+	
 	vfs_lookup_res_t lr;
-	fibril_rwlock_read_lock(&namespace_rwlock);
-	rc = vfs_lookup_internal(path, L_NONE, &lr, NULL);
-	free(path);
+	int rc = vfs_lookup_internal(parent->node, path,
+	    walk_lookup_flags(flags), &lr);
 	if (rc != EOK) {
 		fibril_rwlock_read_unlock(&namespace_rwlock);
-		async_answer_0(callid, rc);
-		async_answer_0(rid, rc);
-		return;
-	}
+		vfs_file_put(parent);
+		return rc;
+	}
+	
 	vfs_node_t *node = vfs_node_get(&lr);
 	if (!node) {
 		fibril_rwlock_read_unlock(&namespace_rwlock);
-		async_answer_0(callid, ENOMEM);
-		async_answer_0(rid, ENOMEM);
-		return;
-	}
-
+		vfs_file_put(parent);
+		return ENOMEM;
+	}
+	
+	vfs_file_t *file;
+	int fd = vfs_fd_alloc(&file, false);
+	if (fd < 0) {
+		vfs_node_put(node);
+		vfs_file_put(parent);
+		return fd;
+	}
+	assert(file != NULL);
+	
+	file->node = node;
+	file->permissions = parent->permissions;
+	file->open_read = false;
+	file->open_write = false;
+	
+	vfs_file_put(file);
+	vfs_file_put(parent);
+	
 	fibril_rwlock_read_unlock(&namespace_rwlock);
 
-	async_exch_t *exch = vfs_exchange_grab(node->fs_handle);
-	
-	aid_t msg;
-	msg = async_send_3(exch, VFS_OUT_STAT, node->service_id,
-	    node->index, false, NULL);
-	async_forward_fast(callid, exch, 0, 0, 0, IPC_FF_ROUTE_FROM_ME);
-	
-	vfs_exchange_release(exch);
-	
-	sysarg_t rv;
-	async_wait_for(msg, &rv);
-
-	async_answer_0(rid, rv);
-
-	vfs_node_put(node);
-}
-
-void vfs_mkdir(ipc_callid_t rid, ipc_call_t *request)
-{
-	int mode = IPC_GET_ARG1(*request);
-	
-	char *path;
-	int rc = async_data_write_accept((void **) &path, true, 0, 0, 0, NULL);
-	if (rc != EOK) {
-		async_answer_0(rid, rc);
-		return;
-	}
-	
-	/* Ignore mode for now. */
-	(void) mode;
-	
-	fibril_rwlock_write_lock(&namespace_rwlock);
-	int lflag = L_DIRECTORY | L_CREATE | L_EXCLUSIVE;
-	rc = vfs_lookup_internal(path, lflag, NULL, NULL);
-	fibril_rwlock_write_unlock(&namespace_rwlock);
-	free(path);
-	async_answer_0(rid, rc);
-}
-
-void vfs_unlink(ipc_callid_t rid, ipc_call_t *request)
-{
-	int lflag = IPC_GET_ARG1(*request);
-	
-	char *path;
-	int rc = async_data_write_accept((void **) &path, true, 0, 0, 0, NULL);
-	if (rc != EOK) {
-		async_answer_0(rid, rc);
-		return;
-	}
-	
-	fibril_rwlock_write_lock(&namespace_rwlock);
-	lflag &= L_DIRECTORY;	/* sanitize lflag */
-	vfs_lookup_res_t lr;
-	rc = vfs_lookup_internal(path, lflag | L_UNLINK, &lr, NULL);
-	free(path);
-	if (rc != EOK) {
-		fibril_rwlock_write_unlock(&namespace_rwlock);
-		async_answer_0(rid, rc);
-		return;
-	}
-
-	/*
-	 * The name has already been unlinked by vfs_lookup_internal().
-	 * We have to get and put the VFS node to ensure that it is
-	 * VFS_OUT_DESTROY'ed after the last reference to it is dropped.
-	 */
-	vfs_node_t *node = vfs_node_get(&lr);
-	fibril_mutex_lock(&nodes_mutex);
-	node->lnkcnt--;
-	fibril_mutex_unlock(&nodes_mutex);
-	fibril_rwlock_write_unlock(&namespace_rwlock);
-	vfs_node_put(node);
-	async_answer_0(rid, EOK);
-}
-
-void vfs_rename(ipc_callid_t rid, ipc_call_t *request)
-{
-	/* Retrieve the old path. */
-	char *old;
-	int rc = async_data_write_accept((void **) &old, true, 0, 0, 0, NULL);
-	if (rc != EOK) {
-		async_answer_0(rid, rc);
-		return;
-	}
-	
-	/* Retrieve the new path. */
-	char *new;
-	rc = async_data_write_accept((void **) &new, true, 0, 0, 0, NULL);
-	if (rc != EOK) {
-		free(old);
-		async_answer_0(rid, rc);
-		return;
-	}
-	
-	size_t olen;
-	size_t nlen;
-	char *oldc = canonify(old, &olen);
-	char *newc = canonify(new, &nlen);
-	
-	if ((!oldc) || (!newc)) {
-		async_answer_0(rid, EINVAL);
-		free(old);
-		free(new);
-		return;
-	}
-	
-	oldc[olen] = '\0';
-	newc[nlen] = '\0';
-	
-	if ((!str_lcmp(newc, oldc, str_length(oldc))) &&
-	    ((newc[str_length(oldc)] == '/') ||
-	    (str_length(oldc) == 1) ||
-	    (str_length(oldc) == str_length(newc)))) {
-	    	/*
-		 * oldc is a prefix of newc and either
-		 * - newc continues with a / where oldc ends, or
-		 * - oldc was / itself, or
-		 * - oldc and newc are equal.
-		 */
-		async_answer_0(rid, EINVAL);
-		free(old);
-		free(new);
-		return;
-	}
-	
-	vfs_lookup_res_t old_lr;
-	vfs_lookup_res_t new_lr;
-	vfs_lookup_res_t new_par_lr;
-	fibril_rwlock_write_lock(&namespace_rwlock);
-	
-	/* Lookup the node belonging to the old file name. */
-	rc = vfs_lookup_internal(oldc, L_NONE, &old_lr, NULL);
-	if (rc != EOK) {
-		fibril_rwlock_write_unlock(&namespace_rwlock);
-		async_answer_0(rid, rc);
-		free(old);
-		free(new);
-		return;
-	}
-	
-	vfs_node_t *old_node = vfs_node_get(&old_lr);
-	if (!old_node) {
-		fibril_rwlock_write_unlock(&namespace_rwlock);
-		async_answer_0(rid, ENOMEM);
-		free(old);
-		free(new);
-		return;
-	}
-	
-	/* Determine the path to the parent of the node with the new name. */
-	char *parentc = str_dup(newc);
-	if (!parentc) {
-		fibril_rwlock_write_unlock(&namespace_rwlock);
-		vfs_node_put(old_node);
-		async_answer_0(rid, rc);
-		free(old);
-		free(new);
-		return;
-	}
-	
-	char *lastsl = str_rchr(parentc + 1, '/');
-	if (lastsl)
-		*lastsl = '\0';
-	else
-		parentc[1] = '\0';
-	
-	/* Lookup parent of the new file name. */
-	rc = vfs_lookup_internal(parentc, L_NONE, &new_par_lr, NULL);
-	free(parentc);	/* not needed anymore */
-	if (rc != EOK) {
-		fibril_rwlock_write_unlock(&namespace_rwlock);
-		vfs_node_put(old_node);
-		async_answer_0(rid, rc);
-		free(old);
-		free(new);
-		return;
-	}
-	
-	/* Check whether linking to the same file system instance. */
-	if ((old_node->fs_handle != new_par_lr.triplet.fs_handle) ||
-	    (old_node->service_id != new_par_lr.triplet.service_id)) {
-		fibril_rwlock_write_unlock(&namespace_rwlock);
-		vfs_node_put(old_node);
-		async_answer_0(rid, EXDEV);	/* different file systems */
-		free(old);
-		free(new);
-		return;
-	}
-	
-	/* Destroy the old link for the new name. */
-	vfs_node_t *new_node = NULL;
-	rc = vfs_lookup_internal(newc, L_UNLINK, &new_lr, NULL);
-	
-	switch (rc) {
-	case ENOENT:
-		/* simply not in our way */
-		break;
-	case EOK:
-		new_node = vfs_node_get(&new_lr);
-		if (!new_node) {
-			fibril_rwlock_write_unlock(&namespace_rwlock);
-			vfs_node_put(old_node);
-			async_answer_0(rid, ENOMEM);
-			free(old);
-			free(new);
-			return;
-		}
-		fibril_mutex_lock(&nodes_mutex);
-		new_node->lnkcnt--;
-		fibril_mutex_unlock(&nodes_mutex);
-		break;
-	default:
-		fibril_rwlock_write_unlock(&namespace_rwlock);
-		vfs_node_put(old_node);
-		async_answer_0(rid, ENOTEMPTY);
-		free(old);
-		free(new);
-		return;
-	}
-	
-	/* Create the new link for the new name. */
-	rc = vfs_lookup_internal(newc, L_LINK, NULL, NULL, old_node->index);
-	if (rc != EOK) {
-		fibril_rwlock_write_unlock(&namespace_rwlock);
-		vfs_node_put(old_node);
-		if (new_node)
-			vfs_node_put(new_node);
-		async_answer_0(rid, rc);
-		free(old);
-		free(new);
-		return;
-	}
-	
-	fibril_mutex_lock(&nodes_mutex);
-	old_node->lnkcnt++;
-	fibril_mutex_unlock(&nodes_mutex);
-	
-	/* Destroy the link for the old name. */
-	rc = vfs_lookup_internal(oldc, L_UNLINK, NULL, NULL);
-	if (rc != EOK) {
-		fibril_rwlock_write_unlock(&namespace_rwlock);
-		vfs_node_put(old_node);
-		if (new_node)
-			vfs_node_put(new_node);
-		async_answer_0(rid, rc);
-		free(old);
-		free(new);
-		return;
-	}
-	
-	fibril_mutex_lock(&nodes_mutex);
-	old_node->lnkcnt--;
-	fibril_mutex_unlock(&nodes_mutex);
-	fibril_rwlock_write_unlock(&namespace_rwlock);
-	vfs_node_put(old_node);
-	
-	if (new_node)
-		vfs_node_put(new_node);
-	
-	free(old);
-	free(new);
-	async_answer_0(rid, EOK);
-}
-
-void vfs_dup(ipc_callid_t rid, ipc_call_t *request)
-{
-	int oldfd = IPC_GET_ARG1(*request);
-	int newfd = IPC_GET_ARG2(*request);
-	
-	/* If the file descriptors are the same, do nothing. */
-	if (oldfd == newfd) {
-		async_answer_1(rid, EOK, newfd);
-		return;
-	}
-	
-	/* Lookup the file structure corresponding to oldfd. */
-	vfs_file_t *oldfile = vfs_file_get(oldfd);
-	if (!oldfile) {
-		async_answer_0(rid, EBADF);
-		return;
-	}
-	
-	/*
-	 * Lock the open file structure so that no other thread can manipulate
-	 * the same open file at a time.
-	 */
-	fibril_mutex_lock(&oldfile->lock);
-	
-	/* Make sure newfd is closed. */
-	(void) vfs_fd_free(newfd);
-	
-	/* Assign the old file to newfd. */
-	int ret = vfs_fd_assign(oldfile, newfd);
-	fibril_mutex_unlock(&oldfile->lock);
-	vfs_file_put(oldfile);
-	
-	if (ret != EOK)
-		async_answer_0(rid, ret);
-	else
-		async_answer_1(rid, EOK, newfd);
-}
-
-void vfs_wait_handle(ipc_callid_t rid, ipc_call_t *request)
-{
-	int fd = vfs_wait_handle_internal();
-	async_answer_1(rid, EOK, fd);
-}
-
-void vfs_get_mtab(ipc_callid_t rid, ipc_call_t *request)
-{
-	ipc_callid_t callid;
-	ipc_call_t data;
-	sysarg_t rc = EOK;
-	size_t len;
-
-	fibril_mutex_lock(&mtab_list_lock);
-
-	/* Send to the caller the number of mounted filesystems */
-	callid = async_get_call(&data);
-	if (IPC_GET_IMETHOD(data) != VFS_IN_PING) {
-		rc = ENOTSUP;
-		async_answer_0(callid, rc);
-		goto exit;
-	}
-	async_answer_1(callid, EOK, mtab_size);
-
-	list_foreach(mtab_list, link, mtab_ent_t, mtab_ent) {
-		rc = ENOTSUP;
-
-		if (!async_data_read_receive(&callid, &len)) {
-			async_answer_0(callid, rc);
-			goto exit;
-		}
-
-		(void) async_data_read_finalize(callid, mtab_ent->mp,
-		    str_size(mtab_ent->mp));
-
-		if (!async_data_read_receive(&callid, &len)) {
-			async_answer_0(callid, rc);
-			goto exit;
-		}
-
-		(void) async_data_read_finalize(callid, mtab_ent->opts,
-		    str_size(mtab_ent->opts));
-
-		if (!async_data_read_receive(&callid, &len)) {
-			async_answer_0(callid, rc);
-			goto exit;
-		}
-
-		(void) async_data_read_finalize(callid, mtab_ent->fs_name,
-		    str_size(mtab_ent->fs_name));
-
-		callid = async_get_call(&data);
-
-		if (IPC_GET_IMETHOD(data) != VFS_IN_PING) {
-			async_answer_0(callid, rc);
-			goto exit;
-		}
-
-		rc = EOK;
-		async_answer_2(callid, rc, mtab_ent->instance,
-		    mtab_ent->service_id);
-	}
-
-exit:
-	fibril_mutex_unlock(&mtab_list_lock);
-	async_answer_0(rid, rc);
-}
-
-void vfs_statfs(ipc_callid_t rid, ipc_call_t *request)
-{
-	char *path;
-	int rc = async_data_write_accept((void **) &path, true, 0, 0, 0, NULL);
-	if (rc != EOK) {
-		async_answer_0(rid, rc);
-		return;
-	}
-	
-	ipc_callid_t callid;
-	if (!async_data_read_receive(&callid, NULL)) {
-		free(path);
-		async_answer_0(callid, EINVAL);
-		async_answer_0(rid, EINVAL);
-		return;
-	}
-
-	vfs_lookup_res_t lr;
-	fibril_rwlock_read_lock(&namespace_rwlock);
-	rc = vfs_lookup_internal(path, L_NONE, &lr, NULL);
-	free(path);
-	if (rc != EOK) {
-		fibril_rwlock_read_unlock(&namespace_rwlock);
-		async_answer_0(callid, rc);
-		async_answer_0(rid, rc);
-		return;
-	}
-	vfs_node_t *node = vfs_node_get(&lr);
-	if (!node) {
-		fibril_rwlock_read_unlock(&namespace_rwlock);
-		async_answer_0(callid, ENOMEM);
-		async_answer_0(rid, ENOMEM);
-		return;
-	}
-
-	fibril_rwlock_read_unlock(&namespace_rwlock);
-
-	async_exch_t *exch = vfs_exchange_grab(node->fs_handle);
-	
-	aid_t msg;
-	msg = async_send_3(exch, VFS_OUT_STATFS, node->service_id,
-	    node->index, false, NULL);
-	async_forward_fast(callid, exch, 0, 0, 0, IPC_FF_ROUTE_FROM_ME);
-	
-	vfs_exchange_release(exch);
-	
-	sysarg_t rv;
-	async_wait_for(msg, &rv);
-
-	async_answer_0(rid, rv);
-
-	vfs_node_put(node);
+	*out_fd = fd;
+	return EOK;
+}
+
+int vfs_op_write(int fd, aoff64_t pos, size_t *out_bytes)
+{
+	return vfs_rdwr(fd, pos, false, rdwr_ipc_client, out_bytes);
 }
 
Index: uspace/srv/vfs/vfs_pager.c
===================================================================
--- uspace/srv/vfs/vfs_pager.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/srv/vfs/vfs_pager.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -50,10 +50,4 @@
 	int rc;
 
-	vfs_file_t *file = vfs_file_get(fd);
-	if (!file) {
-		async_answer_0(rid, ENOENT);
-		return;
-	}
-
 	page = as_area_create(AS_AREA_ANY, page_size,
 	    AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE,
@@ -61,5 +55,4 @@
 
 	if (page == AS_MAP_FAILED) {
-		vfs_file_put(file);
 		async_answer_0(rid, ENOMEM);
 		return;
@@ -71,11 +64,8 @@
 	};
 
-	fibril_mutex_lock(&file->lock);
-	file->pos = offset;
-	fibril_mutex_unlock(&file->lock);
-
 	size_t total = 0;
+	aoff64_t pos = offset;
 	do {
-		rc = vfs_rdwr_internal(fd, true, &chunk);
+		rc = vfs_rdwr_internal(fd, pos, true, &chunk);
 		if (rc != EOK)
 			break;
@@ -83,9 +73,8 @@
 			break;
 		total += chunk.size;
+		pos += chunk.size;
 		chunk.buffer += chunk.size;
 		chunk.size = page_size - total;
 	} while (total < page_size);
-
-	vfs_file_put(file);
 
 	async_answer_1(rid, rc, (sysarg_t) page);
Index: uspace/srv/vfs/vfs_register.c
===================================================================
--- uspace/srv/vfs/vfs_register.c	(revision 39f892a96bc81bea824b6a8cba0f953a4e2a783d)
+++ uspace/srv/vfs/vfs_register.c	(revision 368ee04b0543abf978947ce5a1ea47698bb9692f)
@@ -296,5 +296,5 @@
  *
  */
-fs_handle_t fs_name_to_handle(unsigned int instance, char *name, bool lock)
+fs_handle_t fs_name_to_handle(unsigned int instance, const char *name, bool lock)
 {
 	int handle = 0;
