Index: uspace/lib/libc/generic/vfs/vfs.c
===================================================================
--- uspace/lib/libc/generic/vfs/vfs.c	(revision 2664838b8a9ac35d96ca7ecebab945aaad52c7d8)
+++ uspace/lib/libc/generic/vfs/vfs.c	(revision 07deef576e996d5e93d3d0c16be2bb8f453a0623)
@@ -469,4 +469,71 @@
 }
 
+int rename(const char *old, const char *new)
+{
+	int res;
+	ipcarg_t rc;
+	aid_t req;
+	
+	char *olda = absolutize(old);
+	if (!olda)
+		return ENOMEM;
+	size_t oldc_len;
+	char *oldc = canonify(olda, &oldc_len);
+	if (!oldc) {
+		free(olda);
+		return EINVAL;
+	}
+	char *newa = absolutize(new);
+	if (!newa) {
+		free(olda);
+		return ENOMEM;
+	}
+	size_t newc_len;
+	char *newc = canonify(newa, &newc_len);
+	if (!newc) {
+		free(olda);
+		free(newa);
+		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(olda);
+			free(newa);
+			return res;
+		}
+	}
+	req = async_send_0(vfs_phone, VFS_RENAME, NULL);
+	rc = ipc_data_write_start(vfs_phone, oldc, oldc_len);
+	if (rc != EOK) {
+		async_wait_for(req, NULL);
+		async_serialize_end();
+		futex_up(&vfs_phone_futex);
+		free(olda);
+		free(newa);
+		return (int) rc;
+	}
+	rc = ipc_data_write_start(vfs_phone, newc, newc_len);
+	if (rc != EOK) {
+		async_wait_for(req, NULL);
+		async_serialize_end();
+		futex_up(&vfs_phone_futex);
+		free(olda);
+		free(newa);
+		return (int) rc;
+	}
+	async_wait_for(req, &rc);
+	async_serialize_end();
+	futex_up(&vfs_phone_futex);
+	free(olda);
+	free(newa);
+	return rc;
+}
+
 int chdir(const char *path)
 {
Index: uspace/lib/libc/include/stdio.h
===================================================================
--- uspace/lib/libc/include/stdio.h	(revision 2664838b8a9ac35d96ca7ecebab945aaad52c7d8)
+++ uspace/lib/libc/include/stdio.h	(revision 07deef576e996d5e93d3d0c16be2bb8f453a0623)
@@ -68,4 +68,6 @@
 #define fprintf(f, fmt, ...) printf(fmt, ##__VA_ARGS__)
 
+extern int rename(const char *, const char *);
+
 #endif
 
Index: uspace/lib/libfs/libfs.c
===================================================================
--- uspace/lib/libfs/libfs.c	(revision 2664838b8a9ac35d96ca7ecebab945aaad52c7d8)
+++ uspace/lib/libfs/libfs.c	(revision 07deef576e996d5e93d3d0c16be2bb8f453a0623)
@@ -142,4 +142,5 @@
 	int dev_handle = IPC_GET_ARG3(*request);
 	int lflag = IPC_GET_ARG4(*request);
+	int index = IPC_GET_ARG5(*request); /* when L_LINK specified */
 
 	if (last < next)
@@ -181,19 +182,32 @@
 		/* handle miss: match amongst siblings */
 		if (!tmp) {
-			if ((next > last) && (lflag & L_CREATE)) {
-				/* no components left and L_CREATE specified */
+			if (next <= last) {
+				/* there are unprocessed components */
+				ipc_answer_0(rid, ENOENT);
+				return;
+			}
+			/* miss in the last component */
+			if (lflag & (L_CREATE | L_LINK)) { 
+				/* request to create a new link */
 				if (!ops->is_directory(cur)) {
 					ipc_answer_0(rid, ENOTDIR);
 					return;
-				} 
-				void *nodep = ops->create(lflag);
+				}
+				void *nodep;
+				if (lflag & L_CREATE)
+					nodep = ops->create(lflag);
+				else
+					nodep = ops->node_get(fs_handle,
+					    dev_handle, index);
 				if (nodep) {
 					if (!ops->link(cur, nodep, component)) {
-						ops->destroy(nodep);
+						if (lflag & L_CREATE)
+							ops->destroy(nodep);
 						ipc_answer_0(rid, ENOSPC);
 					} else {
 						ipc_answer_5(rid, EOK,
 						    fs_handle, dev_handle,
-						    ops->index_get(nodep), 0,
+						    ops->index_get(nodep),
+						    ops->size_get(nodep),
 						    ops->lnkcnt_get(nodep));
 					}
@@ -202,5 +216,10 @@
 				}
 				return;
-			}
+			} else if (lflag & L_PARENT) {
+				/* return parent */
+				ipc_answer_5(rid, EOK, fs_handle, dev_handle,
+				    ops->index_get(cur), ops->size_get(cur),
+				    ops->lnkcnt_get(cur));
+			} 
 			ipc_answer_0(rid, ENOENT);
 			return;
@@ -215,5 +234,5 @@
 	/* handle miss: excessive components */
 	if (!tmp && next <= last) {
-		if (lflag & L_CREATE) {
+		if (lflag & (L_CREATE | L_LINK)) {
 			if (!ops->is_directory(cur)) {
 				ipc_answer_0(rid, ENOTDIR);
@@ -240,13 +259,20 @@
 			len = 0;
 				
-			void *nodep = ops->create(lflag);
+			void *nodep;
+			if (lflag & L_CREATE)
+				nodep = ops->create(lflag);
+			else
+				nodep = ops->node_get(fs_handle, dev_handle,
+				    index);
 			if (nodep) {
 				if (!ops->link(cur, nodep, component)) {
-					ops->destroy(nodep);
+					if (lflag & L_CREATE)
+						ops->destroy(nodep);
 					ipc_answer_0(rid, ENOSPC);
 				} else {
 					ipc_answer_5(rid, EOK,
 					    fs_handle, dev_handle,
-					    ops->index_get(nodep), 0,
+					    ops->index_get(nodep),
+					    ops->size_get(nodep),
 					    ops->lnkcnt_get(nodep));
 				}
@@ -261,5 +287,12 @@
 
 	/* handle hit */
-	if (lflag & L_DESTROY) {
+	if (lflag & L_PARENT) {
+		cur = par;
+		if (!cur) {
+			ipc_answer_0(rid, ENOENT);
+			return;
+		}
+	}
+	if (lflag & L_UNLINK) {
 		unsigned old_lnkcnt = ops->lnkcnt_get(cur);
 		int res = ops->unlink(par, cur);
@@ -268,5 +301,6 @@
 		return;
 	}
-	if ((lflag & (L_CREATE | L_EXCLUSIVE)) == (L_CREATE | L_EXCLUSIVE)) {
+	if (((lflag & (L_CREATE | L_EXCLUSIVE)) == (L_CREATE | L_EXCLUSIVE)) ||
+	    (lflag & L_LINK)) {
 		ipc_answer_0(rid, EEXIST);
 		return;
Index: uspace/lib/libfs/libfs.h
===================================================================
--- uspace/lib/libfs/libfs.h	(revision 2664838b8a9ac35d96ca7ecebab945aaad52c7d8)
+++ uspace/lib/libfs/libfs.h	(revision 07deef576e996d5e93d3d0c16be2bb8f453a0623)
@@ -44,4 +44,5 @@
 typedef struct {
 	bool (* match)(void *, void *, const char *);
+	void * (* node_get)(int, int, unsigned long);
 	void * (* create)(int);
 	void (* destroy)(void *);
