Index: .bzrignore
===================================================================
--- .bzrignore	(revision f483a1595e01c6dce011869a0e03969833df9750)
+++ .bzrignore	(revision f483a1595e01c6dce011869a0e03969833df9750)
@@ -0,0 +1,176 @@
+Makefile.depend
+Makefile.depend.prev
+*.map
+*.disasm
+Makefile.common
+Makefile.config
+autotool/
+common.h
+common.h.prev
+config.h
+image.iso
+cscope.out
+boot/distroot/
+boot/initrd.fs
+boot/initrd.img
+kernel/kernel.bin
+kernel/kernel.dump
+kernel/kernel.map.prev
+kernel/kernel.raw
+kernel/arch/amd64/_link.ld
+kernel/arch/amd64/include/common.h
+kernel/arch/ia32/_link.ld
+kernel/generic/include/arch
+kernel/generic/include/genarch
+kernel/generic/src/debug/real_map.bin
+uspace/app/bdsh/bdsh
+uspace/app/blkdump/blkdump
+uspace/app/edit/edit
+uspace/app/ext2info/ext2info
+uspace/app/getterm/getterm
+uspace/app/init/init
+uspace/app/kill/kill
+uspace/app/killall/killall
+uspace/app/klog/klog
+uspace/app/mkfat/mkfat
+uspace/app/netecho/netecho
+uspace/app/nettest1/nettest1
+uspace/app/nettest2/nettest2
+uspace/app/ping/ping
+uspace/app/redir/redir
+uspace/app/sbi/sbi
+uspace/app/stats/stats
+uspace/app/sysinfo/sysinfo
+uspace/app/taskdump/taskdump
+uspace/app/tasks/tasks
+uspace/app/test_serial/test_serial
+uspace/app/tester/tester
+uspace/app/tetris/tetris
+uspace/app/top/top
+uspace/app/trace/trace
+uspace/app/websrv/websrv
+uspace/dist/app/bdsh
+uspace/dist/app/blkdump
+uspace/dist/app/edit
+uspace/dist/app/ext2info
+uspace/dist/app/getterm
+uspace/dist/app/kill
+uspace/dist/app/killall
+uspace/dist/app/klog
+uspace/dist/app/mkfat
+uspace/dist/app/netecho
+uspace/dist/app/nettest1
+uspace/dist/app/nettest2
+uspace/dist/app/ping
+uspace/dist/app/redir
+uspace/dist/app/sbi
+uspace/dist/app/stats
+uspace/dist/app/sysinfo
+uspace/dist/app/taskdump
+uspace/dist/app/tasks
+uspace/dist/app/test_serial
+uspace/dist/app/tester
+uspace/dist/app/tetris
+uspace/dist/app/top
+uspace/dist/app/trace
+uspace/dist/app/websrv
+uspace/dist/cfg/net/general
+uspace/dist/cfg/net/lo
+uspace/dist/cfg/net/ne2k
+uspace/dist/drv/isa/
+uspace/dist/drv/ns8250/
+uspace/dist/drv/pciintel/
+uspace/dist/drv/root/
+uspace/dist/drv/rootia32/
+uspace/dist/drv/rootpc/
+uspace/dist/drv/rootvirt/
+uspace/dist/drv/test1/
+uspace/dist/drv/test2/
+uspace/dist/srv/apic
+uspace/dist/srv/arp
+uspace/dist/srv/ata_bd
+uspace/dist/srv/char_ms
+uspace/dist/srv/clip
+uspace/dist/srv/console
+uspace/dist/srv/devfs
+uspace/dist/srv/devman
+uspace/dist/srv/dp8390
+uspace/dist/srv/eth
+uspace/dist/srv/ext2
+uspace/dist/srv/fat
+uspace/dist/srv/fb
+uspace/dist/srv/file_bd
+uspace/dist/srv/g_part
+uspace/dist/srv/i8042
+uspace/dist/srv/i8259
+uspace/dist/srv/icmp
+uspace/dist/srv/ip
+uspace/dist/srv/kbd
+uspace/dist/srv/lo
+uspace/dist/srv/mbr_part
+uspace/dist/srv/ne2000
+uspace/dist/srv/net
+uspace/dist/srv/nildummy
+uspace/dist/srv/pipefs
+uspace/dist/srv/taskmon
+uspace/dist/srv/tcp
+uspace/dist/srv/tmpfs
+uspace/dist/srv/udp
+uspace/drv/root/root
+uspace/drv/isa/isa
+uspace/drv/ns8250/ns8250
+uspace/drv/pciintel/pciintel
+uspace/drv/rootia32/rootia32
+uspace/drv/rootpc/rootpc
+uspace/drv/rootvirt/rootvirt
+uspace/drv/test1/test1
+uspace/drv/test2/test2
+uspace/lib/c/arch/amd64/_link.ld
+uspace/lib/c/arch/amd64/include/common.h
+uspace/lib/c/arch/ia32/_link.ld
+uspace/lib/c/include/arch
+uspace/lib/c/include/kernel
+uspace/lib/c/include/libarch
+uspace/srv/bd/ata_bd/ata_bd
+uspace/srv/bd/file_bd/file_bd
+uspace/srv/bd/gxe_bd/gxe_bd
+uspace/srv/bd/part/guid_part/g_part
+uspace/srv/bd/part/mbr_part/mbr_part
+uspace/srv/bd/rd/rd
+uspace/srv/clip/clip
+uspace/srv/devman/devman
+uspace/srv/devmap/devmap
+uspace/srv/fs/devfs/devfs
+uspace/srv/fs/ext2/ext2
+uspace/srv/fs/fat/fat
+uspace/srv/fs/tmpfs/tmpfs
+uspace/srv/fs/pipefs/pipefs
+uspace/srv/hid/adb_mouse/adb_ms
+uspace/srv/hid/char_mouse/char_ms
+uspace/srv/hid/console/console
+uspace/srv/hid/fb/fb
+uspace/srv/hid/kbd/kbd
+uspace/srv/hid/s3c24xx_ts/s3c24ts
+uspace/srv/hw/char/i8042/i8042
+uspace/srv/hw/char/s3c24xx_uart/s3c24ser
+uspace/srv/hw/irc/apic/apic
+uspace/srv/hw/irc/i8259/i8259
+uspace/srv/hw/netif/dp8390/dp8390
+uspace/srv/hw/netif/ne2000/ne2000
+uspace/srv/loader/loader
+uspace/srv/loader/arch/amd64/_link.ld
+uspace/srv/loader/arch/ia32/_link.ld
+uspace/srv/net/cfg/lo
+uspace/srv/net/cfg/ne2k
+uspace/srv/net/il/arp/arp
+uspace/srv/net/il/ip/ip
+uspace/srv/net/net/net
+uspace/srv/net/netif/lo/lo
+uspace/srv/net/nil/eth/eth
+uspace/srv/net/nil/nildummy/nildummy
+uspace/srv/net/tl/icmp/icmp
+uspace/srv/net/tl/tcp/tcp
+uspace/srv/net/tl/udp/udp
+uspace/srv/ns/ns
+uspace/srv/taskmon/taskmon
+uspace/srv/vfs/vfs
Index: boot/Makefile.common
===================================================================
--- boot/Makefile.common	(revision 664af7080d443cca0efb84c002b3d440ca6f67c1)
+++ boot/Makefile.common	(revision f483a1595e01c6dce011869a0e03969833df9750)
@@ -97,4 +97,6 @@
 	$(USPACE_PATH)/srv/fs/tmpfs/tmpfs \
 	$(USPACE_PATH)/srv/fs/fat/fat \
+	$(USPACE_PATH)/srv/fs/pipefs/pipefs \
+	$(USPACE_PATH)/srv/fs/ext2/ext2 \
 	$(USPACE_PATH)/srv/taskmon/taskmon \
 	$(USPACE_PATH)/srv/hw/netif/ne2000/ne2000 \
@@ -124,5 +126,7 @@
 
 RD_APPS_NON_ESSENTIAL = \
+	$(USPACE_PATH)/app/blkdump/blkdump \
 	$(USPACE_PATH)/app/edit/edit \
+	$(USPACE_PATH)/app/ext2info/ext2info \
 	$(USPACE_PATH)/app/kill/kill \
 	$(USPACE_PATH)/app/killall/killall \
Index: uspace/Makefile
===================================================================
--- uspace/Makefile	(revision 664af7080d443cca0efb84c002b3d440ca6f67c1)
+++ uspace/Makefile	(revision f483a1595e01c6dce011869a0e03969833df9750)
@@ -35,5 +35,7 @@
 DIRS = \
 	app/bdsh \
+	app/blkdump \
 	app/edit \
+	app/ext2info \
 	app/getterm \
 	app/init \
@@ -72,4 +74,6 @@
 	srv/fs/tmpfs \
 	srv/fs/devfs \
+	srv/fs/pipefs \
+	srv/fs/ext2 \
 	srv/hid/adb_mouse \
 	srv/hid/char_mouse \
@@ -148,5 +152,6 @@
 	lib/drv \
 	lib/packet \
-	lib/net
+	lib/net \
+	lib/ext2
 
 LIBC_BUILD = $(addsuffix .build,$(LIBC))
Index: uspace/Makefile.common
===================================================================
--- uspace/Makefile.common	(revision 664af7080d443cca0efb84c002b3d440ca6f67c1)
+++ uspace/Makefile.common	(revision f483a1595e01c6dce011869a0e03969833df9750)
@@ -86,4 +86,6 @@
 LIBCLUI_PREFIX = $(LIB_PREFIX)/clui
 
+LIBEXT2_PREFIX = $(LIB_PREFIX)/ext2
+
 LIBDRV_PREFIX = $(LIB_PREFIX)/drv
 LIBPACKET_PREFIX = $(LIB_PREFIX)/packet
Index: uspace/app/bdsh/cmds/modules/mount/mount.c
===================================================================
--- uspace/app/bdsh/cmds/modules/mount/mount.c	(revision 664af7080d443cca0efb84c002b3d440ca6f67c1)
+++ uspace/app/bdsh/cmds/modules/mount/mount.c	(revision f483a1595e01c6dce011869a0e03969833df9750)
@@ -44,5 +44,5 @@
 {
 	static char helpfmt[] =
-	    "Usage:  %s <fstype> <mp> <dev> [<moptions>]\n";
+	    "Usage:  %s <fstype> <mp> [dev] [<moptions>]\n";
 	if (level == HELP_SHORT) {
 		printf("'%s' mounts a file system.\n", cmdname);
@@ -59,17 +59,20 @@
 	unsigned int argc;
 	const char *mopts = "";
+	const char *dev = "";
 	int rc;
 
 	argc = cli_count_args(argv);
 
-	if ((argc < 4) || (argc > 5)) {
+	if ((argc < 3) || (argc > 5)) {
 		printf("%s: invalid number of arguments.\n",
 		    cmdname);
 		return CMD_FAILURE;
 	}
+	if (argc > 3)
+		dev = argv[3];
 	if (argc == 5)
 		mopts = argv[4];
 
-	rc = mount(argv[1], argv[2], argv[3], mopts, 0);
+	rc = mount(argv[1], argv[2], dev, mopts, 0);
 	if (rc != EOK) {
 		printf("Unable to mount %s filesystem to %s on %s (rc=%d)\n",
Index: uspace/app/blkdump/Makefile
===================================================================
--- uspace/app/blkdump/Makefile	(revision f483a1595e01c6dce011869a0e03969833df9750)
+++ uspace/app/blkdump/Makefile	(revision f483a1595e01c6dce011869a0e03969833df9750)
@@ -0,0 +1,38 @@
+#
+# Copyright (c) 2005 Martin Decky
+# 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.
+#
+
+USPACE_PREFIX = ../..
+LIBS = $(LIBBLOCK_PREFIX)/libblock.a
+EXTRA_CFLAGS = -I$(LIBBLOCK_PREFIX)
+BINARY = blkdump
+
+SOURCES = \
+	blkdump.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/blkdump/blkdump.c
===================================================================
--- uspace/app/blkdump/blkdump.c	(revision f483a1595e01c6dce011869a0e03969833df9750)
+++ uspace/app/blkdump/blkdump.c	(revision f483a1595e01c6dce011869a0e03969833df9750)
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2011 Martin Sucha
+ * Copyright (c) 2010 Jiri Svoboda
+ * 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	blockdump.c
+ * @brief	Tool for dumping content of block devices
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <libblock.h>
+#include <mem.h>
+#include <devmap.h>
+#include <byteorder.h>
+#include <sys/types.h>
+#include <sys/typefmt.h>
+#include <inttypes.h>
+#include <errno.h>
+
+#define NAME	"blkdump"
+
+static void syntax_print(void);
+static void print_hex_row(uint8_t *data, size_t length, size_t bytes_per_row);
+
+int main(int argc, char **argv)
+{
+
+	int rc;
+	char *dev_path;
+	devmap_handle_t handle;
+	size_t block_size;
+	char *endptr;
+	aoff64_t block_offset = 0;
+	aoff64_t block_count = 1;
+	aoff64_t dev_nblocks;
+	uint8_t *data;
+	size_t data_offset;
+	aoff64_t current;
+	aoff64_t limit;
+	bool relative = false;
+	
+	if (argc < 2) {
+		printf(NAME ": Error, argument missing.\n");
+		syntax_print();
+		return 1;
+	}
+
+	--argc; ++argv;
+
+	if (str_cmp(*argv, "--relative") == 0) {
+		--argc; ++argv;
+		relative = true;
+	}
+	
+	if (str_cmp(*argv, "--offset") == 0) {
+		--argc; ++argv;
+		if (*argv == NULL) {
+			printf(NAME ": Error, argument missing (offset).\n");
+			syntax_print();
+			return 1;
+		}
+
+		block_offset = strtol(*argv, &endptr, 10);
+		if (*endptr != '\0') {
+			printf(NAME ": Error, invalid argument (offset).\n");
+			syntax_print();
+			return 1;
+		}
+
+		--argc; ++argv;
+	}
+	
+	if (str_cmp(*argv, "--count") == 0) {
+		--argc; ++argv;
+		if (*argv == NULL) {
+			printf(NAME ": Error, argument missing (count).\n");
+			syntax_print();
+			return 1;
+		}
+
+		block_count = strtol(*argv, &endptr, 10);
+		if (*endptr != '\0') {
+			printf(NAME ": Error, invalid argument (count).\n");
+			syntax_print();
+			return 1;
+		}
+
+		--argc; ++argv;
+	}
+
+	if (argc != 1) {
+		printf(NAME ": Error, unexpected argument.\n");
+		syntax_print();
+		return 1;
+	}
+
+	dev_path = *argv;
+
+	rc = devmap_device_get_handle(dev_path, &handle, 0);
+	if (rc != EOK) {
+		printf(NAME ": Error resolving device `%s'.\n", dev_path);
+		return 2;
+	}
+
+	rc = block_init(handle, 2048);
+	if (rc != EOK)  {
+		printf(NAME ": Error initializing libblock.\n");
+		return 2;
+	}
+
+	rc = block_get_bsize(handle, &block_size);
+	if (rc != EOK) {
+		printf(NAME ": Error determining device block size.\n");
+		return 2;
+	}
+
+	rc = block_get_nblocks(handle, &dev_nblocks);
+	if (rc != EOK) {
+		printf(NAME ": Warning, failed to obtain block device size.\n");
+	}
+
+	printf("Device %s has %" PRIuOFF64 " blocks, %" PRIuOFF64 " bytes each\n", dev_path, dev_nblocks, (aoff64_t) block_size);
+
+	data = malloc(block_size);
+	if (data == NULL) {
+		printf(NAME ": Error allocating data buffer of %" PRIuOFF64 " bytes", (aoff64_t) block_size);
+		block_fini(handle);
+		return 3;
+	}
+	
+	limit = block_offset + block_count;
+	for (current = block_offset; current < limit; current++) {
+		rc = block_read_direct(handle, current, 1, data);
+		if (rc != EOK) {
+			printf(NAME ": Error reading block at %" PRIuOFF64 " \n", current);
+			free(data);
+			return 3;
+		}
+		
+		printf("---- Block %" PRIuOFF64 " (at %" PRIuOFF64 ") ----\n", current, current*block_size);
+		
+		for (data_offset = 0; data_offset < block_size; data_offset += 16) {
+			if (relative) {
+				printf("%8" PRIxOFF64 ": ", (aoff64_t) data_offset);
+			}
+			else {
+				printf("%8" PRIxOFF64 ": ", current*block_size + data_offset);
+			}
+			print_hex_row(data+data_offset, block_size-data_offset, 16);
+			printf("\n");
+		}
+		printf("\n");
+	}
+	
+	free(data);
+
+	block_fini(handle);
+
+	return 0;
+}
+
+/**
+ * Print a row of 16 bytes as commonly seen in hexadecimal dumps
+ */
+static void print_hex_row(uint8_t *data, size_t length, size_t bytes_per_row) {
+	size_t pos;
+	uint8_t b;
+	
+	if (length > bytes_per_row) {
+		length = bytes_per_row;
+	}
+	
+	// Print hexadecimal values
+	for (pos = 0; pos < length; pos++) {
+		if (pos == length/2) {
+			printf(" ");
+		}
+		printf("%02hhX ", data[pos]);
+	}
+	
+	// pad with spaces if we have less than 16 bytes
+	for (pos = length; pos < bytes_per_row; pos++) {
+		if (pos == length/2) {
+			printf(" ");
+		}
+		printf("   ");
+	}
+	
+	// Print printable characters
+	for (pos = 0; pos < length; pos++) {
+		if (pos == length/2) {
+			printf(" ");
+		}
+		b = data[pos];
+		if (b >= 32 && b < 128) {
+			putchar(b);
+		}
+		else {
+			putchar('.');
+		}
+	}
+}
+
+static void syntax_print(void)
+{
+	printf("syntax: blkdump [--relative] [--offset <num_blocks>] [--count <num_blocks>] <device_name>\n");
+}
+
+/**
+ * @}
+ */
Index: uspace/app/ext2info/Makefile
===================================================================
--- uspace/app/ext2info/Makefile	(revision f483a1595e01c6dce011869a0e03969833df9750)
+++ uspace/app/ext2info/Makefile	(revision f483a1595e01c6dce011869a0e03969833df9750)
@@ -0,0 +1,38 @@
+#
+# Copyright (c) 2005 Martin Decky
+# 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.
+#
+
+USPACE_PREFIX = ../..
+LIBS = $(LIBBLOCK_PREFIX)/libblock.a $(LIBEXT2_PREFIX)/libext2.a
+EXTRA_CFLAGS = -I$(LIBBLOCK_PREFIX) -I$(LIBEXT2_PREFIX)
+BINARY = ext2info
+
+SOURCES = \
+	ext2info.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/ext2info/ext2info.c
===================================================================
--- uspace/app/ext2info/ext2info.c	(revision f483a1595e01c6dce011869a0e03969833df9750)
+++ uspace/app/ext2info/ext2info.c	(revision f483a1595e01c6dce011869a0e03969833df9750)
@@ -0,0 +1,414 @@
+/*
+ * Copyright (c) 2011 Martin Sucha
+ * Copyright (c) 2010 Jiri Svoboda
+ * 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	ext2info.c
+ * @brief	Tool for displaying information about ext2 filesystem
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <libblock.h>
+#include <mem.h>
+#include <devmap.h>
+#include <byteorder.h>
+#include <sys/types.h>
+#include <sys/typefmt.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <libext2.h>
+
+#define NAME	"ext2info"
+
+static void syntax_print(void);
+static void print_superblock(ext2_superblock_t *);
+static void print_block_groups(ext2_filesystem_t *);
+static void print_block_group(ext2_block_group_t *);
+static void print_inode_by_number(ext2_filesystem_t *, uint32_t);
+static void print_inode(ext2_filesystem_t *, ext2_inode_t *);
+
+#define ARG_SUPERBLOCK 1
+#define ARG_BLOCK_GROUPS 2
+#define ARG_INODE 4
+#define ARG_STRICT_CHECK 8
+#define ARG_COMMON (ARG_SUPERBLOCK | ARG_BLOCK_GROUPS)
+#define ARG_ALL (ARG_COMMON | ARG_INODE)
+
+
+int main(int argc, char **argv)
+{
+
+	int rc;
+	char *endptr;
+	char *dev_path;
+	devmap_handle_t handle;
+	ext2_filesystem_t filesystem;
+	int arg_flags;
+	uint32_t inode = 0;
+	
+	arg_flags = 0;
+	
+	if (argc < 2) {
+		printf(NAME ": Error, argument missing.\n");
+		syntax_print();
+		return 1;
+	}
+	
+	// Skip program name
+	--argc; ++argv;
+	
+	if (str_cmp(*argv, "--strict-check") == 0) {
+		--argc; ++argv;
+		arg_flags |= ARG_STRICT_CHECK;
+	}
+	
+	if (str_cmp(*argv, "--superblock") == 0) {
+		--argc; ++argv;
+		arg_flags |= ARG_SUPERBLOCK;
+	}
+	
+	if (str_cmp(*argv, "--block-groups") == 0) {
+		--argc; ++argv;
+		arg_flags |= ARG_BLOCK_GROUPS;
+	}
+	
+	if (str_cmp(*argv, "--inode") == 0) {
+		--argc; ++argv;
+		if (argc == 0) {
+			printf(NAME ": Argument expected for --inode\n");
+			return 2;
+		}
+		
+		inode = strtol(*argv, &endptr, 10);
+		if (*endptr != '\0') {
+			printf(NAME ": Error, invalid argument for --inode.\n");
+			syntax_print();
+			return 1;
+		}
+		
+		arg_flags |= ARG_INODE;
+		--argc; ++argv;
+	}
+
+	if (argc != 1) {
+		printf(NAME ": Error, unexpected argument.\n");
+		syntax_print();
+		return 1;
+	}
+	
+	// Display common things by default
+	if ((arg_flags & ARG_ALL) == 0) {
+		arg_flags = ARG_COMMON;
+	}
+
+	dev_path = *argv;
+
+	rc = devmap_device_get_handle(dev_path, &handle, 0);
+	if (rc != EOK) {
+		printf(NAME ": Error resolving device `%s'.\n", dev_path);
+		return 2;
+	}
+
+	rc = ext2_filesystem_init(&filesystem, handle);
+	if (rc != EOK)  {
+		printf(NAME ": Error initializing libext2.\n");
+		return 3;
+	}
+	
+	rc = ext2_filesystem_check_sanity(&filesystem);
+	if (rc != EOK) {
+		printf(NAME ": Filesystem did not pass sanity check.\n");
+		if (arg_flags & ARG_STRICT_CHECK) {
+			return 3;
+		}
+	}
+	
+	if (arg_flags & ARG_SUPERBLOCK) {
+		print_superblock(filesystem.superblock);
+	}
+	
+	if (arg_flags & ARG_BLOCK_GROUPS) {
+		print_block_groups(&filesystem);
+	}
+	
+	if (arg_flags & ARG_INODE) {
+		print_inode_by_number(&filesystem, inode);
+	}
+
+	ext2_filesystem_fini(&filesystem);
+
+	return 0;
+}
+
+
+static void syntax_print(void)
+{
+	printf("syntax: ext2info --strict-check --superblock --block-groups --inode <i-number> <device_name>\n");
+}
+
+static void print_superblock(ext2_superblock_t *superblock)
+{
+	uint16_t magic;
+	uint32_t first_block;
+	uint32_t block_size;
+	uint32_t fragment_size;
+	uint32_t blocks_per_group;
+	uint32_t fragments_per_group;
+	uint32_t rev_major;
+	uint16_t rev_minor;
+	uint16_t state;
+	uint32_t first_inode;
+	uint16_t inode_size;
+	uint32_t total_blocks;
+	uint32_t reserved_blocks;
+	uint32_t free_blocks;
+	uint32_t total_inodes;
+	uint32_t free_inodes;	
+	uint32_t os;
+	
+	int pos;
+	unsigned char c;
+	
+	magic = ext2_superblock_get_magic(superblock);
+	first_block = ext2_superblock_get_first_block(superblock);
+	block_size = ext2_superblock_get_block_size(superblock);
+	fragment_size = ext2_superblock_get_fragment_size(superblock);
+	blocks_per_group = ext2_superblock_get_blocks_per_group(superblock);
+	fragments_per_group = ext2_superblock_get_fragments_per_group(superblock);
+	rev_major = ext2_superblock_get_rev_major(superblock);
+	rev_minor = ext2_superblock_get_rev_minor(superblock);
+	state = ext2_superblock_get_state(superblock);
+	first_inode = ext2_superblock_get_first_inode(superblock);
+	inode_size = ext2_superblock_get_inode_size(superblock);
+	total_blocks = ext2_superblock_get_total_block_count(superblock);
+	reserved_blocks = ext2_superblock_get_reserved_block_count(superblock);
+	free_blocks = ext2_superblock_get_free_block_count(superblock);
+	total_inodes = ext2_superblock_get_total_inode_count(superblock);
+	free_inodes = ext2_superblock_get_free_inode_count(superblock);
+	os = ext2_superblock_get_os(superblock);
+	
+	printf("Superblock:\n");
+	
+	if (magic == EXT2_SUPERBLOCK_MAGIC) {
+		printf("  Magic value: %X (correct)\n", magic);
+	}
+	else {
+		printf("  Magic value: %X (incorrect)\n", magic);
+	}
+	
+	printf("  Revision: %u.%hu\n", rev_major, rev_minor);
+	printf("  State: %hu\n", state);
+	printf("  Creator OS: %u\n", os);
+	printf("  First block: %u\n", first_block);
+	printf("  Block size: %u bytes (%u KiB)\n", block_size, block_size/1024);
+	printf("  Blocks per group: %u\n", blocks_per_group);
+	printf("  Total blocks: %u\n", total_blocks);
+	printf("  Reserved blocks: %u\n", reserved_blocks);
+	printf("  Free blocks: %u\n", free_blocks);
+	printf("  Fragment size: %u bytes (%u KiB)\n", fragment_size,
+	    fragment_size/1024);
+	printf("  Fragments per group: %u\n", fragments_per_group);
+	printf("  First inode: %u\n", first_inode);
+	printf("  Inode size: %hu bytes\n", inode_size);
+	printf("  Total inodes: %u\n", total_inodes);
+	printf("  Free inodes: %u\n", free_inodes);
+	
+	
+	if (rev_major == 1) {
+		printf("  UUID: ");
+		for (pos = 0; pos < 16; pos++) {
+			printf("%02x", superblock->uuid[pos]);
+		}
+		printf("\n");
+		
+		printf("  Volume label: ");
+		for (pos = 0; pos < 16; pos++) {
+			c = superblock->volume_name[pos];
+			if (c >= 32 && c < 128) {
+				putchar(c);
+			}
+			else {
+				putchar(' ');
+			}
+		}
+		printf("\n");
+	}
+	
+}
+
+void print_block_groups(ext2_filesystem_t *filesystem)
+{
+	uint32_t block_group_count;
+	uint32_t i;
+	ext2_block_group_ref_t *block_group_ref;
+	int rc;
+	
+	printf("Block groups:\n");
+	
+	block_group_count = ext2_superblock_get_block_group_count(
+	    filesystem->superblock);
+	
+	for (i = 0; i < block_group_count; i++) {
+		printf("  Block group %u\n", i);
+		rc = ext2_filesystem_get_block_group_ref(filesystem, i, &block_group_ref);
+		if (rc != EOK) {
+			printf("    Failed reading block group\n");
+			continue;
+		}
+		
+		print_block_group(block_group_ref->block_group);
+		
+		rc = ext2_filesystem_put_block_group_ref(block_group_ref);
+		if (rc != EOK) {
+			printf("    Failed freeing block group\n");
+		}
+	}
+	
+}
+
+void print_block_group(ext2_block_group_t *bg)
+{
+	uint32_t block_bitmap_block;
+	uint32_t inode_bitmap_block;
+	uint32_t inode_table_first_block;
+	uint16_t free_block_count;
+	uint16_t free_inode_count;
+	uint16_t directory_inode_count;
+	
+	block_bitmap_block = ext2_block_group_get_block_bitmap_block(bg);
+	inode_bitmap_block = ext2_block_group_get_inode_bitmap_block(bg);
+	inode_table_first_block = ext2_block_group_get_inode_table_first_block(bg);
+	free_block_count = ext2_block_group_get_free_block_count(bg);
+	free_inode_count = ext2_block_group_get_free_inode_count(bg);
+	directory_inode_count = ext2_block_group_get_directory_inode_count(bg);
+	
+	printf("    Block bitmap block: %u\n", block_bitmap_block);
+	printf("    Inode bitmap block: %u\n", inode_bitmap_block);
+	printf("    Inode table's first block: %u\n", inode_table_first_block);
+	printf("    Free blocks: %u\n", free_block_count);
+	printf("    Free inodes: %u\n", free_inode_count);
+	printf("    Directory inodes: %u\n", directory_inode_count);
+}
+
+void print_inode_by_number(ext2_filesystem_t *fs, uint32_t inode)
+{
+	int rc;
+	ext2_inode_ref_t *inode_ref;
+	
+	printf("Inode %u\n", inode);
+	
+	rc = ext2_filesystem_get_inode_ref(fs, inode, &inode_ref);
+	if (rc != EOK) {
+		printf("  Failed getting inode ref\n");
+		return;
+	}
+	
+	print_inode(fs, inode_ref->inode);
+	
+	rc = ext2_filesystem_put_inode_ref(inode_ref);
+	if (rc != EOK) {
+		printf("  Failed putting inode ref\n");
+	}
+}
+
+void print_inode(ext2_filesystem_t *fs, ext2_inode_t *inode)
+{
+	uint32_t mode;
+	uint32_t user_id;
+	uint32_t group_id;
+	uint64_t size;
+	uint16_t usage_count;
+	uint32_t flags;
+	uint16_t access;
+	const char *type;
+	uint32_t block;
+	int i;
+	bool all_blocks = false;
+	
+	mode = ext2_inode_get_mode(fs->superblock, inode);
+	user_id = ext2_inode_get_user_id(fs->superblock, inode);
+	group_id = ext2_inode_get_group_id(fs->superblock, inode);
+	size = ext2_inode_get_size(fs->superblock, inode);
+	usage_count = ext2_inode_get_usage_count(inode);
+	flags = ext2_inode_get_flags(inode);
+	
+	type = "Unknown";
+	if ((mode & EXT2_INODE_MODE_BLOCKDEV) == EXT2_INODE_MODE_BLOCKDEV) {
+		type = "Block device";
+	}
+	else if (mode & EXT2_INODE_MODE_FIFO) {
+		type = "Fifo (pipe)";
+	}
+	else if (mode & EXT2_INODE_MODE_CHARDEV) {
+		type = "Character device";
+	}
+	else if (mode & EXT2_INODE_MODE_DIRECTORY) {
+		type = "Directory";
+	}
+	else if (mode & EXT2_INODE_MODE_FILE) {
+		type = "File";
+	}
+	else if (mode & EXT2_INODE_MODE_SOFTLINK) {
+		type = "Soft link";
+	}
+	else if (mode & EXT2_INODE_MODE_SOCKET) {
+		type = "Socket";
+	}
+	
+	access = mode & EXT2_INODE_MODE_ACCESS_MASK;
+	
+	printf("  Mode: %08x (Type: %s, Access bits: %04ho)\n", mode, type, access);
+	printf("  User ID: %u\n", user_id);
+	printf("  Group ID: %u\n", group_id);
+	printf("  Size: %" PRIu64 "\n", size);
+	printf("  Usage (link) count: %u\n", usage_count);
+	printf("  Flags: %u\n", flags);
+	printf("  Block list: ");
+	for (i = 0; i < 12; i++) {
+		block = ext2_inode_get_direct_block(inode, i);
+		if (block == 0) {
+			all_blocks = true;
+			break;
+		}
+		printf("%u ", block);
+	}
+	if (!all_blocks) {
+		printf(" and more...");
+	}
+	printf("\n");
+}
+
+/**
+ * @}
+ */
Index: uspace/app/redir/redir.c
===================================================================
--- uspace/app/redir/redir.c	(revision 664af7080d443cca0efb84c002b3d440ca6f67c1)
+++ uspace/app/redir/redir.c	(revision f483a1595e01c6dce011869a0e03969833df9750)
@@ -49,5 +49,5 @@
 static void usage(void)
 {
-	printf("Usage: %s [-i <stdin>] [-o <stdout>] [-e <stderr>] -- <cmd> [args ...]\n",
+	fprintf(stderr, "Usage: %s [-i <stdin>] [-o <stdout>] [-e <stderr>] -- <cmd> [args ...]\n",
 	    NAME);
 }
@@ -83,5 +83,5 @@
 	args = (const char **) calloc(argc + 1, sizeof(char *));
 	if (!args) {
-		printf("No memory available\n");
+		fprintf(stderr, "No memory available\n");
 		return 0;
 	}
@@ -98,6 +98,7 @@
 	
 	if (rc != EOK) {
-		printf("%s: Error spawning %s (%s)\n", NAME, argv[0],
+		fprintf(stderr, "%s: Error spawning %s (%s)\n", NAME, argv[0],
 		    str_error(rc));
+		return 0;
 	}
 	
Index: uspace/lib/block/libblock.c
===================================================================
--- uspace/lib/block/libblock.c	(revision 664af7080d443cca0efb84c002b3d440ca6f67c1)
+++ uspace/lib/block/libblock.c	(revision f483a1595e01c6dce011869a0e03969833df9750)
@@ -2,4 +2,5 @@
  * Copyright (c) 2008 Jakub Jermar
  * Copyright (c) 2008 Martin Decky
+ * Copyright (c) 2011 Martin Sucha
  * All rights reserved.
  *
@@ -810,4 +811,56 @@
 }
 
+/** Read bytes directly from the device (bypass cache)
+ * 
+ * @param devmap_handle	Device handle of the block device.
+ * @param abs_offset	Absolute offset in bytes where to start reading
+ * @param bytes			Number of bytes to read
+ * @param data			Buffer that receives the data
+ * 
+ * @return		EOK on success or negative error code on failure.
+ */
+int block_read_bytes_direct(devmap_handle_t devmap_handle, aoff64_t abs_offset,
+    size_t bytes, void *data)
+{
+	int rc;
+	size_t phys_block_size;
+	size_t buf_size;
+	void *buffer;
+	aoff64_t first_block;
+	aoff64_t last_block;
+	size_t blocks;
+	size_t offset;
+	
+	rc = block_get_bsize(devmap_handle, &phys_block_size);
+	if (rc != EOK) {
+		return rc;
+	}
+	
+	// calculate data position and required space
+	first_block = abs_offset / phys_block_size;
+	offset = abs_offset % phys_block_size;
+	last_block = (abs_offset + bytes - 1) / phys_block_size;
+	blocks = last_block - first_block + 1;
+	buf_size = blocks * phys_block_size;
+	
+	// read the data into memory
+	buffer = malloc(buf_size);
+	if (buffer == NULL) {
+		return ENOMEM;
+	}
+	
+	rc = block_read_direct(devmap_handle, first_block, blocks, buffer);
+	if (rc != EOK) {
+		free(buffer);
+		return rc;
+	}
+	
+	// copy the data from the buffer
+	memcpy(data, buffer + offset, bytes);
+	free(buffer);
+	
+	return EOK;
+}
+
 /** Read blocks from block device.
  *
Index: uspace/lib/block/libblock.h
===================================================================
--- uspace/lib/block/libblock.h	(revision 664af7080d443cca0efb84c002b3d440ca6f67c1)
+++ uspace/lib/block/libblock.h	(revision f483a1595e01c6dce011869a0e03969833df9750)
@@ -2,4 +2,5 @@
  * Copyright (c) 2008 Jakub Jermar
  * Copyright (c) 2008 Martin Decky 
+ * Copyright (c) 2011 Martin Sucha 
  * All rights reserved.
  *
@@ -113,4 +114,5 @@
 extern int block_get_nblocks(devmap_handle_t, aoff64_t *);
 extern int block_read_direct(devmap_handle_t, aoff64_t, size_t, void *);
+extern int block_read_bytes_direct(devmap_handle_t, aoff64_t, size_t, void *);
 extern int block_write_direct(devmap_handle_t, aoff64_t, size_t, const void *);
 
Index: uspace/lib/ext2/Makefile
===================================================================
--- uspace/lib/ext2/Makefile	(revision f483a1595e01c6dce011869a0e03969833df9750)
+++ uspace/lib/ext2/Makefile	(revision f483a1595e01c6dce011869a0e03969833df9750)
@@ -0,0 +1,42 @@
+#
+# Copyright (c) 2005 Martin Decky
+# Copyright (c) 2007 Jakub Jermar
+# Copyright (c) 2010 Martin Sucha
+# 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.
+#
+
+USPACE_PREFIX = ../..
+LIBRARY = libext2
+EXTRA_CFLAGS = -I$(LIBBLOCK_PREFIX)
+LIBS = $(LIBBLOCK_PREFIX)/libblock.a
+
+SOURCES = \
+	libext2_filesystem.c \
+	libext2_superblock.c \
+	libext2_block_group.c \
+	libext2_inode.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/lib/ext2/libext2.h
===================================================================
--- uspace/lib/ext2/libext2.h	(revision f483a1595e01c6dce011869a0e03969833df9750)
+++ uspace/lib/ext2/libext2.h	(revision f483a1595e01c6dce011869a0e03969833df9750)
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2011 Martin Sucha
+ * 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 libext2
+ * @{
+ */
+/**
+ * @file
+ */
+
+#ifndef LIBEXT2_LIBEXT2_H_
+#define LIBEXT2_LIBEXT2_H_
+
+#include "libext2_superblock.h"
+#include "libext2_block_group.h"
+#include "libext2_inode.h"
+#include "libext2_filesystem.h"
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/ext2/libext2_block_group.c
===================================================================
--- uspace/lib/ext2/libext2_block_group.c	(revision f483a1595e01c6dce011869a0e03969833df9750)
+++ uspace/lib/ext2/libext2_block_group.c	(revision f483a1595e01c6dce011869a0e03969833df9750)
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2011 Martin Sucha
+ * 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 libext2
+ * @{
+ */
+/**
+ * @file
+ */
+
+#include "libext2.h"
+#include "libext2_block_group.h"
+#include <byteorder.h>
+
+/**
+ * Get block ID corresponding to the block bitmap of this block group
+ * 
+ * @param bg pointer to block group descriptor
+ */
+inline uint32_t	ext2_block_group_get_block_bitmap_block(ext2_block_group_t *bg)
+{
+	return uint32_t_le2host(bg->block_bitmap_block);
+}
+
+/**
+ * Get block ID corresponding to the inode bitmap of this block group
+ * 
+ * @param bg pointer to block group descriptor
+ */
+inline uint32_t	ext2_block_group_get_inode_bitmap_block(ext2_block_group_t *bg)
+{
+	return uint32_t_le2host(bg->inode_bitmap_block);
+}
+
+/**
+ * Get block ID of first block in inode table
+ * 
+ * @param bg pointer to block group descriptor
+ */
+inline uint32_t	ext2_block_group_get_inode_table_first_block(ext2_block_group_t *bg)
+{
+	return uint32_t_le2host(bg->inode_table_first_block);
+}
+
+/**
+ * Get amount of free blocks in this block group
+ * 
+ * @param bg pointer to block group descriptor
+ */
+inline uint16_t	ext2_block_group_get_free_block_count(ext2_block_group_t *bg)
+{
+	return uint16_t_le2host(bg->free_block_count);
+}
+
+/**
+ * Get amount of free inodes in this block group
+ * 
+ * @param bg pointer to block group descriptor
+ */
+inline uint16_t	ext2_block_group_get_free_inode_count(ext2_block_group_t *bg)
+{
+	return uint16_t_le2host(bg->free_inode_count);
+}
+
+/**
+ * Get amount of inodes allocated for directories
+ * 
+ * @param bg pointer to block group descriptor
+ */
+inline uint16_t	ext2_block_group_get_directory_inode_count(ext2_block_group_t *bg)
+{
+	return uint16_t_le2host(bg->directory_inode_count);
+}
+
+
+/** @}
+ */
Index: uspace/lib/ext2/libext2_block_group.h
===================================================================
--- uspace/lib/ext2/libext2_block_group.h	(revision f483a1595e01c6dce011869a0e03969833df9750)
+++ uspace/lib/ext2/libext2_block_group.h	(revision f483a1595e01c6dce011869a0e03969833df9750)
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2011 Martin Sucha
+ * 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 libext2
+ * @{
+ */
+/**
+ * @file
+ */
+
+#ifndef LIBEXT2_LIBEXT2_BLOCK_GROUP_H_
+#define LIBEXT2_LIBEXT2_BLOCK_GROUP_H_
+
+#include <libblock.h>
+
+typedef struct ext2_block_group {
+	uint32_t block_bitmap_block; // Block ID for block bitmap
+	uint32_t inode_bitmap_block; // Block ID for inode bitmap
+	uint32_t inode_table_first_block; // Block ID of first block of inode table 
+	uint16_t free_block_count; // Count of free blocks
+	uint16_t free_inode_count; // Count of free inodes
+	uint16_t directory_inode_count; // Number of inodes allocated to directories
+} ext2_block_group_t;
+
+typedef struct ext2_block_group_ref {
+	block_t *block; // Reference to a block containing this block group descr
+	ext2_block_group_t *block_group;
+} ext2_block_group_ref_t;
+
+#define EXT2_BLOCK_GROUP_DESCRIPTOR_SIZE 32
+
+inline uint32_t	ext2_block_group_get_block_bitmap_block(ext2_block_group_t *);
+inline uint32_t	ext2_block_group_get_inode_bitmap_block(ext2_block_group_t *);
+inline uint32_t	ext2_block_group_get_inode_table_first_block(ext2_block_group_t *);
+inline uint16_t	ext2_block_group_get_free_block_count(ext2_block_group_t *);
+inline uint16_t	ext2_block_group_get_free_inode_count(ext2_block_group_t *);
+inline uint16_t	ext2_block_group_get_directory_inode_count(ext2_block_group_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/ext2/libext2_filesystem.c
===================================================================
--- uspace/lib/ext2/libext2_filesystem.c	(revision f483a1595e01c6dce011869a0e03969833df9750)
+++ uspace/lib/ext2/libext2_filesystem.c	(revision f483a1595e01c6dce011869a0e03969833df9750)
@@ -0,0 +1,269 @@
+/*
+ * Copyright (c) 2011 Martin Sucha
+ * 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 libext2
+ * @{
+ */
+/**
+ * @file
+ */
+
+#include "libext2_filesystem.h"
+#include "libext2_superblock.h"
+#include "libext2_block_group.h"
+#include "libext2_inode.h"
+#include <errno.h>
+#include <libblock.h>
+#include <malloc.h>
+
+/**
+ * Initialize an instance of filesystem on the device.
+ * This function reads superblock from the device and
+ * initializes libblock cache with appropriate logical block size.
+ * 
+ * @param fs			Pointer to ext2_filesystem_t to initialize
+ * @param devmap_handle	Device handle of the block device
+ * 
+ * @return 		EOK on success or negative error code on failure
+ */
+int ext2_filesystem_init(ext2_filesystem_t *fs, devmap_handle_t devmap_handle)
+{
+	int rc;
+	ext2_superblock_t *temp_superblock;
+	size_t block_size;
+	
+	fs->device = devmap_handle;
+	
+	rc = block_init(fs->device, 2048);
+	if (rc != EOK) {
+		return rc;
+	}
+	
+	rc = ext2_superblock_read_direct(fs->device, &temp_superblock);
+	if (rc != EOK) {
+		block_fini(fs->device);
+		return rc;
+	}
+	
+	block_size = ext2_superblock_get_block_size(temp_superblock);
+	
+	if (block_size > EXT2_MAX_BLOCK_SIZE) {
+		block_fini(fs->device);
+		return ENOTSUP;
+	}
+	
+	rc = block_cache_init(devmap_handle, block_size, 0, CACHE_MODE_WT);
+	if (rc != EOK) {
+		block_fini(fs->device);
+		return rc;
+	}
+	
+	fs->superblock = temp_superblock;
+	
+	return EOK; 
+}
+
+/**
+ * Check filesystem for sanity
+ * 
+ * @param fs			Pointer to ext2_filesystem_t to check
+ * @return 		EOK on success or negative error code on failure
+ */
+int ext2_filesystem_check_sanity(ext2_filesystem_t *fs)
+{
+	int rc;
+	
+	rc = ext2_superblock_check_sanity(fs->superblock);
+	if (rc != EOK) {
+		return rc;
+	}
+	
+	return EOK;
+}
+
+/**
+ * Get a reference to block descriptor
+ * 
+ * @param fs Pointer to filesystem information
+ * @param bgid Index of block group to find
+ * @param ref Pointer where to store pointer to block group reference
+ * 
+ * @return 		EOK on success or negative error code on failure
+ */
+int ext2_filesystem_get_block_group_ref(ext2_filesystem_t *fs, uint32_t bgid,
+    ext2_block_group_ref_t **ref)
+{
+	int rc;
+	aoff64_t block_id;
+	uint32_t descriptors_per_block;
+	size_t offset;
+	ext2_block_group_ref_t *newref;
+	
+	newref = malloc(sizeof(ext2_block_group_ref_t));
+	if (newref == NULL) {
+		return ENOMEM;
+	}
+	
+	descriptors_per_block = ext2_superblock_get_block_size(fs->superblock)
+	    / EXT2_BLOCK_GROUP_DESCRIPTOR_SIZE;
+	
+	// Block group descriptor table starts at the next block after superblock
+	block_id = ext2_superblock_get_first_block(fs->superblock) + 1;
+	
+	// Find the block containing the descriptor we are looking for
+	block_id += bgid / descriptors_per_block;
+	offset = (bgid % descriptors_per_block) * EXT2_BLOCK_GROUP_DESCRIPTOR_SIZE;
+	
+	rc = block_get(&newref->block, fs->device, block_id, 0);
+	if (rc != EOK) {
+		free(newref);
+		return rc;
+	}
+	
+	newref->block_group = newref->block->data + offset;
+	
+	*ref = newref;
+	
+	return EOK;
+}
+
+/**
+ * Free a reference to block group
+ * 
+ * @param ref Pointer to block group reference to free
+ * 
+ * @return 		EOK on success or negative error code on failure
+ */
+int ext2_filesystem_put_block_group_ref(ext2_block_group_ref_t *ref)
+{
+	int rc;
+	
+	rc = block_put(ref->block);
+	free(ref);
+	
+	return rc;
+}
+
+/**
+ * Get a reference to inode
+ * 
+ * @param fs Pointer to filesystem information
+ * @param index The index number of the inode
+ * @param ref Pointer where to store pointer to inode reference
+ * 
+ * @return 		EOK on success or negative error code on failure
+ */
+int ext2_filesystem_get_inode_ref(ext2_filesystem_t *fs, uint32_t index,
+    ext2_inode_ref_t **ref)
+{
+	int rc;
+	aoff64_t block_id;
+	uint32_t block_group;
+	uint32_t offset_in_group;
+	uint32_t byte_offset_in_group;
+	size_t offset_in_block;
+	uint32_t inodes_per_group;
+	uint32_t inode_table_start;
+	uint16_t inode_size;
+	uint32_t block_size;
+	ext2_block_group_ref_t *bg_ref;
+	ext2_inode_ref_t *newref;
+	
+	newref = malloc(sizeof(ext2_inode_ref_t));
+	if (newref == NULL) {
+		return ENOMEM;
+	}
+	
+	inodes_per_group = ext2_superblock_get_inodes_per_group(fs->superblock);
+	
+	// inode numbers are 1-based
+	index -= 1;
+	block_group = index / inodes_per_group;
+	offset_in_group = index % inodes_per_group;
+	
+	rc = ext2_filesystem_get_block_group_ref(fs, block_group, &bg_ref);
+	if (rc != EOK) {
+		free(newref);
+		return rc;
+	}
+	
+	inode_table_start = ext2_block_group_get_inode_table_first_block(
+	    bg_ref->block_group);
+	
+	inode_size = ext2_superblock_get_inode_size(fs->superblock);
+	block_size = ext2_superblock_get_block_size(fs->superblock);
+	
+	byte_offset_in_group = offset_in_group * inode_size;
+	
+	block_id = inode_table_start + (byte_offset_in_group / block_size);
+	offset_in_block = byte_offset_in_group % block_size;
+	
+	rc = block_get(&newref->block, fs->device, block_id, 0);
+	if (rc != EOK) {
+		free(newref);
+		return rc;
+	}
+	
+	newref->inode = newref->block->data + offset_in_block;
+	
+	*ref = newref;
+	
+	return EOK;
+}
+
+/**
+ * Free a reference to inode
+ * 
+ * @param ref Pointer to inode reference to free
+ * 
+ * @return 		EOK on success or negative error code on failure
+ */
+int ext2_filesystem_put_inode_ref(ext2_inode_ref_t *ref)
+{
+	int rc;
+	
+	rc = block_put(ref->block);
+	free(ref);
+	
+	return rc;
+}
+
+/**
+ * Finalize an instance of filesystem
+ * 
+ * @param fs Pointer to ext2_filesystem_t to finalize
+ */
+void ext2_filesystem_fini(ext2_filesystem_t *fs)
+{
+	free(fs->superblock);
+	block_fini(fs->device);
+}
+
+
+/** @}
+ */
Index: uspace/lib/ext2/libext2_filesystem.h
===================================================================
--- uspace/lib/ext2/libext2_filesystem.h	(revision f483a1595e01c6dce011869a0e03969833df9750)
+++ uspace/lib/ext2/libext2_filesystem.h	(revision f483a1595e01c6dce011869a0e03969833df9750)
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2011 Martin Sucha
+ * 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 libext2
+ * @{
+ */
+/**
+ * @file
+ */
+
+#ifndef LIBEXT2_LIBEXT2_FILESYSTEM_H_
+#define LIBEXT2_LIBEXT2_FILESYSTEM_H_
+
+#include <libblock.h>
+#include "libext2_superblock.h"
+#include "libext2_block_group.h"
+#include "libext2_inode.h"
+
+typedef struct ext2_filesystem {
+	devmap_handle_t		device;
+	ext2_superblock_t *	superblock;
+} ext2_filesystem_t;
+
+// allow maximum this block size
+#define EXT2_MAX_BLOCK_SIZE			8096
+#define EXT2_REV0_FIRST_INODE		11
+#define EXT2_REV0_INODE_SIZE		128
+
+extern int ext2_filesystem_init(ext2_filesystem_t *, devmap_handle_t);
+extern int ext2_filesystem_check_sanity(ext2_filesystem_t *);
+extern int ext2_filesystem_get_block_group_ref(ext2_filesystem_t *, uint32_t, 
+    ext2_block_group_ref_t **);
+extern int ext2_filesystem_put_block_group_ref(ext2_block_group_ref_t *);
+extern int ext2_filesystem_get_inode_ref(ext2_filesystem_t *, uint32_t,
+    ext2_inode_ref_t **);
+extern int ext2_filesystem_put_inode_ref(ext2_inode_ref_t *);
+extern void ext2_filesystem_fini(ext2_filesystem_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/ext2/libext2_inode.c
===================================================================
--- uspace/lib/ext2/libext2_inode.c	(revision f483a1595e01c6dce011869a0e03969833df9750)
+++ uspace/lib/ext2/libext2_inode.c	(revision f483a1595e01c6dce011869a0e03969833df9750)
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2011 Martin Sucha
+ * 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 libext2
+ * @{
+ */
+/**
+ * @file
+ */
+
+#include "libext2.h"
+#include "libext2_inode.h"
+#include "libext2_superblock.h"
+#include <byteorder.h>
+
+/**
+ * Get mode stored in the inode
+ * 
+ * @param inode pointer to inode
+ */
+inline uint32_t ext2_inode_get_mode(ext2_superblock_t *sb, ext2_inode_t *inode)
+{
+	if (ext2_superblock_get_os(sb) == EXT2_SUPERBLOCK_OS_HURD) {
+		return ((uint32_t)uint16_t_le2host(inode->mode_high)) << 16 |
+		    ((uint32_t)uint16_t_le2host(inode->mode));
+	}
+	return uint16_t_le2host(inode->mode);
+}
+
+/**
+ * Get uid this inode is belonging to
+ * 
+ * @param inode pointer to inode
+ */
+inline uint32_t ext2_inode_get_user_id(ext2_superblock_t *sb, ext2_inode_t *inode)
+{
+	uint32_t os = ext2_superblock_get_os(sb);
+	if (os == EXT2_SUPERBLOCK_OS_LINUX || os == EXT2_SUPERBLOCK_OS_HURD) {
+		return ((uint32_t)uint16_t_le2host(inode->user_id_high)) << 16 |
+		    ((uint32_t)uint16_t_le2host(inode->user_id));
+	}
+	return uint16_t_le2host(inode->user_id);
+}
+
+/**
+ * Get size of file
+ * 
+ * For regular files in revision 1 and later, the high 32 bits of
+ * file size are stored in inode->size_high and are 0 otherwise
+ * 
+ * @param inode pointer to inode
+ */
+inline uint64_t ext2_inode_get_size(ext2_superblock_t *sb, ext2_inode_t *inode)
+{
+	uint32_t major_rev = ext2_superblock_get_rev_major(sb);
+	uint32_t mode = ext2_inode_get_mode(sb, inode);
+	
+	if (major_rev > 0 && mode & EXT2_INODE_MODE_FILE) {
+		return ((uint64_t)uint32_t_le2host(inode->size_high)) << 32 |
+		    ((uint64_t)uint32_t_le2host(inode->size));
+	}
+	return uint32_t_le2host(inode->size);
+}
+
+/**
+ * Get gid this inode belongs to
+ * 
+ * For Linux and Hurd, the high 16 bits are stored in OS dependent part
+ * of inode structure
+ * 
+ * @param inode pointer to inode
+ */
+inline uint32_t ext2_inode_get_group_id(ext2_superblock_t *sb, ext2_inode_t *inode)
+{
+	uint32_t os = ext2_superblock_get_os(sb);
+	if (os == EXT2_SUPERBLOCK_OS_LINUX || os == EXT2_SUPERBLOCK_OS_HURD) {
+		return ((uint32_t)uint16_t_le2host(inode->group_id_high)) << 16 |
+		    ((uint32_t)uint16_t_le2host(inode->group_id));
+	}
+	return uint16_t_le2host(inode->group_id);
+}
+
+/**
+ * Get usage count (i.e. hard link count)
+ * A value of 1 is common, while 0 means that the inode should be freed
+ * 
+ * @param inode pointer to inode
+ */
+inline uint16_t ext2_inode_get_usage_count(ext2_inode_t *inode)
+{
+	return uint16_t_le2host(inode->usage_count);
+}
+
+/**
+ * Get number of 512-byte data blocks allocated for contents of the file
+ * represented by this inode.
+ * This should be multiple of block size unless fragments are used.
+ * 
+ * @param inode pointer to inode
+ */
+inline uint32_t ext2_inode_get_reserved_512_blocks(ext2_inode_t *inode)
+{
+	return uint32_t_le2host(inode->reserved_512_blocks);
+}
+
+/**
+ * Get inode flags
+ * 
+ * @param inode pointer to inode
+ */
+inline uint32_t ext2_inode_get_flags(ext2_inode_t *inode) {
+	return uint32_t_le2host(inode->flags);
+}
+
+/**
+ * Get direct block ID
+ * 
+ * @param inode pointer to inode
+ * @param idx Index to block. Valid values are 0 <= idx < 12
+ */
+inline uint32_t ext2_inode_get_direct_block(ext2_inode_t *inode, uint8_t idx)
+{
+	return uint32_t_le2host(inode->direct_blocks[idx]);
+}
+
+/**
+ * Get indirect block ID
+ * 
+ * @param inode pointer to inode
+ */
+inline uint32_t ext2_inode_get_single_indirect_block(ext2_inode_t *inode)
+{
+	return uint32_t_le2host(inode->single_indirect_block);
+}
+
+/**
+ * Get double indirect block ID
+ * 
+ * @param inode pointer to inode
+ */
+inline uint32_t ext2_inode_get_double_indirect_block(ext2_inode_t *inode)
+{
+	return uint32_t_le2host(inode->double_indirect_block);
+}
+
+/**
+ * Get triple indirect block ID
+ * 
+ * @param inode pointer to inode
+ */
+inline uint32_t ext2_inode_get_triple_indirect_block(ext2_inode_t *inode)
+{
+	return uint32_t_le2host(inode->triple_indirect_block);
+}
+
+
+
+/** @}
+ */
Index: uspace/lib/ext2/libext2_inode.h
===================================================================
--- uspace/lib/ext2/libext2_inode.h	(revision f483a1595e01c6dce011869a0e03969833df9750)
+++ uspace/lib/ext2/libext2_inode.h	(revision f483a1595e01c6dce011869a0e03969833df9750)
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2011 Martin Sucha
+ * 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 libext2
+ * @{
+ */
+/**
+ * @file
+ */
+
+#ifndef LIBEXT2_LIBEXT2_INODE_H_
+#define LIBEXT2_LIBEXT2_INODE_H_
+
+#include <libblock.h>
+#include "libext2_superblock.h"
+
+typedef struct ext2_inode {
+	uint16_t mode;
+	uint16_t user_id;
+	uint32_t size;
+	uint8_t unused[16];
+	uint16_t group_id;
+	uint16_t usage_count; // Hard link count, when 0 the inode is to be freed
+	uint32_t reserved_512_blocks; // Size of this inode in 512-byte blocks
+	uint32_t flags;
+	uint8_t unused2[4];
+	uint32_t direct_blocks[12]; // Direct block ids stored in this inode
+	uint32_t single_indirect_block;
+	uint32_t double_indirect_block;
+	uint32_t triple_indirect_block;
+	uint32_t version;
+	uint32_t file_acl;
+	union {
+		uint32_t dir_acl;
+		uint32_t size_high; // For regular files in version >= 1
+	} __attribute__ ((packed));
+	uint8_t unused3[6];
+	uint16_t mode_high; // Hurd only
+	uint16_t user_id_high; // Linux/Hurd only
+	uint16_t group_id_high; // Linux/Hurd only
+} __attribute__ ((packed)) ext2_inode_t;
+
+#define EXT2_INODE_MODE_FIFO		0x1000
+#define EXT2_INODE_MODE_CHARDEV		0x2000
+#define EXT2_INODE_MODE_DIRECTORY	0x4000
+#define EXT2_INODE_MODE_BLOCKDEV	0x6000
+#define EXT2_INODE_MODE_FILE		0x8000
+#define EXT2_INODE_MODE_SOFTLINK	0xA000
+#define EXT2_INODE_MODE_SOCKET		0xC000
+#define EXT2_INODE_MODE_ACCESS_MASK	0x0FFF
+
+typedef struct ext2_inode_ref {
+	block_t *block; // Reference to a block containing this inode
+	ext2_inode_t *inode;
+} ext2_inode_ref_t;
+
+inline uint32_t ext2_inode_get_mode(ext2_superblock_t *, ext2_inode_t *);
+inline uint32_t ext2_inode_get_user_id(ext2_superblock_t *, ext2_inode_t *);
+inline uint64_t ext2_inode_get_size(ext2_superblock_t *, ext2_inode_t *);
+inline uint32_t ext2_inode_get_group_id(ext2_superblock_t *, ext2_inode_t *);
+inline uint16_t ext2_inode_get_usage_count(ext2_inode_t *);
+inline uint32_t ext2_inode_get_reserved_512_blocks(ext2_inode_t *);
+inline uint32_t ext2_inode_get_flags(ext2_inode_t *);
+inline uint32_t ext2_inode_get_direct_block(ext2_inode_t *, uint8_t);
+inline uint32_t ext2_inode_get_single_indirect_block(ext2_inode_t *);
+inline uint32_t ext2_inode_get_double_indirect_block(ext2_inode_t *);
+inline uint32_t ext2_inode_get_triple_indirect_block(ext2_inode_t *);
+
+
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/ext2/libext2_superblock.c
===================================================================
--- uspace/lib/ext2/libext2_superblock.c	(revision f483a1595e01c6dce011869a0e03969833df9750)
+++ uspace/lib/ext2/libext2_superblock.c	(revision f483a1595e01c6dce011869a0e03969833df9750)
@@ -0,0 +1,379 @@
+/*
+ * Copyright (c) 2011 Martin Sucha
+ * 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 libext2
+ * @{
+ */
+/**
+ * @file
+ */
+
+#include "libext2.h"
+#include <errno.h>
+#include <malloc.h>
+#include <libblock.h>
+#include <byteorder.h>
+
+/**
+ * Return a magic number from ext2 superblock, this should be equal to
+ * EXT_SUPERBLOCK_MAGIC for valid ext2 superblock
+ * 
+ * @param sb pointer to superblock
+ */
+inline uint16_t ext2_superblock_get_magic(ext2_superblock_t *sb)
+{
+	return uint16_t_le2host(sb->magic);
+}
+
+/**
+ * Get the position of first ext2 data block (i.e. the block number
+ * containing main superblock)
+ * 
+ * @param sb pointer to superblock
+ */
+inline uint32_t ext2_superblock_get_first_block(ext2_superblock_t *sb)
+{
+	return uint32_t_le2host(sb->first_block);
+}
+
+/**
+ * Get the number of bits to shift a value of 1024 to the left necessary
+ * to get the size of a block
+ * 
+ * @param sb pointer to superblock
+ */
+inline uint32_t ext2_superblock_get_block_size_log2(ext2_superblock_t *sb)
+{
+	return uint32_t_le2host(sb->block_size_log2);
+}
+
+/**
+ * Get the size of a block, in bytes 
+ * 
+ * @param sb pointer to superblock
+ */
+inline uint32_t ext2_superblock_get_block_size(ext2_superblock_t *sb)
+{
+	return 1024 << ext2_superblock_get_block_size_log2(sb);
+}
+
+/**
+ * Get the number of bits to shift a value of 1024 to the left necessary
+ * to get the size of a fragment (note that this is a signed integer and
+ * if negative, the value should be shifted to the right instead)
+ * 
+ * @param sb pointer to superblock
+ */
+inline int32_t ext2_superblock_get_fragment_size_log2(ext2_superblock_t *sb)
+{
+	return uint32_t_le2host(sb->fragment_size_log2);
+}
+
+/**
+ * Get the size of a fragment, in bytes 
+ * 
+ * @param sb pointer to superblock
+ */
+inline uint32_t ext2_superblock_get_fragment_size(ext2_superblock_t *sb)
+{
+	int32_t log = ext2_superblock_get_fragment_size_log2(sb);
+	if (log >= 0) {
+		return 1024 << log;
+	}
+	else {
+		return 1024 >> -log;
+	}
+}
+
+/**
+ * Get number of blocks per block group
+ * 
+ * @param sb pointer to superblock
+ */
+inline uint32_t ext2_superblock_get_blocks_per_group(ext2_superblock_t *sb)
+{
+	return uint32_t_le2host(sb->blocks_per_group);
+}
+
+/**
+ * Get number of fragments per block group
+ * 
+ * @param sb pointer to superblock
+ */
+inline uint32_t ext2_superblock_get_fragments_per_group(ext2_superblock_t *sb)
+{
+	return uint32_t_le2host(sb->fragments_per_group);
+}
+
+/**
+ * Get filesystem state
+ * 
+ * @param sb pointer to superblock
+ */
+inline uint16_t ext2_superblock_get_state(ext2_superblock_t *sb)
+{
+	return uint16_t_le2host(sb->state);
+}
+
+/**
+ * Get minor revision number
+ * 
+ * @param sb pointer to superblock
+ */
+inline uint16_t ext2_superblock_get_rev_minor(ext2_superblock_t *sb)
+{
+	return uint16_t_le2host(sb->rev_minor);
+}
+
+/**
+ * Get major revision number
+ * 
+ * @param sb pointer to superblock
+ */
+inline uint32_t ext2_superblock_get_rev_major(ext2_superblock_t *sb)
+{
+	return uint32_t_le2host(sb->rev_major);
+}
+
+/**
+ * Get index of first regular inode
+ * 
+ * @param sb pointer to superblock
+ */
+inline uint32_t ext2_superblock_get_first_inode(ext2_superblock_t *sb)
+{
+	if (ext2_superblock_get_rev_major(sb) == 0) {
+		return EXT2_REV0_FIRST_INODE;
+	}
+	return uint32_t_le2host(sb->first_inode);
+}
+
+/**
+ * Get size of inode
+ * 
+ * @param sb pointer to superblock
+ */
+inline uint16_t ext2_superblock_get_inode_size(ext2_superblock_t *sb)
+{
+	if (ext2_superblock_get_rev_major(sb) == 0) {
+		return EXT2_REV0_INODE_SIZE;
+	}
+	return uint32_t_le2host(sb->inode_size);
+}
+
+/**
+ * Get total inode count
+ * 
+ * @param sb pointer to superblock
+ */
+inline uint32_t	ext2_superblock_get_total_inode_count(ext2_superblock_t *sb)
+{
+	return uint32_t_le2host(sb->total_inode_count);
+}
+
+/**
+ * Get total block count
+ * 
+ * @param sb pointer to superblock
+ */
+inline uint32_t	ext2_superblock_get_total_block_count(ext2_superblock_t *sb)
+{
+	return uint32_t_le2host(sb->total_block_count);
+}
+
+/**
+ * Get amount of blocks reserved for the superuser
+ * 
+ * @param sb pointer to superblock
+ */
+inline uint32_t	ext2_superblock_get_reserved_block_count(ext2_superblock_t *sb)
+{
+	return uint32_t_le2host(sb->reserved_block_count);
+}
+
+/**
+ * Get amount of free blocks
+ * 
+ * @param sb pointer to superblock
+ */
+inline uint32_t	ext2_superblock_get_free_block_count(ext2_superblock_t *sb)
+{
+	return uint32_t_le2host(sb->free_block_count);
+}
+
+/**
+ * Get amount of free inodes
+ * 
+ * @param sb pointer to superblock
+ */
+inline uint32_t	ext2_superblock_get_free_inode_count(ext2_superblock_t *sb)
+{
+	return uint32_t_le2host(sb->free_inode_count);
+}
+
+/**
+ * Get id of operating system that created the filesystem
+ * 
+ * @param sb pointer to superblock
+ */
+inline uint32_t	ext2_superblock_get_os(ext2_superblock_t *sb)
+{
+	return uint32_t_le2host(sb->os);
+}
+
+/**
+ * Get count of inodes per block group
+ * 
+ * @param sb pointer to superblock
+ */
+inline uint32_t	ext2_superblock_get_inodes_per_group(ext2_superblock_t *sb)
+{
+	return uint32_t_le2host(sb->inodes_per_group);
+}
+
+/**
+ * Compute count of block groups present in the filesystem
+ * 
+ * Note: This function works only for correct filesystem,
+ *       i.e. it assumes that total block count > 0 and
+ *       blocks per group > 0
+ * 
+ * Example:
+ *   If there are 3 blocks per group, the result should be as follows:
+ *   Total blocks	Result
+ *   1				1
+ *   2				1
+ *   3				1
+ *   4				2
+ * 
+ * 
+ * @param sb pointer to superblock
+ */
+inline uint32_t ext2_superblock_get_block_group_count(ext2_superblock_t *sb)
+{
+	/* We add one to the result because e.g. 2/3 = 0, while to store
+	 *  2 blocks in 3-block group we need one (1) block group
+	 * 
+	 * We subtract one first because of special case that to store e.g.
+	 *  3 blocks in a 3-block group we need only one group
+	 *  (and 3/3 yields one - this is one more that we want as we
+	 *   already add one at the end)
+	 */ 
+	return ((ext2_superblock_get_total_block_count(sb)-1) / 
+	    ext2_superblock_get_blocks_per_group(sb))+1;
+}
+
+/** Read a superblock directly from device (i.e. no libblock cache)
+ * 
+ * @param devmap_handle	Device handle of the block device.
+ * @param superblock	Pointer where to store pointer to new superblock
+ * 
+ * @return		EOK on success or negative error code on failure.
+ */
+int ext2_superblock_read_direct(devmap_handle_t devmap_handle,
+    ext2_superblock_t **superblock)
+{
+	void *data;
+	int rc;
+	
+	data = malloc(EXT2_SUPERBLOCK_SIZE);
+	if (data == NULL) {
+		return ENOMEM;
+	}
+	
+	rc = block_read_bytes_direct(devmap_handle, EXT2_SUPERBLOCK_OFFSET,
+	    EXT2_SUPERBLOCK_SIZE, data);
+	if (rc != EOK) {
+		free(data);
+		return rc;
+	}
+	
+	(*superblock) = data;
+	return EOK;
+}
+
+/** Check a superblock for sanity
+ * 
+ * @param sb	Pointer to superblock
+ * 
+ * @return		EOK on success or negative error code on failure.
+ */
+int ext2_superblock_check_sanity(ext2_superblock_t *sb)
+{
+	if (ext2_superblock_get_magic(sb) != EXT2_SUPERBLOCK_MAGIC) {
+		return ENOTSUP;
+	}
+	
+	if (ext2_superblock_get_rev_major(sb) > 1) {
+		return ENOTSUP;
+	}
+	
+	if (ext2_superblock_get_total_inode_count(sb) == 0) {
+		return ENOTSUP;
+	}
+	
+	if (ext2_superblock_get_total_block_count(sb) == 0) {
+		return ENOTSUP;
+	}
+	
+	if (ext2_superblock_get_blocks_per_group(sb) == 0) {
+		return ENOTSUP;
+	}
+	
+	if (ext2_superblock_get_fragments_per_group(sb) == 0) {
+		return ENOTSUP;
+	}
+	
+	// We don't support fragments smaller than block
+	if (ext2_superblock_get_block_size(sb) != 
+		    ext2_superblock_get_fragment_size(sb)) {
+		return ENOTSUP;
+	}
+	if (ext2_superblock_get_blocks_per_group(sb) !=
+		    ext2_superblock_get_fragments_per_group(sb)) {
+		return ENOTSUP;
+	}
+	
+	if (ext2_superblock_get_inodes_per_group(sb) == 0) {
+		return ENOTSUP;
+	}
+	
+	if (ext2_superblock_get_inode_size(sb) < 128) {
+		return ENOTSUP;
+	}
+	
+	if (ext2_superblock_get_first_inode(sb) < 11) {
+		return ENOTSUP;
+	}
+	
+	return EOK;
+}
+
+
+/** @}
+ */
Index: uspace/lib/ext2/libext2_superblock.h
===================================================================
--- uspace/lib/ext2/libext2_superblock.h	(revision f483a1595e01c6dce011869a0e03969833df9750)
+++ uspace/lib/ext2/libext2_superblock.h	(revision f483a1595e01c6dce011869a0e03969833df9750)
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2011 Martin Sucha
+ * 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 libext2
+ * @{
+ */
+/**
+ * @file
+ */
+
+#ifndef LIBEXT2_LIBEXT2_SUPERBLOCK_H_
+#define LIBEXT2_LIBEXT2_SUPERBLOCK_H_
+
+#include <libblock.h>
+
+typedef struct ext2_superblock {
+	uint32_t	total_inode_count; // Total number of inodes
+	uint32_t	total_block_count; // Total number of blocks
+	uint32_t	reserved_block_count; // Total number of reserved blocks
+	uint32_t	free_block_count; // Total number of free blocks
+	uint32_t	free_inode_count; // Total number of free inodes
+	uint32_t	first_block; // Block containing the superblock (either 0 or 1)
+	uint32_t	block_size_log2; // log_2(block_size)
+	int32_t		fragment_size_log2; // log_2(fragment size)
+	uint32_t	blocks_per_group; // Number of blocks in one block group
+	uint32_t	fragments_per_group; // Number of fragments per block group
+	uint32_t	inodes_per_group; // Number of inodes per block group
+	uint8_t		unused2[12];
+	uint16_t	magic; // Magic value
+	uint16_t	state; // State (mounted/unmounted)
+	uint16_t	error_behavior; // What to do when errors are encountered
+	uint16_t	rev_minor; // Minor revision level
+	uint8_t		unused3[8];
+	uint32_t	os; // OS that created the filesystem
+	uint32_t	rev_major; // Major revision level
+	uint8_t		unused4[4];
+	
+	// Following is for ext2 revision 1 only
+	uint32_t	first_inode;
+	uint16_t	inode_size;
+	uint8_t		unused5[14];
+	uint8_t		uuid[16]; // UUID TODO: Create a library for UUIDs
+	uint8_t		volume_name[16];
+
+// TODO: add __attribute__((aligned(...)) for better performance?
+//       (it is necessary to ensure the superblock is correctly aligned then
+//        though)
+} __attribute__ ((packed)) ext2_superblock_t;
+
+#define EXT2_SUPERBLOCK_MAGIC		0xEF53
+#define EXT2_SUPERBLOCK_SIZE		1024
+#define EXT2_SUPERBLOCK_OFFSET		1024
+#define EXT2_SUPERBLOCK_LAST_BYTE	(EXT2_SUPERBLOCK_OFFSET + \
+									 EXT2_SUPERBLOCK_SIZE -1)
+#define EXT2_SUPERBLOCK_OS_LINUX	0
+#define EXT2_SUPERBLOCK_OS_HURD		1
+
+
+inline uint16_t	ext2_superblock_get_magic(ext2_superblock_t *);
+inline uint32_t	ext2_superblock_get_first_block(ext2_superblock_t *);
+inline uint32_t	ext2_superblock_get_block_size_log2(ext2_superblock_t *);
+inline uint32_t	ext2_superblock_get_block_size(ext2_superblock_t *);
+inline int32_t	ext2_superblock_get_fragment_size_log2(ext2_superblock_t *);
+inline uint32_t	ext2_superblock_get_fragment_size(ext2_superblock_t *);
+inline uint32_t	ext2_superblock_get_blocks_per_group(ext2_superblock_t *);
+inline uint32_t	ext2_superblock_get_fragments_per_group(ext2_superblock_t *);
+inline uint16_t	ext2_superblock_get_state(ext2_superblock_t *);
+inline uint16_t	ext2_superblock_get_rev_minor(ext2_superblock_t *);
+inline uint32_t	ext2_superblock_get_rev_major(ext2_superblock_t *);
+inline uint32_t	ext2_superblock_get_os(ext2_superblock_t *);
+inline uint32_t	ext2_superblock_get_first_inode(ext2_superblock_t *);
+inline uint16_t	ext2_superblock_get_inode_size(ext2_superblock_t *);
+inline uint32_t	ext2_superblock_get_total_inode_count(ext2_superblock_t *);
+inline uint32_t	ext2_superblock_get_total_block_count(ext2_superblock_t *);
+inline uint32_t	ext2_superblock_get_reserved_block_count(ext2_superblock_t *);
+inline uint32_t	ext2_superblock_get_free_block_count(ext2_superblock_t *);
+inline uint32_t	ext2_superblock_get_free_inode_count(ext2_superblock_t *);
+inline uint32_t	ext2_superblock_get_block_group_count(ext2_superblock_t *);
+inline uint32_t	ext2_superblock_get_inodes_per_group(ext2_superblock_t *);
+
+extern int ext2_superblock_read_direct(devmap_handle_t, ext2_superblock_t **);
+extern int ext2_superblock_check_sanity(ext2_superblock_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/fs/ext2/Makefile
===================================================================
--- uspace/srv/fs/ext2/Makefile	(revision f483a1595e01c6dce011869a0e03969833df9750)
+++ uspace/srv/fs/ext2/Makefile	(revision f483a1595e01c6dce011869a0e03969833df9750)
@@ -0,0 +1,40 @@
+#
+# Copyright (c) 2005 Martin Decky
+# Copyright (c) 2007 Jakub Jermar
+# Copyright (c) 2010 Martin Sucha
+# 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.
+#
+
+USPACE_PREFIX = ../../..
+LIBS = $(LIBBLOCK_PREFIX)/libblock.a $(LIBFS_PREFIX)/libfs.a $(LIBEXT2_PREFIX)/libext2.a
+EXTRA_CFLAGS += -I$(LIBBLOCK_PREFIX) -I$(LIBFS_PREFIX) -I$(LIBEXT2_PREFIX)
+BINARY = ext2
+
+SOURCES = \
+	ext2.c \
+	ext2_ops.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/srv/fs/ext2/ext2.c
===================================================================
--- uspace/srv/fs/ext2/ext2.c	(revision f483a1595e01c6dce011869a0e03969833df9750)
+++ uspace/srv/fs/ext2/ext2.c	(revision f483a1595e01c6dce011869a0e03969833df9750)
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2006 Martin Decky
+ * 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 fs
+ * @{
+ */ 
+
+/**
+ * @file	ext2.c
+ * @brief	EXT2 file system driver for HelenOS.
+ */
+
+#include "ext2.h"
+#include <ipc/services.h>
+#include <ipc/ns.h>
+#include <async.h>
+#include <errno.h>
+#include <unistd.h>
+#include <task.h>
+#include <stdio.h>
+#include <libfs.h>
+#include "../../vfs/vfs.h"
+
+#define NAME	"ext2"
+
+vfs_info_t ext2_vfs_info = {
+	.name = NAME,
+};
+
+fs_reg_t ext2_reg;
+
+/**
+ * This connection fibril processes VFS requests from VFS.
+ *
+ * In order to support simultaneous VFS requests, our design is as follows.
+ * The connection fibril accepts VFS requests from VFS. If there is only one
+ * instance of the fibril, VFS will need to serialize all VFS requests it sends
+ * to EXT2. To overcome this bottleneck, VFS can send EXT2 the IPC_M_CONNECT_ME_TO
+ * call. In that case, a new connection fibril will be created, which in turn
+ * will accept the call. Thus, a new phone will be opened for VFS.
+ *
+ * There are few issues with this arrangement. First, VFS can run out of
+ * available phones. In that case, VFS can close some other phones or use one
+ * phone for more serialized requests. Similarily, EXT2 can refuse to duplicate
+ * the connection. VFS should then just make use of already existing phones and
+ * route its requests through them. To avoid paying the fibril creation price 
+ * upon each request, EXT2 might want to keep the connections open after the
+ * request has been completed.
+ */
+static void ext2_connection(ipc_callid_t iid, ipc_call_t *icall)
+{
+	if (iid) {
+		/*
+		 * This only happens for connections opened by
+		 * IPC_M_CONNECT_ME_TO calls as opposed to callback connections
+		 * created by IPC_M_CONNECT_TO_ME.
+		 */
+		async_answer_0(iid, EOK);
+	}
+	
+	dprintf(NAME ": connection opened\n");
+	while (1) {
+		ipc_callid_t callid;
+		ipc_call_t call;
+	
+		callid = async_get_call(&call);
+		switch  (IPC_GET_IMETHOD(call)) {
+		case IPC_M_PHONE_HUNGUP:
+			return;
+		case VFS_OUT_MOUNTED:
+			ext2_mounted(callid, &call);
+			break;
+		case VFS_OUT_MOUNT:
+			ext2_mount(callid, &call);
+			break;
+		case VFS_OUT_UNMOUNTED:
+			ext2_unmounted(callid, &call);
+			break;
+		case VFS_OUT_UNMOUNT:
+			ext2_unmount(callid, &call);
+			break;
+		case VFS_OUT_LOOKUP:
+			ext2_lookup(callid, &call);
+			break;
+		case VFS_OUT_READ:
+			ext2_read(callid, &call);
+			break;
+		case VFS_OUT_WRITE:
+			ext2_write(callid, &call);
+			break;
+		case VFS_OUT_TRUNCATE:
+			ext2_truncate(callid, &call);
+			break;
+		case VFS_OUT_STAT:
+			ext2_stat(callid, &call);
+			break;
+		case VFS_OUT_CLOSE:
+			ext2_close(callid, &call);
+			break;
+		case VFS_OUT_DESTROY:
+			ext2_destroy(callid, &call);
+			break;
+		case VFS_OUT_OPEN_NODE:
+			ext2_open_node(callid, &call);
+			break;
+		case VFS_OUT_SYNC:
+			ext2_sync(callid, &call);
+			break;
+		default:
+			async_answer_0(callid, ENOTSUP);
+			break;
+		}
+	}
+}
+
+int main(int argc, char **argv)
+{
+	int vfs_phone;
+	int rc;
+
+	printf(NAME ": HelenOS EXT2 file system server\n");
+
+	vfs_phone = service_connect_blocking(SERVICE_VFS, 0, 0);
+	if (vfs_phone < EOK) {
+		printf(NAME ": failed to connect to VFS\n");
+		return -1;
+	}
+	
+	rc = fs_register(vfs_phone, &ext2_reg, &ext2_vfs_info, ext2_connection);
+	
+	printf(NAME ": Accepting connections\n");
+	task_retval(0);
+	async_manager();
+	/* not reached */
+	return 0;
+}
+
+/**
+ * @}
+ */ 
Index: uspace/srv/fs/ext2/ext2.h
===================================================================
--- uspace/srv/fs/ext2/ext2.h	(revision f483a1595e01c6dce011869a0e03969833df9750)
+++ uspace/srv/fs/ext2/ext2.h	(revision f483a1595e01c6dce011869a0e03969833df9750)
@@ -0,0 +1,71 @@
+/*
+ * 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 fs
+ * @{
+ */ 
+
+#ifndef EXT2_EXT2_H_
+#define EXT2_EXT2_H_
+
+#include <libext2.h>
+#include <fibril_synch.h>
+#include <libfs.h>
+#include <atomic.h>
+#include <sys/types.h>
+#include <bool.h>
+#include "../../vfs/vfs.h"
+
+#ifndef dprintf
+#define dprintf(...)	printf(__VA_ARGS__)
+#endif
+
+#define min(a, b)		((a) < (b) ? (a) : (b))
+
+extern fs_reg_t ext2_reg;
+
+extern void ext2_mounted(ipc_callid_t, ipc_call_t *);
+extern void ext2_mount(ipc_callid_t, ipc_call_t *);
+extern void ext2_unmounted(ipc_callid_t, ipc_call_t *);
+extern void ext2_unmount(ipc_callid_t, ipc_call_t *);
+extern void ext2_lookup(ipc_callid_t, ipc_call_t *);
+extern void ext2_read(ipc_callid_t, ipc_call_t *);
+extern void ext2_write(ipc_callid_t, ipc_call_t *);
+extern void ext2_truncate(ipc_callid_t, ipc_call_t *);
+extern void ext2_stat(ipc_callid_t, ipc_call_t *);
+extern void ext2_close(ipc_callid_t, ipc_call_t *);
+extern void ext2_destroy(ipc_callid_t, ipc_call_t *);
+extern void ext2_open_node(ipc_callid_t, ipc_call_t *);
+extern void ext2_stat(ipc_callid_t, ipc_call_t *);
+extern void ext2_sync(ipc_callid_t, ipc_call_t *);
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/srv/fs/ext2/ext2_ops.c
===================================================================
--- uspace/srv/fs/ext2/ext2_ops.c	(revision f483a1595e01c6dce011869a0e03969833df9750)
+++ uspace/srv/fs/ext2/ext2_ops.c	(revision f483a1595e01c6dce011869a0e03969833df9750)
@@ -0,0 +1,313 @@
+/*
+ * 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 fs
+ * @{
+ */ 
+
+/**
+ * @file	ext2_ops.c
+ * @brief	Implementation of VFS operations for the EXT2 file system server.
+ */
+
+#include "ext2.h"
+#include "../../vfs/vfs.h"
+#include <libfs.h>
+#include <libblock.h>
+#include <libext2.h>
+#include <ipc/services.h>
+#include <ipc/devmap.h>
+#include <macros.h>
+#include <async.h>
+#include <errno.h>
+#include <str.h>
+#include <byteorder.h>
+#include <adt/hash_table.h>
+#include <adt/list.h>
+#include <assert.h>
+#include <fibril_synch.h>
+#include <sys/mman.h>
+#include <align.h>
+
+#define EXT2_NODE(node)	((node) ? (ext2_node_t *) (node)->data : NULL)
+#define FS_NODE(node)	((node) ? (node)->bp : NULL)
+
+/*
+ * Forward declarations of EXT2 libfs operations.
+ */
+static int ext2_root_get(fs_node_t **, devmap_handle_t);
+static int ext2_match(fs_node_t **, fs_node_t *, const char *);
+static int ext2_node_get(fs_node_t **, devmap_handle_t, fs_index_t);
+static int ext2_node_open(fs_node_t *);
+static int ext2_node_put(fs_node_t *);
+static int ext2_create_node(fs_node_t **, devmap_handle_t, int);
+static int ext2_destroy_node(fs_node_t *);
+static int ext2_link(fs_node_t *, fs_node_t *, const char *);
+static int ext2_unlink(fs_node_t *, fs_node_t *, const char *);
+static int ext2_has_children(bool *, fs_node_t *);
+static fs_index_t ext2_index_get(fs_node_t *);
+static aoff64_t ext2_size_get(fs_node_t *);
+static unsigned ext2_lnkcnt_get(fs_node_t *);
+static char ext2_plb_get_char(unsigned);
+static bool ext2_is_directory(fs_node_t *);
+static bool ext2_is_file(fs_node_t *node);
+static devmap_handle_t ext2_device_get(fs_node_t *node);
+
+/*
+ * EXT2 libfs operations.
+ */
+
+int ext2_root_get(fs_node_t **rfn, devmap_handle_t devmap_handle)
+{
+	// TODO
+	return 0;
+	//return ext2_node_get(rfn, devmap_handle, 0);
+}
+
+int ext2_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
+{
+	// TODO
+	return ENOTSUP;
+}
+
+/** Instantiate a EXT2 in-core node. */
+int ext2_node_get(fs_node_t **rfn, devmap_handle_t devmap_handle, fs_index_t index)
+{
+	// TODO
+	return ENOTSUP;
+}
+
+int ext2_node_open(fs_node_t *fn)
+{
+	/*
+	 * Opening a file is stateless, nothing
+	 * to be done here.
+	 */
+	return EOK;
+}
+
+int ext2_node_put(fs_node_t *fn)
+{
+	// TODO
+	return ENOTSUP;
+}
+
+int ext2_create_node(fs_node_t **rfn, devmap_handle_t devmap_handle, int flags)
+{
+	// TODO
+	return ENOTSUP;
+}
+
+int ext2_destroy_node(fs_node_t *fn)
+{
+	// TODO
+	return ENOTSUP;
+}
+
+int ext2_link(fs_node_t *pfn, fs_node_t *cfn, const char *name)
+{
+	// TODO
+	return ENOTSUP;
+}
+
+int ext2_unlink(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
+{
+	// TODO
+	return ENOTSUP;
+}
+
+int ext2_has_children(bool *has_children, fs_node_t *fn)
+{
+	// TODO
+	return ENOTSUP;
+}
+
+
+fs_index_t ext2_index_get(fs_node_t *fn)
+{
+	// TODO
+	return 0;
+}
+
+aoff64_t ext2_size_get(fs_node_t *fn)
+{
+	// TODO
+	return 0;
+}
+
+unsigned ext2_lnkcnt_get(fs_node_t *fn)
+{
+	// TODO
+	return 0;
+}
+
+char ext2_plb_get_char(unsigned pos)
+{
+	return ext2_reg.plb_ro[pos % PLB_SIZE];
+}
+
+bool ext2_is_directory(fs_node_t *fn)
+{
+	// TODO
+	return false;
+}
+
+bool ext2_is_file(fs_node_t *fn)
+{
+	// TODO
+	return false;
+}
+
+devmap_handle_t ext2_device_get(fs_node_t *node)
+{
+	return 0;
+}
+
+/** libfs operations */
+libfs_ops_t ext2_libfs_ops = {
+	.root_get = ext2_root_get,
+	.match = ext2_match,
+	.node_get = ext2_node_get,
+	.node_open = ext2_node_open,
+	.node_put = ext2_node_put,
+	.create = ext2_create_node,
+	.destroy = ext2_destroy_node,
+	.link = ext2_link,
+	.unlink = ext2_unlink,
+	.has_children = ext2_has_children,
+	.index_get = ext2_index_get,
+	.size_get = ext2_size_get,
+	.lnkcnt_get = ext2_lnkcnt_get,
+	.plb_get_char = ext2_plb_get_char,
+	.is_directory = ext2_is_directory,
+	.is_file = ext2_is_file,
+	.device_get = ext2_device_get
+};
+
+/*
+ * VFS operations.
+ */
+
+void ext2_mounted(ipc_callid_t rid, ipc_call_t *request)
+{
+//	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
+	// TODO
+	async_answer_0(rid, ENOTSUP);
+}
+
+void ext2_mount(ipc_callid_t rid, ipc_call_t *request)
+{
+	libfs_mount(&ext2_libfs_ops, ext2_reg.fs_handle, rid, request);
+}
+
+void ext2_unmounted(ipc_callid_t rid, ipc_call_t *request)
+{
+//	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
+	// TODO
+	async_answer_0(rid, ENOTSUP);
+}
+
+void ext2_unmount(ipc_callid_t rid, ipc_call_t *request)
+{
+	libfs_unmount(&ext2_libfs_ops, rid, request);
+}
+
+void ext2_lookup(ipc_callid_t rid, ipc_call_t *request)
+{
+	libfs_lookup(&ext2_libfs_ops, ext2_reg.fs_handle, rid, request);
+}
+
+void ext2_read(ipc_callid_t rid, ipc_call_t *request)
+{
+//	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
+//	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
+//	aoff64_t pos =
+//	    (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request), IPC_GET_ARG4(*request));
+	
+	// TODO
+	async_answer_0(rid, ENOTSUP);
+}
+
+void ext2_write(ipc_callid_t rid, ipc_call_t *request)
+{
+//	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
+//	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
+//	aoff64_t pos =
+//	    (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request), IPC_GET_ARG4(*request));
+	
+	// TODO
+	async_answer_0(rid, ENOTSUP);
+}
+
+void ext2_truncate(ipc_callid_t rid, ipc_call_t *request)
+{
+//	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
+//	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
+//	aoff64_t size =
+//	    (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request), IPC_GET_ARG4(*request));
+	
+	// TODO
+	async_answer_0(rid, ENOTSUP);
+}
+
+void ext2_close(ipc_callid_t rid, ipc_call_t *request)
+{
+	async_answer_0(rid, EOK);
+}
+
+void ext2_destroy(ipc_callid_t rid, ipc_call_t *request)
+{
+//	devmap_handle_t devmap_handle = (devmap_handle_t)IPC_GET_ARG1(*request);
+//	fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
+	
+	// TODO
+	async_answer_0(rid, ENOTSUP);
+}
+
+void ext2_open_node(ipc_callid_t rid, ipc_call_t *request)
+{
+	libfs_open_node(&ext2_libfs_ops, ext2_reg.fs_handle, rid, request);
+}
+
+void ext2_stat(ipc_callid_t rid, ipc_call_t *request)
+{
+	libfs_stat(&ext2_libfs_ops, ext2_reg.fs_handle, rid, request);
+}
+
+void ext2_sync(ipc_callid_t rid, ipc_call_t *request)
+{
+//	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
+//	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
+	
+	// TODO
+	async_answer_0(rid, ENOTSUP);
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/fs/pipefs/Makefile
===================================================================
--- uspace/srv/fs/pipefs/Makefile	(revision f483a1595e01c6dce011869a0e03969833df9750)
+++ uspace/srv/fs/pipefs/Makefile	(revision f483a1595e01c6dce011869a0e03969833df9750)
@@ -0,0 +1,39 @@
+#
+# Copyright (c) 2005 Martin Decky
+# 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.
+#
+
+USPACE_PREFIX = ../../..
+LIBS = $(LIBBLOCK_PREFIX)/libblock.a $(LIBFS_PREFIX)/libfs.a
+EXTRA_CFLAGS += -I$(LIBBLOCK_PREFIX) -I$(LIBFS_PREFIX)
+BINARY = pipefs
+
+SOURCES = \
+	pipefs.c \
+	pipefs_ops.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/srv/fs/pipefs/pipefs.c
===================================================================
--- uspace/srv/fs/pipefs/pipefs.c	(revision f483a1595e01c6dce011869a0e03969833df9750)
+++ uspace/srv/fs/pipefs/pipefs.c	(revision f483a1595e01c6dce011869a0e03969833df9750)
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2006 Martin Decky
+ * 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 fs
+ * @{
+ */ 
+
+/**
+ * @file	pipefs.c
+ * @brief	File system driver for in-memory file system.
+ *
+ * Every instance of pipefs exists purely in memory and has neither a disk layout
+ * nor any permanent storage (e.g. disk blocks). With each system reboot, data
+ * stored in a pipefs file system is lost.
+ */
+
+#include "pipefs.h"
+#include <ipc/services.h>
+#include <ipc/ns.h>
+#include <async.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <task.h>
+#include <libfs.h>
+#include "../../vfs/vfs.h"
+
+#define NAME "pipefs"
+
+
+vfs_info_t pipefs_vfs_info = {
+	.name = NAME,
+};
+
+fs_reg_t pipefs_reg;
+
+/**
+ * This connection fibril processes VFS requests from VFS.
+ *
+ * In order to support simultaneous VFS requests, our design is as follows.
+ * The connection fibril accepts VFS requests from VFS. If there is only one
+ * instance of the fibril, VFS will need to serialize all VFS requests it sends
+ * to PIPEFS. To overcome this bottleneck, VFS can send PIPEFS the
+ * IPC_M_CONNECT_ME_TO call. In that case, a new connection fibril will be
+ * created, which in turn will accept the call. Thus, a new phone will be
+ * opened for VFS.
+ *
+ * There are few issues with this arrangement. First, VFS can run out of
+ * available phones. In that case, VFS can close some other phones or use one
+ * phone for more serialized requests. Similarily, PIPEFS can refuse to duplicate
+ * the connection. VFS should then just make use of already existing phones and
+ * route its requests through them. To avoid paying the fibril creation price 
+ * upon each request, PIPEFS might want to keep the connections open after the
+ * request has been completed.
+ */
+static void pipefs_connection(ipc_callid_t iid, ipc_call_t *icall)
+{
+	if (iid) {
+		/*
+		 * This only happens for connections opened by
+		 * IPC_M_CONNECT_ME_TO calls as opposed to callback connections
+		 * created by IPC_M_CONNECT_TO_ME.
+		 */
+		async_answer_0(iid, EOK);
+	}
+	
+	dprintf(NAME ": connection opened\n");
+	while (1) {
+		ipc_callid_t callid;
+		ipc_call_t call;
+	
+		callid = async_get_call(&call);
+		switch  (IPC_GET_IMETHOD(call)) {
+		case IPC_M_PHONE_HUNGUP:
+			return;
+		case VFS_OUT_MOUNTED:
+			pipefs_mounted(callid, &call);
+			break;
+		case VFS_OUT_MOUNT:
+			pipefs_mount(callid, &call);
+			break;
+		case VFS_OUT_UNMOUNTED:
+			pipefs_unmounted(callid, &call);
+			break;
+		case VFS_OUT_UNMOUNT:
+			pipefs_unmount(callid, &call);
+			break;
+		case VFS_OUT_LOOKUP:
+			pipefs_lookup(callid, &call);
+			break;
+		case VFS_OUT_READ:
+			pipefs_read(callid, &call);
+			break;
+		case VFS_OUT_WRITE:
+			pipefs_write(callid, &call);
+			break;
+		case VFS_OUT_TRUNCATE:
+			pipefs_truncate(callid, &call);
+			break;
+		case VFS_OUT_CLOSE:
+			pipefs_close(callid, &call);
+			break;
+		case VFS_OUT_DESTROY:
+			pipefs_destroy(callid, &call);
+			break;
+		case VFS_OUT_OPEN_NODE:
+			pipefs_open_node(callid, &call);
+			break;
+		case VFS_OUT_STAT:
+			pipefs_stat(callid, &call);
+			break;
+		case VFS_OUT_SYNC:
+			pipefs_sync(callid, &call);
+			break;
+		default:
+			async_answer_0(callid, ENOTSUP);
+			break;
+		}
+	}
+}
+
+int main(int argc, char **argv)
+{
+	printf(NAME ": HelenOS PIPEFS file system server\n");
+
+	if (!pipefs_init()) {
+		printf(NAME ": failed to initialize PIPEFS\n");
+		return -1;
+	}
+
+	int vfs_phone = service_connect_blocking(SERVICE_VFS, 0, 0);
+	if (vfs_phone < EOK) {
+		printf(NAME ": Unable to connect to VFS\n");
+		return -1;
+	}
+
+	int rc = fs_register(vfs_phone, &pipefs_reg, &pipefs_vfs_info,
+	    pipefs_connection);
+	if (rc != EOK) {
+		printf(NAME ": Failed to register file system (%d)\n", rc);
+		return rc;
+	}
+
+	printf(NAME ": Accepting connections\n");
+	task_retval(0);
+	async_manager();
+	/* not reached */
+	return 0;
+}
+
+/**
+ * @}
+ */ 
Index: uspace/srv/fs/pipefs/pipefs.h
===================================================================
--- uspace/srv/fs/pipefs/pipefs.h	(revision f483a1595e01c6dce011869a0e03969833df9750)
+++ uspace/srv/fs/pipefs/pipefs.h	(revision f483a1595e01c6dce011869a0e03969833df9750)
@@ -0,0 +1,106 @@
+/*
+ * 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 fs
+ * @{
+ */
+
+#ifndef PIPEFS_PIPEFS_H_
+#define PIPEFS_PIPEFS_H_
+
+#include <libfs.h>
+#include <atomic.h>
+#include <sys/types.h>
+#include <bool.h>
+#include <adt/hash_table.h>
+
+#define PIPEFS_NODE(node)	((node) ? (pipefs_node_t *)(node)->data : NULL)
+#define FS_NODE(node)		((node) ? (node)->bp : NULL)
+
+typedef enum {
+	PIPEFS_NONE,
+	PIPEFS_FILE,
+	PIPEFS_DIRECTORY
+} pipefs_dentry_type_t;
+
+/* forward declaration */
+struct pipefs_node;
+
+typedef struct pipefs_dentry {
+	link_t link;		/**< Linkage for the list of siblings. */
+	struct pipefs_node *node;/**< Back pointer to PIPEFS node. */
+	char *name;		/**< Name of dentry. */
+} pipefs_dentry_t;
+
+typedef struct pipefs_node {
+	fs_node_t *bp;		/**< Back pointer to the FS node. */
+	fs_index_t index;	/**< PIPEFS node index. */
+	devmap_handle_t devmap_handle;/**< Device handle. */
+	link_t nh_link;		/**< Nodes hash table link. */
+	pipefs_dentry_type_t type;
+	unsigned lnkcnt;	/**< Link count. */
+	/* Following is for nodes of type PIPEFS_FILE */
+	aoff64_t start;		/**< File offset where first data block resides */
+	size_t size;		/**< File size if type is PIPEFS_FILE. */
+	link_t data_head;	/**< Head of data blocks list for PIPEFS_FILE. */
+	/* This is for directory */
+	link_t cs_head;		/**< Head of child's siblings list. */	
+} pipefs_node_t;
+
+typedef struct pipefs_data_block {
+	link_t link;		/**< Linkage for the list of data blocks */
+	size_t size;		/**< Size of this block */
+	void *data;			/**< Data for this block */
+} pipefs_data_block_t;
+
+extern fs_reg_t pipefs_reg;
+
+extern libfs_ops_t pipefs_libfs_ops;
+
+extern bool pipefs_init(void);
+
+extern void pipefs_mounted(ipc_callid_t, ipc_call_t *);
+extern void pipefs_mount(ipc_callid_t, ipc_call_t *);
+extern void pipefs_unmounted(ipc_callid_t, ipc_call_t *);
+extern void pipefs_unmount(ipc_callid_t, ipc_call_t *);
+extern void pipefs_lookup(ipc_callid_t, ipc_call_t *);
+extern void pipefs_read(ipc_callid_t, ipc_call_t *);
+extern void pipefs_write(ipc_callid_t, ipc_call_t *);
+extern void pipefs_truncate(ipc_callid_t, ipc_call_t *);
+extern void pipefs_stat(ipc_callid_t, ipc_call_t *);
+extern void pipefs_close(ipc_callid_t, ipc_call_t *);
+extern void pipefs_destroy(ipc_callid_t, ipc_call_t *);
+extern void pipefs_open_node(ipc_callid_t, ipc_call_t *);
+extern void pipefs_sync(ipc_callid_t, ipc_call_t *);
+
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/srv/fs/pipefs/pipefs_ops.c
===================================================================
--- uspace/srv/fs/pipefs/pipefs_ops.c	(revision f483a1595e01c6dce011869a0e03969833df9750)
+++ uspace/srv/fs/pipefs/pipefs_ops.c	(revision f483a1595e01c6dce011869a0e03969833df9750)
@@ -0,0 +1,787 @@
+/*
+ * 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 fs
+ * @{
+ */
+
+/**
+ * @file	pipefs_ops.c
+ * @brief	Implementation of VFS operations for the PIPEFS file system
+ *		server.
+ */
+
+#include "pipefs.h"
+#include "../../vfs/vfs.h"
+#include <macros.h>
+#include <stdint.h>
+#include <async.h>
+#include <errno.h>
+#include <atomic.h>
+#include <stdlib.h>
+#include <str.h>
+#include <stdio.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <adt/hash_table.h>
+#include <as.h>
+#include <libfs.h>
+
+#define min(a, b)		((a) < (b) ? (a) : (b))
+#define max(a, b)		((a) > (b) ? (a) : (b))
+
+#define NODES_BUCKETS	256
+
+/** All root nodes have index 0. */
+#define PIPEFS_SOME_ROOT		0
+/** Global counter for assigning node indices. Shared by all instances. */
+fs_index_t pipefs_next_index = 1;
+
+/*
+ * Implementation of the libfs interface.
+ */
+
+/* Forward declarations of static functions. */
+static int pipefs_match(fs_node_t **, fs_node_t *, const char *);
+static int pipefs_node_get(fs_node_t **, devmap_handle_t, fs_index_t);
+static int pipefs_node_open(fs_node_t *);
+static int pipefs_node_put(fs_node_t *);
+static int pipefs_create_node(fs_node_t **, devmap_handle_t, int);
+static int pipefs_destroy_node(fs_node_t *);
+static int pipefs_link_node(fs_node_t *, fs_node_t *, const char *);
+static int pipefs_unlink_node(fs_node_t *, fs_node_t *, const char *);
+
+/* Implementation of helper functions. */
+static int pipefs_root_get(fs_node_t **rfn, devmap_handle_t devmap_handle)
+{
+	return pipefs_node_get(rfn, devmap_handle, PIPEFS_SOME_ROOT); 
+}
+
+static int pipefs_has_children(bool *has_children, fs_node_t *fn)
+{
+	*has_children = !list_empty(&PIPEFS_NODE(fn)->cs_head);
+	return EOK;
+}
+
+static fs_index_t pipefs_index_get(fs_node_t *fn)
+{
+	return PIPEFS_NODE(fn)->index;
+}
+
+static aoff64_t pipefs_size_get(fs_node_t *fn)
+{
+	return PIPEFS_NODE(fn)->size;
+}
+
+static unsigned pipefs_lnkcnt_get(fs_node_t *fn)
+{
+	return PIPEFS_NODE(fn)->lnkcnt;
+}
+
+static char pipefs_plb_get_char(unsigned pos)
+{
+	return pipefs_reg.plb_ro[pos % PLB_SIZE];
+}
+
+static bool pipefs_is_directory(fs_node_t *fn)
+{
+	return PIPEFS_NODE(fn)->type == PIPEFS_DIRECTORY;
+}
+
+static bool pipefs_is_file(fs_node_t *fn)
+{
+	return PIPEFS_NODE(fn)->type == PIPEFS_FILE;
+}
+
+static devmap_handle_t pipefs_device_get(fs_node_t *fn)
+{
+	return 0;
+}
+
+/** libfs operations */
+libfs_ops_t pipefs_libfs_ops = {
+	.root_get = pipefs_root_get,
+	.match = pipefs_match,
+	.node_get = pipefs_node_get,
+	.node_open = pipefs_node_open,
+	.node_put = pipefs_node_put,
+	.create = pipefs_create_node,
+	.destroy = pipefs_destroy_node,
+	.link = pipefs_link_node,
+	.unlink = pipefs_unlink_node,
+	.has_children = pipefs_has_children,
+	.index_get = pipefs_index_get,
+	.size_get = pipefs_size_get,
+	.lnkcnt_get = pipefs_lnkcnt_get,
+	.plb_get_char = pipefs_plb_get_char,
+	.is_directory = pipefs_is_directory,
+	.is_file = pipefs_is_file,
+	.device_get = pipefs_device_get
+};
+
+/** Hash table of all PIPEFS nodes. */
+hash_table_t nodes;
+
+#define NODES_KEY_DEV	0	
+#define NODES_KEY_INDEX	1
+
+/* Implementation of hash table interface for the nodes hash table. */
+static hash_index_t nodes_hash(unsigned long key[])
+{
+	return key[NODES_KEY_INDEX] % NODES_BUCKETS;
+}
+
+static int nodes_compare(unsigned long key[], hash_count_t keys, link_t *item)
+{
+	pipefs_node_t *nodep = hash_table_get_instance(item, pipefs_node_t,
+	    nh_link);
+	
+	switch (keys) {
+	case 1:
+		return (nodep->devmap_handle == key[NODES_KEY_DEV]);
+	case 2:	
+		return ((nodep->devmap_handle == key[NODES_KEY_DEV]) &&
+		    (nodep->index == key[NODES_KEY_INDEX]));
+	default:
+		assert((keys == 1) || (keys == 2));
+	}
+
+	return 0;
+}
+
+static void nodes_remove_callback(link_t *item)
+{
+	pipefs_node_t *nodep = hash_table_get_instance(item, pipefs_node_t,
+	    nh_link);
+
+	while (!list_empty(&nodep->cs_head)) {
+		pipefs_dentry_t *dentryp = list_get_instance(nodep->cs_head.next,
+		    pipefs_dentry_t, link);
+
+		assert(nodep->type == PIPEFS_DIRECTORY);
+		list_remove(&dentryp->link);
+		free(dentryp);
+	}
+
+	while (!list_empty(&nodep->data_head)) {
+		assert(nodep->type == PIPEFS_FILE);
+		
+		pipefs_data_block_t *data_block = list_get_instance(nodep->data_head.next,
+		    pipefs_data_block_t, link);
+		
+		list_remove(&data_block->link);
+		free(data_block->data);
+		free(data_block);
+	}
+	free(nodep->bp);
+	free(nodep);
+}
+
+/** PIPEFS nodes hash table operations. */
+hash_table_operations_t nodes_ops = {
+	.hash = nodes_hash,
+	.compare = nodes_compare,
+	.remove_callback = nodes_remove_callback
+};
+
+static void pipefs_node_initialize(pipefs_node_t *nodep)
+{
+	nodep->bp = NULL;
+	nodep->index = 0;
+	nodep->devmap_handle = 0;
+	nodep->type = PIPEFS_NONE;
+	nodep->lnkcnt = 0;
+	nodep->start = 0;
+	nodep->size = 0;
+	list_initialize(&nodep->data_head);
+	link_initialize(&nodep->nh_link);
+	list_initialize(&nodep->cs_head);
+}
+
+static void pipefs_dentry_initialize(pipefs_dentry_t *dentryp)
+{
+	link_initialize(&dentryp->link);
+	dentryp->name = NULL;
+	dentryp->node = NULL;
+}
+
+bool pipefs_init(void)
+{
+	if (!hash_table_create(&nodes, NODES_BUCKETS, 2, &nodes_ops))
+		return false;
+	
+	return true;
+}
+
+static bool pipefs_instance_init(devmap_handle_t devmap_handle)
+{
+	fs_node_t *rfn;
+	int rc;
+	
+	rc = pipefs_create_node(&rfn, devmap_handle, L_DIRECTORY);
+	if (rc != EOK || !rfn)
+		return false;
+	PIPEFS_NODE(rfn)->lnkcnt = 0;	/* FS root is not linked */
+	return true;
+}
+
+static void pipefs_instance_done(devmap_handle_t devmap_handle)
+{
+	unsigned long key[] = {
+		[NODES_KEY_DEV] = devmap_handle
+	};
+	/*
+	 * Here we are making use of one special feature of our hash table
+	 * implementation, which allows to remove more items based on a partial
+	 * key match. In the following, we are going to remove all nodes
+	 * matching our device handle. The nodes_remove_callback() function will
+	 * take care of resource deallocation.
+	 */
+	hash_table_remove(&nodes, key, 1);
+}
+
+int pipefs_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
+{
+	pipefs_node_t *parentp = PIPEFS_NODE(pfn);
+	link_t *lnk;
+
+	for (lnk = parentp->cs_head.next; lnk != &parentp->cs_head;
+	    lnk = lnk->next) {
+		pipefs_dentry_t *dentryp;
+		dentryp = list_get_instance(lnk, pipefs_dentry_t, link);
+		if (!str_cmp(dentryp->name, component)) {
+			*rfn = FS_NODE(dentryp->node);
+			return EOK;
+		}
+	}
+
+	*rfn = NULL;
+	return EOK;
+}
+
+int pipefs_node_get(fs_node_t **rfn, devmap_handle_t devmap_handle, fs_index_t index)
+{
+	unsigned long key[] = {
+		[NODES_KEY_DEV] = devmap_handle,
+		[NODES_KEY_INDEX] = index
+	};
+	link_t *lnk = hash_table_find(&nodes, key);
+	if (lnk) {
+		pipefs_node_t *nodep;
+		nodep = hash_table_get_instance(lnk, pipefs_node_t, nh_link);
+		*rfn = FS_NODE(nodep);
+	} else {
+		*rfn = NULL;
+	}
+	return EOK;	
+}
+
+int pipefs_node_open(fs_node_t *fn)
+{
+	/* nothing to do */
+	return EOK;
+}
+
+int pipefs_node_put(fs_node_t *fn)
+{
+	/* nothing to do */
+	return EOK;
+}
+
+int pipefs_create_node(fs_node_t **rfn, devmap_handle_t devmap_handle, int lflag)
+{
+	fs_node_t *rootfn;
+	int rc;
+
+	assert((lflag & L_FILE) ^ (lflag & L_DIRECTORY));
+
+	pipefs_node_t *nodep = malloc(sizeof(pipefs_node_t));
+	if (!nodep)
+		return ENOMEM;
+	pipefs_node_initialize(nodep);
+	nodep->bp = malloc(sizeof(fs_node_t));
+	if (!nodep->bp) {
+		free(nodep);
+		return ENOMEM;
+	}
+	fs_node_initialize(nodep->bp);
+	nodep->bp->data = nodep;	/* link the FS and PIPEFS nodes */
+
+	rc = pipefs_root_get(&rootfn, devmap_handle);
+	assert(rc == EOK);
+	if (!rootfn)
+		nodep->index = PIPEFS_SOME_ROOT;
+	else
+		nodep->index = pipefs_next_index++;
+	nodep->devmap_handle = devmap_handle;
+	if (lflag & L_DIRECTORY) 
+		nodep->type = PIPEFS_DIRECTORY;
+	else 
+		nodep->type = PIPEFS_FILE;
+
+	/* Insert the new node into the nodes hash table. */
+	unsigned long key[] = {
+		[NODES_KEY_DEV] = nodep->devmap_handle,
+		[NODES_KEY_INDEX] = nodep->index
+	};
+	hash_table_insert(&nodes, key, &nodep->nh_link);
+	*rfn = FS_NODE(nodep);
+	return EOK;
+}
+
+int pipefs_destroy_node(fs_node_t *fn)
+{
+	pipefs_node_t *nodep = PIPEFS_NODE(fn);
+	
+	assert(!nodep->lnkcnt);
+	assert(list_empty(&nodep->cs_head));
+
+	unsigned long key[] = {
+		[NODES_KEY_DEV] = nodep->devmap_handle,
+		[NODES_KEY_INDEX] = nodep->index
+	};
+	hash_table_remove(&nodes, key, 2);
+
+	/*
+	 * The nodes_remove_callback() function takes care of the actual
+	 * resource deallocation.
+	 */
+	return EOK;
+}
+
+int pipefs_link_node(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
+{
+	pipefs_node_t *parentp = PIPEFS_NODE(pfn);
+	pipefs_node_t *childp = PIPEFS_NODE(cfn);
+	pipefs_dentry_t *dentryp;
+	link_t *lnk;
+
+	assert(parentp->type == PIPEFS_DIRECTORY);
+
+	/* Check for duplicit entries. */
+	for (lnk = parentp->cs_head.next; lnk != &parentp->cs_head;
+	    lnk = lnk->next) {
+		dentryp = list_get_instance(lnk, pipefs_dentry_t, link);	
+		if (!str_cmp(dentryp->name, nm))
+			return EEXIST;
+	}
+
+	/* Allocate and initialize the dentry. */
+	dentryp = malloc(sizeof(pipefs_dentry_t));
+	if (!dentryp)
+		return ENOMEM;
+	pipefs_dentry_initialize(dentryp);
+
+	/* Populate and link the new dentry. */
+	size_t size = str_size(nm);
+	dentryp->name = malloc(size + 1);
+	if (!dentryp->name) {
+		free(dentryp);
+		return ENOMEM;
+	}
+	str_cpy(dentryp->name, size + 1, nm);
+	dentryp->node = childp;
+	childp->lnkcnt++;
+	list_append(&dentryp->link, &parentp->cs_head);
+
+	return EOK;
+}
+
+int pipefs_unlink_node(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
+{
+	pipefs_node_t *parentp = PIPEFS_NODE(pfn);
+	pipefs_node_t *childp = NULL;
+	pipefs_dentry_t *dentryp;
+	link_t *lnk;
+
+	if (!parentp)
+		return EBUSY;
+	
+	for (lnk = parentp->cs_head.next; lnk != &parentp->cs_head;
+	    lnk = lnk->next) {
+		dentryp = list_get_instance(lnk, pipefs_dentry_t, link);
+		if (!str_cmp(dentryp->name, nm)) {
+			childp = dentryp->node;
+			assert(FS_NODE(childp) == cfn);
+			break;
+		}	
+	}
+
+	if (!childp)
+		return ENOENT;
+		
+	if ((childp->lnkcnt == 1) && !list_empty(&childp->cs_head))
+		return ENOTEMPTY;
+
+	list_remove(&dentryp->link);
+	free(dentryp);
+	childp->lnkcnt--;
+
+	return EOK;
+}
+
+void pipefs_mounted(ipc_callid_t rid, ipc_call_t *request)
+{
+	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
+	fs_node_t *rootfn;
+	int rc;
+	
+	/* Accept the mount options. */
+	char *opts;
+	rc = async_data_write_accept((void **) &opts, true, 0, 0, 0, NULL);
+	if (rc != EOK) {
+		async_answer_0(rid, rc);
+		return;
+	}
+
+	/* Check if this device is not already mounted. */
+	rc = pipefs_root_get(&rootfn, devmap_handle);
+	if ((rc == EOK) && (rootfn)) {
+		(void) pipefs_node_put(rootfn);
+		free(opts);
+		async_answer_0(rid, EEXIST);
+		return;
+	}
+
+	/* Initialize PIPEFS instance. */
+	if (!pipefs_instance_init(devmap_handle)) {
+		free(opts);
+		async_answer_0(rid, ENOMEM);
+		return;
+	}
+
+	rc = pipefs_root_get(&rootfn, devmap_handle);
+	assert(rc == EOK);
+	pipefs_node_t *rootp = PIPEFS_NODE(rootfn);
+	async_answer_3(rid, EOK, rootp->index, rootp->size, rootp->lnkcnt);
+	free(opts);
+}
+
+void pipefs_mount(ipc_callid_t rid, ipc_call_t *request)
+{
+	libfs_mount(&pipefs_libfs_ops, pipefs_reg.fs_handle, rid, request);
+}
+
+void pipefs_unmounted(ipc_callid_t rid, ipc_call_t *request)
+{
+	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
+
+	pipefs_instance_done(devmap_handle);
+	async_answer_0(rid, EOK);
+}
+
+void pipefs_unmount(ipc_callid_t rid, ipc_call_t *request)
+{
+	libfs_unmount(&pipefs_libfs_ops, rid, request);
+}
+
+void pipefs_lookup(ipc_callid_t rid, ipc_call_t *request)
+{
+	libfs_lookup(&pipefs_libfs_ops, pipefs_reg.fs_handle, rid, request);
+}
+
+void pipefs_read(ipc_callid_t rid, ipc_call_t *request)
+{
+	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
+	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
+	aoff64_t pos =
+	    (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request), IPC_GET_ARG4(*request));
+	
+	/*
+	 * Lookup the respective PIPEFS node.
+	 */
+	link_t *hlp;
+	unsigned long key[] = {
+		[NODES_KEY_DEV] = devmap_handle,
+		[NODES_KEY_INDEX] = index
+	};
+	hlp = hash_table_find(&nodes, key);
+	if (!hlp) {
+		async_answer_0(rid, ENOENT);
+		return;
+	}
+	pipefs_node_t *nodep = hash_table_get_instance(hlp, pipefs_node_t,
+	    nh_link);
+	
+	/*
+	 * Receive the read request.
+	 */
+	ipc_callid_t callid;
+	size_t size;
+	if (!async_data_read_receive(&callid, &size)) {
+		async_answer_0(callid, EINVAL);
+		async_answer_0(rid, EINVAL);
+		return;
+	}
+
+	size_t bytes;
+	if (nodep->type == PIPEFS_FILE) {
+		/*
+		 * Check if we still have the requested data.
+		 * This may happen if the client seeked backwards
+		 */
+		if (pos < nodep->start) {
+			async_answer_0(callid, ENOTSUP);
+			async_answer_0(rid, ENOTSUP);
+			return;
+		}
+		
+		/*
+		 * Free all data blocks that end before pos.
+		 * This is in case the client seeked forward 
+		 */
+		while (!list_empty(&nodep->data_head)) {
+			pipefs_data_block_t *data_block =
+			    list_get_instance(nodep->data_head.next,
+			        pipefs_data_block_t, link);
+		
+			aoff64_t block_end = nodep->start + data_block->size;
+			
+			if (block_end > pos) {
+				break;
+			}
+			
+			list_remove(&data_block->link);
+			free(data_block->data);
+			free(data_block);
+			nodep->start = block_end;
+		}
+		
+		if (!list_empty(&nodep->data_head)) {
+			/* We have data block, so let's return its portion after pos */
+			pipefs_data_block_t *data_block =
+			    list_get_instance(nodep->data_head.next,
+			        pipefs_data_block_t, link);
+			
+			assert(nodep->start <= pos);
+			
+			aoff64_t block_end = nodep->start + data_block->size;
+			size_t block_offset = pos - nodep->start;
+			
+			assert(block_end > pos);
+			
+			bytes = min(block_end - pos, size);
+			(void) async_data_read_finalize(callid,
+			    data_block->data + block_offset,
+			    bytes);
+			
+			if (nodep->start + block_offset + bytes == block_end) {
+				/* Free the data block - it was fully read */
+				list_remove(&data_block->link);
+				free(data_block->data);
+				free(data_block);
+				nodep->start = block_end;
+			}
+		}
+		else {
+			/*
+			 * there is no data
+			 * TODO implement waiting for the data
+			 * and remove this else clause
+			 */
+			async_answer_0(callid, ENOTSUP);
+			async_answer_1(rid, ENOTSUP, 0);
+			return;
+		}
+	} else {
+		pipefs_dentry_t *dentryp;
+		link_t *lnk;
+		aoff64_t i;
+		
+		assert(nodep->type == PIPEFS_DIRECTORY);
+		
+		/*
+		 * Yes, we really use O(n) algorithm here.
+		 * If it bothers someone, it could be fixed by introducing a
+		 * hash table.
+		 */
+		for (i = 0, lnk = nodep->cs_head.next;
+		    (i < pos) && (lnk != &nodep->cs_head);
+		    i++, lnk = lnk->next)
+			;
+
+		if (lnk == &nodep->cs_head) {
+			async_answer_0(callid, ENOENT);
+			async_answer_1(rid, ENOENT, 0);
+			return;
+		}
+
+		dentryp = list_get_instance(lnk, pipefs_dentry_t, link);
+
+		(void) async_data_read_finalize(callid, dentryp->name,
+		    str_size(dentryp->name) + 1);
+		bytes = 1;
+	}
+
+	/*
+	 * Answer the VFS_READ call.
+	 */
+	async_answer_1(rid, EOK, bytes);
+}
+
+void pipefs_write(ipc_callid_t rid, ipc_call_t *request)
+{
+	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
+	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
+	aoff64_t pos =
+	    (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request), IPC_GET_ARG4(*request));
+	
+	/*
+	 * Lookup the respective PIPEFS node.
+	 */
+	link_t *hlp;
+	unsigned long key[] = {
+		[NODES_KEY_DEV] = devmap_handle,
+		[NODES_KEY_INDEX] = index
+	};
+	hlp = hash_table_find(&nodes, key);
+	if (!hlp) {
+		async_answer_0(rid, ENOENT);
+		return;
+	}
+	pipefs_node_t *nodep = hash_table_get_instance(hlp, pipefs_node_t,
+	    nh_link);
+
+	/*
+	 * Receive the write request.
+	 */
+	ipc_callid_t callid;
+	size_t size;
+	if (!async_data_write_receive(&callid, &size)) {
+		async_answer_0(callid, EINVAL);	
+		async_answer_0(rid, EINVAL);
+		return;
+	}
+
+	/*
+	 * Check whether we are writing to the end
+	 */
+	if (pos != nodep->size) {
+		async_answer_0(callid, ENOTSUP);
+		async_answer_2(rid, EOK, 0, nodep->size);
+		return;
+	}
+	
+	/*
+	 * Allocate a buffer for the new data.
+	 * Currently we accept any size, create a data block from this
+	 * and append it to the end of a file
+	 */
+	void *newdata = malloc(size);
+	if (!newdata) {
+		async_answer_0(callid, ENOMEM);
+		async_answer_2(rid, EOK, 0, nodep->size);
+		return;
+	}
+	
+	pipefs_data_block_t *newblock = malloc(sizeof(pipefs_data_block_t));
+	
+	if (!newblock) {
+		free(newdata);
+		async_answer_0(callid, ENOMEM);
+		async_answer_2(rid, EOK, 0, nodep->size);
+		return;
+	}
+	
+	int rc = async_data_write_finalize(callid, newdata, size);
+	
+	if (rc != EOK) {
+		free(newblock);
+		free(newdata);
+		async_answer_0(callid, rc);
+		async_answer_2(rid, EOK, 0, nodep->size);
+		return;
+	}
+	
+	link_initialize(&newblock->link);
+	newblock->size = size;
+	newblock->data = newdata;
+	list_append(&newblock->link, &nodep->data_head);
+	
+	nodep->size += size;
+	
+	async_answer_2(rid, EOK, size, nodep->size);
+}
+
+void pipefs_truncate(ipc_callid_t rid, ipc_call_t *request)
+{
+	/*
+	 * PIPEFS does not support resizing of files
+	 */
+	async_answer_0(rid, ENOTSUP);
+}
+
+void pipefs_close(ipc_callid_t rid, ipc_call_t *request)
+{
+	async_answer_0(rid, EOK);
+}
+
+void pipefs_destroy(ipc_callid_t rid, ipc_call_t *request)
+{
+	devmap_handle_t devmap_handle = (devmap_handle_t)IPC_GET_ARG1(*request);
+	fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
+	int rc;
+
+	link_t *hlp;
+	unsigned long key[] = {
+		[NODES_KEY_DEV] = devmap_handle,
+		[NODES_KEY_INDEX] = index
+	};
+	hlp = hash_table_find(&nodes, key);
+	if (!hlp) {
+		async_answer_0(rid, ENOENT);
+		return;
+	}
+	pipefs_node_t *nodep = hash_table_get_instance(hlp, pipefs_node_t,
+	    nh_link);
+	rc = pipefs_destroy_node(FS_NODE(nodep));
+	async_answer_0(rid, rc);
+}
+
+void pipefs_open_node(ipc_callid_t rid, ipc_call_t *request)
+{
+	libfs_open_node(&pipefs_libfs_ops, pipefs_reg.fs_handle, rid, request);
+}
+
+void pipefs_stat(ipc_callid_t rid, ipc_call_t *request)
+{
+	libfs_stat(&pipefs_libfs_ops, pipefs_reg.fs_handle, rid, request);
+}
+
+void pipefs_sync(ipc_callid_t rid, ipc_call_t *request)
+{
+	/*
+	 * PIPEFS keeps its data structures always consistent,
+	 * thus the sync operation is a no-op.
+	 */
+	async_answer_0(rid, EOK);
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/hw/netif/ne2000/dp8390_drv.h
===================================================================
--- uspace/srv/hw/netif/ne2000/dp8390_drv.h	(revision f483a1595e01c6dce011869a0e03969833df9750)
+++ uspace/srv/hw/netif/ne2000/dp8390_drv.h	(revision f483a1595e01c6dce011869a0e03969833df9750)
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2009 Lukas Mejdrech
+ * 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 dp8390
+ *  @{
+ */
+
+/** @file
+ *  DP8390 network interface driver interface.
+ */
+
+#ifndef __NET_NETIF_DP8390_DRIVER_H__
+#define __NET_NETIF_DP8390_DRIVER_H__
+
+#include "dp8390.h"
+
+/** Initializes and/or starts the network interface.
+ *  @param[in,out] dep The network interface structure.
+ *  @param[in] mode The state mode.
+ *  @returns EOK on success.
+ *  @returns EXDEV if the network interface is disabled.
+ */
+int do_init(dpeth_t *dep, int mode);
+
+/** Stops the network interface.
+ *  @param[in,out] dep The network interface structure.
+ */
+void do_stop(dpeth_t *dep);
+
+/** Processes the interrupt.
+ *  @param[in,out] dep The network interface structure.
+ *  @param[in] isr The interrupt status register.
+ */
+void dp_check_ints(dpeth_t *dep, int isr);
+
+/** Probes and initializes the network interface.
+ *  @param[in,out] dep The network interface structure.
+ *  @returns EOK on success.
+ *  @returns EXDEV if the network interface was not recognized.
+ */
+int do_probe(dpeth_t * dep);
+
+/** Sends a packet.
+ *  @param[in,out] dep The network interface structure.
+ *  @param[in] packet The packet t be sent.
+ *  @param[in] from_int The value indicating whether the sending is initialized from the interrupt handler.
+ *  @returns 
+ */
+int do_pwrite(dpeth_t * dep, packet_t *packet, int from_int);
+
+/** Prints out network interface information.
+ *  @param[in] dep The network interface structure.
+ */
+void dp8390_dump(dpeth_t * dep);
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/hw/netif/ne2000/dp8390_port.h
===================================================================
--- uspace/srv/hw/netif/ne2000/dp8390_port.h	(revision f483a1595e01c6dce011869a0e03969833df9750)
+++ uspace/srv/hw/netif/ne2000/dp8390_port.h	(revision f483a1595e01c6dce011869a0e03969833df9750)
@@ -0,0 +1,274 @@
+/*
+ * Copyright (c) 2009 Lukas Mejdrech
+ * 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 dp8390
+ *  @{
+ */
+
+/** @file
+ *  DP8390 network interface types and structures ports.
+ */
+
+#ifndef __NET_NETIF_DP8390_PORT_H__
+#define __NET_NETIF_DP8390_PORT_H__
+
+#include <errno.h>
+#include <mem.h>
+#include <stdio.h>
+#include <libarch/ddi.h>
+#include <sys/types.h>
+
+/** Macro for difining functions.
+ *  @param[in] function The function type and name definition.
+ *  @param[in] params The function parameters definition.
+ */
+#define _PROTOTYPE(function, params) function params
+
+/** Success error code.
+ */
+#define OK	EOK
+
+/** Type definition of the unsigned byte.
+ */
+typedef uint8_t u8_t;
+
+/** Type definition of the unsigned short.
+ */
+typedef uint16_t u16_t;
+
+/** Compares two memory blocks.
+ *  @param[in] first The first memory block.
+ *  @param[in] second The second memory block.
+ *  @param[in] size The blocks size in bytes.
+ *  @returns 0 if equeal.
+ *  @returns -1 if the first is greater than the second.
+ *  @returns 1 if the second is greater than the first.
+ */
+#define memcmp(first, second, size)	bcmp((char *) (first), (char *) (second), (size))
+
+/** Reads 1 byte.
+ *  @param[in] port The address to be read.
+ *  @returns The read value.
+ */
+#define inb(port)	pio_read_8((ioport8_t *) (port))
+
+/** Reads 1 word (2 bytes).
+ *  @param[in] port The address to be read.
+ *  @returns The read value.
+ */
+#define inw(port)	pio_read_16((ioport16_t *) (port))
+
+/** Writes 1 byte.
+ *  @param[in] port The address to be written.
+ *  @param[in] value The value to be written.
+ */
+#define outb(port, value)	pio_write_8((ioport8_t *) (port), (value))
+
+/** Writes 1 word (2 bytes).
+ *  @param[in] port The address to be written.
+ *  @param[in] value The value to be written.
+ */
+#define outw(port, value)	pio_write_16((ioport16_t *) (port), (value))
+
+/** Prints out the driver critical error.
+ *  Does not call the system panic().
+ */
+#define panic(...)	printf("%s%s%d", __VA_ARGS__)
+
+/** Copies a memory block.
+ *  @param proc The source process. Ignored parameter.
+ *  @param src_s Ignored parameter.
+ *  @param[in] src The source address.
+ *  @param me The current proces. Ignored parameter.
+ *  @param dst_s Ignored parameter.
+ *  @param[in] dst The destination address.
+ *  @param[in] bytes The block size in bytes.
+ *  @returns EOK.
+ */
+#define sys_vircopy(proc, src_s, src, me, dst_s, dst, bytes)	({memcpy((void *)(dst), (void *)(src), (bytes)); EOK;})
+
+/** Reads a memory block byte by byte.
+ *  @param[in] port The address to be written.
+ *  @param proc The source process. Ignored parameter.
+ *  @param[in] dst The destination address.
+ *  @param[in] bytes The block size in bytes.
+ */
+#define do_vir_insb(port, proc, dst, bytes)	insb((port), (void *)(dst), (bytes))
+
+/** Reads a memory block word by word (2 bytes).
+ *  @param[in] port The address to be written.
+ *  @param proc The source process. Ignored parameter.
+ *  @param[in] dst The destination address.
+ *  @param[in] bytes The block size in bytes.
+ */
+#define do_vir_insw(port, proc, dst, bytes)	insw((port), (void *)(dst), (bytes))
+
+/** Writes a memory block byte by byte.
+ *  @param[in] port The address to be written.
+ *  @param proc The source process. Ignored parameter.
+ *  @param[in] src The source address.
+ *  @param[in] bytes The block size in bytes.
+ */
+#define do_vir_outsb(port, proc, src, bytes)	outsb((port), (void *)(src), (bytes))
+
+/** Writes a memory block word by word (2 bytes).
+ *  @param[in] port The address to be written.
+ *  @param proc The source process. Ignored parameter.
+ *  @param[in] src The source address.
+ *  @param[in] bytes The block size in bytes.
+ */
+#define do_vir_outsw(port, proc, src, bytes)	outsw((port), (void *)(src), (bytes))
+
+/* com.h */
+/* Bits in 'DL_MODE' field of DL requests. */
+#  define DL_NOMODE		0x0
+#  define DL_PROMISC_REQ	0x2
+#  define DL_MULTI_REQ		0x4
+#  define DL_BROAD_REQ		0x8
+
+/* const.h */
+/** True value.
+ */
+#define TRUE               1	/* used for turning integers into Booleans */
+
+/** False value.
+ */
+#define FALSE              0	/* used for turning integers into Booleans */
+
+/** No number value.
+ */
+#define NO_NUM        0x8000	/* used as numerical argument to panic() */
+
+/* devio.h */
+//typedef u16_t port_t;
+/** Type definition of a port.
+ */
+typedef long port_t;
+
+/* dl_eth.h */
+/** Ethernet statistics.
+ */
+typedef struct eth_stat
+{
+	/** Number of receive errors.
+	 */
+	unsigned long ets_recvErr;
+	/** Number of send error.
+	 */
+	unsigned long ets_sendErr;
+	/** Number of buffer overwrite warnings.
+	 */
+	unsigned long ets_OVW;
+	/** Number of crc errors of read.
+	 */
+	unsigned long ets_CRCerr;
+	/** Number of frames not alligned (number of bits % 8 != 0).
+	 */
+	unsigned long ets_frameAll;
+	/** Number of packets missed due to slow processing.
+	 */
+	unsigned long ets_missedP;
+	/** Number of packets received.
+	 */
+	unsigned long ets_packetR;
+	/** Number of packets transmitted.
+	 */
+	unsigned long ets_packetT;
+	/** Number of transmission defered (Tx was busy).
+	 */
+	unsigned long ets_transDef;
+	/** Number of collissions.
+	 */
+	unsigned long ets_collision;
+	/** Number of Tx aborted due to excess collisions.
+	 */
+	unsigned long ets_transAb;
+	/** Number of carrier sense lost.
+	 */
+	unsigned long ets_carrSense;
+	/** Number of FIFO underruns (processor too busy).
+	 */
+	unsigned long ets_fifoUnder;
+	/** Number of FIFO overruns (processor too busy).
+	 */
+	unsigned long ets_fifoOver;
+	/** Number of times unable to transmit collision sig.
+	 */
+	unsigned long ets_CDheartbeat;
+	/** Number of times out of window collision.
+	 */
+	unsigned long ets_OWC;
+} eth_stat_t;
+
+/* errno.h */
+/** Generic error.
+ */
+#define EGENERIC     EINVAL
+
+/* ether.h */
+/** Minimum Ethernet packet size in bytes.
+ */
+#define ETH_MIN_PACK_SIZE		  60
+
+/** Maximum Ethernet packet size in bytes.
+ */
+#define ETH_MAX_PACK_SIZE_TAGGED	1518
+
+/** Ethernet address type definition.
+ */
+typedef struct ether_addr
+{
+	/** Address data.
+	 */
+	u8_t ea_addr[6];
+} ether_addr_t;
+
+/* type.h */
+/** Type definition of the physical addresses and lengths in bytes.
+ */
+typedef unsigned long phys_bytes;
+
+/** Type definition of the virtual addresses and lengths in bytes.
+ */
+typedef unsigned long vir_bytes;
+
+/** Type definition of the input/output vector.
+ */
+typedef struct {
+	/** Address of an I/O buffer.
+	 */
+	vir_bytes iov_addr;
+	/** Sizeof an I/O buffer.
+	 */
+	vir_bytes iov_size;
+} iovec_t;
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/hw/netif/ne2000/local.h
===================================================================
--- uspace/srv/hw/netif/ne2000/local.h	(revision f483a1595e01c6dce011869a0e03969833df9750)
+++ uspace/srv/hw/netif/ne2000/local.h	(revision f483a1595e01c6dce011869a0e03969833df9750)
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 1987,1997, 2006, Vrije Universiteit, Amsterdam, The Netherlands All rights reserved. Redistribution and use of the MINIX 3 operating system 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.
+ * * Neither the name of the Vrije Universiteit nor the names of the software authors or contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+ * * Any deviations from these conditions require written permission from the copyright holder in advance
+ *
+ *
+ * Disclaimer
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, AND CONTRIBUTORS ``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 COPYRIGHT HOLDER OR ANY AUTHORS OR CONTRIBUTORS 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.
+ *
+ * Changes:
+ *  2009 ported to HelenOS, Lukas Mejdrech
+ */
+
+/** @addtogroup dp8390
+ *  @{
+ */
+
+/** @file
+ *  Network interface probe functions.
+ */
+
+#ifndef __NET_NETIF_DP8390_CONFIG_H__
+#define __NET_NETIF_DP8390_CONFIG_H__
+
+#include "dp8390_port.h"
+
+/*
+local.h
+*/
+
+/** WDETH switch.
+ */
+#define ENABLE_WDETH 0
+
+/** NE2000 switch.
+ */
+#define ENABLE_NE2000 1
+
+/** 3C503 switch.
+ */
+#define ENABLE_3C503 0
+
+/** PCI support switch.
+ */
+#define ENABLE_PCI 0
+
+struct dpeth;
+
+/* 3c503.c */
+/* * Probes a 3C503 network interface.
+ *  @param[in] dep The network interface structure.
+ *  @returns 1 if the NE2000 network interface is present.
+ *  @returns 0 otherwise.
+ */
+//_PROTOTYPE(int el2_probe, (struct dpeth*dep)				);
+
+/* ne2000.c */
+/** Probes a NE2000 or NE1000 network interface.
+ *  @param[in] dep The network interface structure.
+ *  @returns 1 if the NE2000 network interface is present.
+ *  @returns 0 otherwise.
+ */
+int ne_probe(struct dpeth * dep);
+//_PROTOTYPE(int ne_probe, (struct dpeth *dep)				);
+//_PROTOTYPE(void ne_init, (struct dpeth *dep)				);
+
+/* rtl8029.c */
+/* * Probes a RTL8029 network interface.
+ *  @param[in] dep The network interface structure.
+ *  @returns 1 if the NE2000 network interface is present.
+ *  @returns 0 otherwise.
+ */
+//_PROTOTYPE(int rtl_probe, (struct dpeth *dep)				);
+
+/* wdeth.c */
+/* * Probes a WDETH network interface.
+ *  @param[in] dep The network interface structure.
+ *  @returns 1 if the NE2000 network interface is present.
+ *  @returns 0 otherwise.
+ */
+//_PROTOTYPE(int wdeth_probe, (struct dpeth*dep)				);
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/hw/netif/ne2000/ne2000.h
===================================================================
--- uspace/srv/hw/netif/ne2000/ne2000.h	(revision f483a1595e01c6dce011869a0e03969833df9750)
+++ uspace/srv/hw/netif/ne2000/ne2000.h	(revision f483a1595e01c6dce011869a0e03969833df9750)
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 1987,1997, 2006, Vrije Universiteit, Amsterdam, The Netherlands All rights reserved. Redistribution and use of the MINIX 3 operating system 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.
+ * * Neither the name of the Vrije Universiteit nor the names of the software authors or contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+ * * Any deviations from these conditions require written permission from the copyright holder in advance
+ *
+ *
+ * Disclaimer
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, AND CONTRIBUTORS ``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 COPYRIGHT HOLDER OR ANY AUTHORS OR CONTRIBUTORS 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.
+ *
+ * Changes:
+ *  2009 ported to HelenOS, Lukas Mejdrech
+ */
+
+/*
+ne2000.h
+
+Created:	March 15, 1994 by Philip Homburg <philip@f-mnx.phicoh.com>
+*/
+
+/** @addtogroup ne2k
+ *  @{
+ */
+
+/** @file
+ *  NE1000 and NE2000 network interface definitions.
+ */
+
+#ifndef __NET_NETIF_NE2000_H__
+#define __NET_NETIF_NE2000_H__
+
+#include <libarch/ddi.h>
+
+#include "dp8390_port.h"
+
+/** DP8390 register offset.
+ */
+#define NE_DP8390	0x00
+
+/** Data register.
+ */
+#define NE_DATA		0x10
+
+/** Reset register.
+ */
+#define NE_RESET	0x1F
+
+/** NE1000 data start.
+ */
+#define NE1000_START	0x2000
+
+/** NE1000 data size.
+ */
+#define NE1000_SIZE	0x2000
+
+/** NE2000 data start.
+ */
+#define NE2000_START	0x4000
+
+/** NE2000 data size.
+ */
+#define NE2000_SIZE	0x4000
+
+/** Reads 1 byte register.
+ *  @param[in] dep The network interface structure.
+ *  @param[in] reg The register offset.
+ *  @returns The read value.
+ */
+#define inb_ne(dep, reg)	(inb(dep->de_base_port+reg))
+
+/** Writes 1 byte register.
+ *  @param[in] dep The network interface structure.
+ *  @param[in] reg The register offset.
+ *  @param[in] data The value to be written.
+ */
+#define outb_ne(dep, reg, data)	(outb(dep->de_base_port+reg, data))
+
+/** Reads 1 word (2 bytes) register.
+ *  @param[in] dep The network interface structure.
+ *  @param[in] reg The register offset.
+ *  @returns The read value.
+ */
+#define inw_ne(dep, reg)	(inw(dep->de_base_port+reg))
+
+/** Writes 1 word (2 bytes) register.
+ *  @param[in] dep The network interface structure.
+ *  @param[in] reg The register offset.
+ *  @param[in] data The value to be written.
+ */
+#define outw_ne(dep, reg, data)	(outw(dep->de_base_port+reg, data))
+
+#endif /* __NET_NETIF_NE2000_H__ */
+
+/*
+ * $PchId: ne2000.h,v 1.4 2004/08/03 12:03:20 philip Exp $
+ */
+
+/** @}
+ */
