Index: uspace/lib/libc/generic/vfs/vfs.c
===================================================================
--- uspace/lib/libc/generic/vfs/vfs.c	(revision dadcec1dfd773eb63e3a2420db90b31207fcc6a2)
+++ uspace/lib/libc/generic/vfs/vfs.c	(revision adc8a631eeee9e9aae1471731f01a21ac0e1cf9e)
@@ -33,5 +33,6 @@
  */
  
-#include <vfs.h>
+#include <vfs/vfs.h>
+#include <vfs/canonify.h>
 #include <stdlib.h>
 #include <unistd.h>
@@ -50,5 +51,42 @@
 
 int vfs_phone = -1;
-atomic_t vfs_phone_futex = FUTEX_INITIALIZER;
+futex_t vfs_phone_futex = FUTEX_INITIALIZER;
+
+futex_t cwd_futex = FUTEX_INITIALIZER;
+DIR *cwd_dir = NULL;
+char *cwd_path = NULL;
+size_t cwd_len = 0; 
+
+static char *absolutize(const char *path)
+{
+	char *ncwd_path;
+
+	futex_down(&cwd_futex);
+	size_t len = strlen(path);
+	if (*path != '/') {
+		if (!cwd_path) {
+			futex_up(&cwd_futex);
+			return NULL;
+		}
+		ncwd_path = malloc(len + cwd_len + 1);
+		if (!ncwd_path) {
+			futex_up(&cwd_futex);
+			return NULL;
+		}
+		strcpy(ncwd_path, cwd_path);
+		ncwd_path[cwd_len] = '/';
+		ncwd_path[cwd_len + 1] = '\0';
+	} else {
+		ncwd_path = malloc(len + 1);
+		if (!ncwd_path) {
+			futex_up(&cwd_futex);
+			return NULL;
+		}
+		ncwd_path[0] = '\0';
+	}
+	strcat(ncwd_path, path);
+	futex_up(&cwd_futex);
+	return ncwd_path;
+}
 
 static int vfs_connect(void)
@@ -67,11 +105,22 @@
 	int dev_handle = 0;	/* TODO */
 
-	futex_down(&vfs_phone_futex);
-	async_serialize_start();
-	if (vfs_phone < 0) {
-		res = vfs_connect();
-		if (res < 0) {
-			async_serialize_end();
-			futex_up(&vfs_phone_futex);
+	char *mpa = absolutize(mp);
+	if (!mpa)
+		return ENOMEM;
+	size_t mpc_len;
+	char *mpc = canonify(mpa, &mpc_len);
+	if (!mpc) {
+		free(mpa);
+		return EINVAL;
+	}
+
+	futex_down(&vfs_phone_futex);
+	async_serialize_start();
+	if (vfs_phone < 0) {
+		res = vfs_connect();
+		if (res < 0) {
+			async_serialize_end();
+			futex_up(&vfs_phone_futex);
+			free(mpa);
 			return res;
 		}
@@ -83,11 +132,13 @@
 		async_serialize_end();
 		futex_up(&vfs_phone_futex);
+		free(mpa);
 		return (int) rc;
 	}
-	rc = ipc_data_write_start(vfs_phone, (void *)mp, strlen(mp));
-	if (rc != EOK) {
-		async_wait_for(req, NULL);
-		async_serialize_end();
-		futex_up(&vfs_phone_futex);
+	rc = ipc_data_write_start(vfs_phone, (void *)mpc, mpc_len);
+	if (rc != EOK) {
+		async_wait_for(req, NULL);
+		async_serialize_end();
+		futex_up(&vfs_phone_futex);
+		free(mpa);
 		return (int) rc;
 	}
@@ -95,4 +146,5 @@
 	async_serialize_end();
 	futex_up(&vfs_phone_futex);
+	free(mpa);
 	return (int) rc;
 }
@@ -105,20 +157,32 @@
 	aid_t req;
 	
-	futex_down(&vfs_phone_futex);
-	async_serialize_start();
-	if (vfs_phone < 0) {
-		res = vfs_connect();
-		if (res < 0) {
-			async_serialize_end();
-			futex_up(&vfs_phone_futex);
+	char *pa = absolutize(path);
+	if (!pa)
+		return ENOMEM;
+	size_t pc_len;
+	char *pc = canonify(pa, &pc_len);
+	if (!pc) {
+		free(pa);
+		return EINVAL;
+	}
+	
+	futex_down(&vfs_phone_futex);
+	async_serialize_start();
+	if (vfs_phone < 0) {
+		res = vfs_connect();
+		if (res < 0) {
+			async_serialize_end();
+			futex_up(&vfs_phone_futex);
+			free(pa);
 			return res;
 		}
 	}
 	req = async_send_3(vfs_phone, VFS_OPEN, lflag, oflag, 0, &answer);
-	rc = ipc_data_write_start(vfs_phone, path, strlen(path));
-	if (rc != EOK) {
-		async_wait_for(req, NULL);
-		async_serialize_end();
-		futex_up(&vfs_phone_futex);
+	rc = ipc_data_write_start(vfs_phone, pc, pc_len);
+	if (rc != EOK) {
+		async_wait_for(req, NULL);
+		async_serialize_end();
+		futex_up(&vfs_phone_futex);
+		free(pa);
 		return (int) rc;
 	}
@@ -126,4 +190,5 @@
 	async_serialize_end();
 	futex_up(&vfs_phone_futex);
+	free(pa);
 	return (int) IPC_GET_ARG1(answer);
 }
@@ -315,20 +380,32 @@
 	aid_t req;
 	
-	futex_down(&vfs_phone_futex);
-	async_serialize_start();
-	if (vfs_phone < 0) {
-		res = vfs_connect();
-		if (res < 0) {
-			async_serialize_end();
-			futex_up(&vfs_phone_futex);
+	char *pa = absolutize(path);
+	if (!pa)
+		return ENOMEM;
+	size_t pc_len;
+	char *pc = canonify(pa, &pc_len);
+	if (!pc) {
+		free(pa);
+		return EINVAL;
+	}
+
+	futex_down(&vfs_phone_futex);
+	async_serialize_start();
+	if (vfs_phone < 0) {
+		res = vfs_connect();
+		if (res < 0) {
+			async_serialize_end();
+			futex_up(&vfs_phone_futex);
+			free(pa);
 			return res;
 		}
 	}
 	req = async_send_1(vfs_phone, VFS_MKDIR, mode, NULL);
-	rc = ipc_data_write_start(vfs_phone, path, strlen(path));
-	if (rc != EOK) {
-		async_wait_for(req, NULL);
-		async_serialize_end();
-		futex_up(&vfs_phone_futex);
+	rc = ipc_data_write_start(vfs_phone, pc, pc_len);
+	if (rc != EOK) {
+		async_wait_for(req, NULL);
+		async_serialize_end();
+		futex_up(&vfs_phone_futex);
+		free(pa);
 		return (int) rc;
 	}
@@ -336,4 +413,5 @@
 	async_serialize_end();
 	futex_up(&vfs_phone_futex);
+	free(pa);
 	return EOK; 
 }
@@ -345,20 +423,31 @@
 	aid_t req;
 	
-	futex_down(&vfs_phone_futex);
-	async_serialize_start();
-	if (vfs_phone < 0) {
-		res = vfs_connect();
-		if (res < 0) {
-			async_serialize_end();
-			futex_up(&vfs_phone_futex);
+	char *pa = absolutize(path);
+	if (!pa)
+		return ENOMEM;
+	size_t pc_len;
+	char *pc = canonify(pa, &pc_len);
+	if (!pc) {
+		free(pa);
+		return EINVAL;
+	}
+	futex_down(&vfs_phone_futex);
+	async_serialize_start();
+	if (vfs_phone < 0) {
+		res = vfs_connect();
+		if (res < 0) {
+			async_serialize_end();
+			futex_up(&vfs_phone_futex);
+			free(pa);
 			return res;
 		}
 	}
 	req = async_send_0(vfs_phone, VFS_UNLINK, NULL);
-	rc = ipc_data_write_start(vfs_phone, path, strlen(path));
-	if (rc != EOK) {
-		async_wait_for(req, NULL);
-		async_serialize_end();
-		futex_up(&vfs_phone_futex);
+	rc = ipc_data_write_start(vfs_phone, pc, pc_len);
+	if (rc != EOK) {
+		async_wait_for(req, NULL);
+		async_serialize_end();
+		futex_up(&vfs_phone_futex);
+		free(pa);
 		return (int) rc;
 	}
@@ -366,4 +455,5 @@
 	async_serialize_end();
 	futex_up(&vfs_phone_futex);
+	free(pa);
 	return EOK; 
 }
@@ -377,4 +467,50 @@
 {
 	return _unlink(path, L_DIRECTORY);
+}
+
+int chdir(const char *path)
+{
+	char *pa = absolutize(path);
+	if (!pa)
+		return ENOMEM;
+	size_t pc_len;
+	char *pc = canonify(pa, &pc_len);
+	if (!pc) {
+		free(pa);
+		return ENOENT;
+	}
+
+	DIR *d = opendir(pc);
+	if (!d) {
+		free(pa);
+		return ENOENT;
+	}
+
+	futex_down(&cwd_futex);
+	if (cwd_dir) {
+		closedir(cwd_dir);
+		cwd_dir = NULL;
+		free(cwd_path);	
+		cwd_path = NULL;
+		cwd_len = 0;
+	}
+	cwd_dir = d;
+	cwd_path = pc;
+	cwd_len = pc_len;
+	futex_up(&cwd_futex);
+}
+
+char *getcwd(char *buf, size_t size)
+{
+	if (!size)
+		return NULL;
+	futex_down(&cwd_futex);
+	if (size < cwd_len + 1) {
+		futex_up(&cwd_futex);
+		return NULL;
+	}
+	strcpy(buf, cwd_path);
+	futex_up(&cwd_futex);
+	return buf;
 }
 
