Index: uspace/srv/fs/tmpfs/tmpfs_dump.c
===================================================================
--- uspace/srv/fs/tmpfs/tmpfs_dump.c	(revision 40257f573530dfd8a6fe333cbdf01104c782effa)
+++ uspace/srv/fs/tmpfs/tmpfs_dump.c	(revision 40257f573530dfd8a6fe333cbdf01104c782effa)
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 2008 Jakub Jermar 
+ * Copyright (c) 2008 Martin Decky 
+ * 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 fs
+ * @{
+ */ 
+
+/**
+ * @file	tmpfs_dump.c
+ * @brief	Support for loading TMPFS file system dump.
+ */
+
+#include "tmpfs.h"
+#include "../../vfs/vfs.h"
+#include <ipc/ipc.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <as.h>
+#include <libfs.h>
+#include <ipc/services.h>
+#include <ipc/devmap.h>
+#include <sys/mman.h>
+#include <byteorder.h>
+
+#define BLOCK_SIZE			1024	// FIXME
+#define RD_BASE				1024	// FIXME
+#define	RD_READ_BLOCK	(RD_BASE + 1)
+
+struct rdentry {
+	uint8_t type;
+	uint32_t len;
+} __attribute__((packed));
+
+static bool 
+tmpfs_blockread(int phone, void *buffer, size_t *bufpos, size_t *buflen,
+    size_t *pos, void *dst, size_t size)
+{
+	size_t offset = 0;
+	size_t left = size;
+	
+	while (left > 0) {
+		size_t rd;
+		
+		if (*bufpos + left < *buflen)
+			rd = left;
+		else
+			rd = *buflen - *bufpos;
+		
+		if (rd > 0) {
+			memcpy(dst + offset, buffer + *bufpos, rd);
+			offset += rd;
+			*bufpos += rd;
+			*pos += rd;
+			left -= rd;
+		}
+		
+		if (*bufpos == *buflen) {
+			ipcarg_t retval;
+			int rc = ipc_call_sync_2_1(phone, RD_READ_BLOCK,
+			    *pos / BLOCK_SIZE, BLOCK_SIZE,
+			    &retval);
+			if ((rc != EOK) || (retval != EOK))
+				return false;
+			
+			*bufpos = 0;
+			*buflen = BLOCK_SIZE;
+		}
+	}
+	
+	return true;
+}
+
+static bool
+tmpfs_restore_recursion(int phone, void *block, size_t *bufpos, size_t *buflen,
+    size_t *pos, tmpfs_dentry_t *parent)
+{
+	struct rdentry entry;
+	libfs_ops_t *ops = &tmpfs_libfs_ops;
+	
+	do {
+		char *fname;
+		tmpfs_dentry_t *node;
+		uint32_t size;
+		
+		if (!tmpfs_blockread(phone, block, bufpos, buflen, pos, &entry,
+		    sizeof(entry)))
+			return false;
+		
+		entry.len = uint32_t_le2host(entry.len);
+		
+		switch (entry.type) {
+		case 0:
+			break;
+		case 1:
+			fname = malloc(entry.len + 1);
+			if (fname == NULL)
+				return false;
+			
+			node = (tmpfs_dentry_t *) ops->create(L_FILE);
+			if (node == NULL) {
+				free(fname);
+				return false;
+			}
+			
+			if (!tmpfs_blockread(phone, block, bufpos, buflen, pos,
+			    fname, entry.len)) {
+				ops->destroy((void *) node);
+				free(fname);
+				return false;
+			}
+			fname[entry.len] = 0;
+			
+			if (!ops->link((void *) parent, (void *) node, fname)) {
+				ops->destroy((void *) node);
+				free(fname);
+				return false;
+			}
+			free(fname);
+			
+			if (!tmpfs_blockread(phone, block, bufpos, buflen, pos,
+			    &size, sizeof(size)))
+				return false;
+			
+			size = uint32_t_le2host(size);
+			
+			node->data = malloc(size);
+			if (node->data == NULL)
+				return false;
+			
+			node->size = size;
+			if (!tmpfs_blockread(phone, block, bufpos, buflen, pos,
+			    node->data, size))
+				return false;
+			
+			break;
+		case 2:
+			fname = malloc(entry.len + 1);
+			if (fname == NULL)
+				return false;
+			
+			node = (tmpfs_dentry_t *) ops->create(L_DIRECTORY);
+			if (node == NULL) {
+				free(fname);
+				return false;
+			}
+			
+			if (!tmpfs_blockread(phone, block, bufpos, buflen, pos,
+			    fname, entry.len)) {
+				ops->destroy((void *) node);
+				free(fname);
+				return false;
+			}
+			fname[entry.len] = 0;
+			
+			if (!ops->link((void *) parent, (void *) node, fname)) {
+				ops->destroy((void *) node);
+				free(fname);
+				return false;
+			}
+			free(fname);
+			
+			if (!tmpfs_restore_recursion(phone, block, bufpos,
+			    buflen, pos, node))
+				return false;
+			
+			break;
+		default:
+			return false;
+		}
+	} while (entry.type != 0);
+	
+	return true;
+}
+
+bool tmpfs_restore(dev_handle_t dev)
+{
+	libfs_ops_t *ops = &tmpfs_libfs_ops;
+
+	void *block = mmap(NULL, BLOCK_SIZE,
+	    PROTO_READ | PROTO_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
+	
+	if (block == NULL)
+		return false;
+	
+	int phone = ipc_connect_me_to(PHONE_NS, SERVICE_DEVMAP,
+	    DEVMAP_CONNECT_TO_DEVICE, dev);
+
+	if (phone < 0) {
+		munmap(block, BLOCK_SIZE);
+		return false;
+	}
+	
+	if (ipc_share_out_start(phone, block, AS_AREA_READ | AS_AREA_WRITE) !=
+	    EOK)
+		goto error;
+	
+	size_t bufpos = 0;
+	size_t buflen = 0;
+	size_t pos = 0;
+	
+	char tag[6];
+	if (!tmpfs_blockread(phone, block, &bufpos, &buflen, &pos, tag, 5))
+		goto error;
+	
+	tag[5] = 0;
+	if (strcmp(tag, "TMPFS") != 0)
+		goto error;
+	
+	if (!tmpfs_restore_recursion(phone, block, &bufpos, &buflen, &pos,
+	    ops->root_get(dev)))
+		goto error;
+		
+	ipc_hangup(phone);
+	munmap(block, BLOCK_SIZE);
+	return true;
+	
+error:
+	ipc_hangup(phone);
+	munmap(block, BLOCK_SIZE);
+	return false;
+}
+
+/**
+ * @}
+ */ 
