Index: uspace/srv/vfs/vfs.c
===================================================================
--- uspace/srv/vfs/vfs.c	(revision c638c071e1a86cd5861ae19ce8b30d9021536c03)
+++ uspace/srv/vfs/vfs.c	(revision 2b88074b388ca2afaa99dfb793b82d8753cc5f24)
@@ -126,4 +126,6 @@
 			vfs_sync(callid, &call);
 			break;
+		case VFS_IN_DUP:
+			vfs_dup(callid, &call);
 		default:
 			ipc_answer_0(callid, ENOTSUP);
Index: uspace/srv/vfs/vfs.h
===================================================================
--- uspace/srv/vfs/vfs.h	(revision c638c071e1a86cd5861ae19ce8b30d9021536c03)
+++ uspace/srv/vfs/vfs.h	(revision 2b88074b388ca2afaa99dfb793b82d8753cc5f24)
@@ -186,5 +186,6 @@
 extern bool vfs_files_init(void);
 extern vfs_file_t *vfs_file_get(int);
-extern int vfs_fd_alloc(void);
+extern int vfs_fd_assign(vfs_file_t *file, int fd);
+extern int vfs_fd_alloc(bool desc);
 extern int vfs_fd_free(int);
 
@@ -200,4 +201,5 @@
 extern void vfs_open_node(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 *);
Index: uspace/srv/vfs/vfs_file.c
===================================================================
--- uspace/srv/vfs/vfs_file.c	(revision c638c071e1a86cd5861ae19ce8b30d9021536c03)
+++ uspace/srv/vfs/vfs_file.c	(revision 2b88074b388ca2afaa99dfb793b82d8753cc5f24)
@@ -76,8 +76,11 @@
 /** Allocate a file descriptor.
  *
- * @return		First available file descriptor or a negative error
- *			code.
- */
-int vfs_fd_alloc(void)
+ * @param desc If true, look for an available file descriptor
+ *             in a descending order.
+ *
+ * @return First available file descriptor or a negative error
+ *         code.
+ */
+int vfs_fd_alloc(bool desc)
 {
 	if (!vfs_files_init())
@@ -85,5 +88,10 @@
 	
 	unsigned int i;
-	for (i = 0; i < MAX_OPEN_FILES; i++) {
+	if (desc)
+		i = MAX_OPEN_FILES;
+	else
+		i = 0;
+	
+	while (true) {
 		if (!files[i]) {
 			files[i] = (vfs_file_t *) malloc(sizeof(vfs_file_t));
@@ -96,4 +104,16 @@
 			return (int) i;
 		}
+		
+		if (desc) {
+			if (i == 0)
+				break;
+			
+			i--;
+		} else {
+			if (i == MAX_OPEN_FILES)
+				break;
+			
+			i++;
+		}
 	}
 	
@@ -118,4 +138,27 @@
 	vfs_file_delref(files[fd]);
 	files[fd] = NULL;
+	
+	return EOK;
+}
+
+/** Assign a file to a file descriptor.
+ *
+ * @param file File to assign.
+ * @param fd   File descriptor to assign to.
+ *
+ * @return EOK on success or EINVAL if fd is an invalid or already
+ *         used file descriptor.
+ *
+ */
+int vfs_fd_assign(vfs_file_t *file, int fd)
+{
+	if (!vfs_files_init())
+		return ENOMEM;
+	
+	if ((fd < 0) || (fd >= MAX_OPEN_FILES) || (files[fd] != NULL))
+		return EINVAL;
+	
+	files[fd] = file;
+	vfs_file_addref(files[fd]);
 	
 	return EOK;
Index: uspace/srv/vfs/vfs_ops.c
===================================================================
--- uspace/srv/vfs/vfs_ops.c	(revision c638c071e1a86cd5861ae19ce8b30d9021536c03)
+++ uspace/srv/vfs/vfs_ops.c	(revision 2b88074b388ca2afaa99dfb793b82d8753cc5f24)
@@ -543,5 +543,5 @@
 	 * structure.
 	 */
-	int fd = vfs_fd_alloc();
+	int fd = vfs_fd_alloc((oflag & O_DESC) != 0);
 	if (fd < 0) {
 		vfs_node_put(node);
@@ -620,5 +620,5 @@
 	 * structure.
 	 */
-	int fd = vfs_fd_alloc();
+	int fd = vfs_fd_alloc((oflag & O_DESC) != 0);
 	if (fd < 0) {
 		vfs_node_put(node);
@@ -679,4 +679,39 @@
 }
 
+static int vfs_close_internal(vfs_file_t *file)
+{
+	/*
+	 * Lock the open file structure so that no other thread can manipulate
+	 * the same open file at a time.
+	 */
+	fibril_mutex_lock(&file->lock);
+	
+	if (file->refcnt <= 1) {
+		/* Only close the file on the destination FS server
+		   if there are no more file descriptors (except the
+		   present one) pointing to this file. */
+		
+		int fs_phone = vfs_grab_phone(file->node->fs_handle);
+		
+		/* Make a VFS_OUT_CLOSE request at the destination FS server. */
+		aid_t msg;
+		ipc_call_t answer;
+		msg = async_send_2(fs_phone, VFS_OUT_CLOSE, file->node->dev_handle,
+		    file->node->index, &answer);
+		
+		/* Wait for reply from the FS server. */
+		ipcarg_t rc;
+		async_wait_for(msg, &rc);
+		
+		vfs_release_phone(fs_phone);
+		fibril_mutex_unlock(&file->lock);
+		
+		return IPC_GET_ARG1(answer);
+	}
+	
+	fibril_mutex_unlock(&file->lock);
+	return EOK;
+}
+
 void vfs_close(ipc_callid_t rid, ipc_call_t *request)
 {
@@ -690,30 +725,10 @@
 	}
 	
-	/*
-	 * Lock the open file structure so that no other thread can manipulate
-	 * the same open file at a time.
-	 */
-	fibril_mutex_lock(&file->lock);
-	int fs_phone = vfs_grab_phone(file->node->fs_handle);
-	
-	/* Make a VFS_OUT_CLOSE request at the destination FS server. */
-	aid_t msg;
-	ipc_call_t answer;
-	msg = async_send_2(fs_phone, VFS_OUT_CLOSE, file->node->dev_handle,
-	    file->node->index, &answer);
-
-	/* Wait for reply from the FS server. */
-	ipcarg_t rc;
-	async_wait_for(msg, &rc);
-
-	vfs_release_phone(fs_phone);
-	fibril_mutex_unlock(&file->lock);
-	
-	int retval = IPC_GET_ARG1(answer);
-	if (retval != EOK)
-		ipc_answer_0(rid, retval);
-	
-	retval = vfs_fd_free(fd);
-	ipc_answer_0(rid, retval);
+	int ret = vfs_close_internal(file);
+	if (ret != EOK)
+		ipc_answer_0(rid, ret);
+	
+	ret = vfs_fd_free(fd);
+	ipc_answer_0(rid, ret);
 }
 
@@ -1310,4 +1325,55 @@
 }
 
+void vfs_dup(ipc_callid_t rid, ipc_call_t *request)
+{
+	int oldfd = IPC_GET_ARG1(*request);
+	int newfd = IPC_GET_ARG2(*request);
+	
+	/* Lookup the file structure corresponding to oldfd. */
+	vfs_file_t *oldfile = vfs_file_get(oldfd);
+	if (!oldfile) {
+		ipc_answer_0(rid, EBADF);
+		return;
+	}
+	
+	/* If the file descriptors are the same, do nothing. */
+	if (oldfd == newfd) {
+		ipc_answer_1(rid, EOK, newfd);
+		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);
+	
+	/* Lookup an open file structure possibly corresponding to newfd. */
+	vfs_file_t *newfile = vfs_file_get(newfd);
+	if (newfile) {
+		/* Close the originally opened file. */
+		int ret = vfs_close_internal(newfile);
+		if (ret != EOK) {
+			ipc_answer_0(rid, ret);
+			return;
+		}
+		
+		ret = vfs_fd_free(newfd);
+		if (ret != EOK) {
+			ipc_answer_0(rid, ret);
+			return;
+		}
+	}
+	
+	/* Assign the old file to newfd. */
+	int ret = vfs_fd_assign(oldfile, newfd);
+	fibril_mutex_unlock(&oldfile->lock);
+	
+	if (ret != EOK)
+		ipc_answer_0(rid, ret);
+	else
+		ipc_answer_1(rid, EOK, newfd);
+}
+
 /**
  * @}
