Index: uspace/Makefile
===================================================================
--- uspace/Makefile	(revision 131d9a4ae105fe5f519d8dbbfda588ef5358a648)
+++ uspace/Makefile	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -97,4 +97,5 @@
 	srv/bd/part/mbr_part \
 	srv/fs/exfat \
+	srv/fs/udf \
 	srv/fs/fat \
 	srv/fs/cdfs \
Index: uspace/app/bdsh/errors.h
===================================================================
--- uspace/app/bdsh/errors.h	(revision 131d9a4ae105fe5f519d8dbbfda588ef5358a648)
+++ uspace/app/bdsh/errors.h	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -30,4 +30,6 @@
 #define ERRORS_H
 
+#include <io/verify.h>
+
 /* Various error levels */
 #define CL_EFATAL  -1
@@ -46,5 +48,6 @@
 extern volatile int cli_errno;
 
-extern void cli_error(int, const char *, ...);
+extern void cli_error(int, const char *, ...)
+    PRINTF_ATTRIBUTE(2, 3);
 
 #endif
Index: uspace/app/bdsh/input.c
===================================================================
--- uspace/app/bdsh/input.c	(revision 131d9a4ae105fe5f519d8dbbfda588ef5358a648)
+++ uspace/app/bdsh/input.c	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -67,7 +67,8 @@
 int process_input(cliuser_t *usr)
 {
-	token_t *tokens = calloc(WORD_MAX, sizeof(token_t));
-	if (tokens == NULL)
+	token_t *tokens_buf = calloc(WORD_MAX, sizeof(token_t));
+	if (tokens_buf == NULL)
 		return ENOMEM;
+	token_t *tokens = tokens_buf;
 	
 	char *cmd[WORD_MAX];
@@ -80,5 +81,5 @@
 
 	if (usr->line == NULL) {
-		free(tokens);
+		free(tokens_buf);
 		return CL_EFAIL;
 	}
@@ -213,5 +214,5 @@
 	}
 	tok_fini(&tok);
-	free(tokens);
+	free(tokens_buf);
 
 	return rc;
Index: uspace/app/edit/edit.c
===================================================================
--- uspace/app/edit/edit.c	(revision 131d9a4ae105fe5f519d8dbbfda588ef5358a648)
+++ uspace/app/edit/edit.c	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -111,5 +111,4 @@
 #define BUF_SIZE 64
 #define TAB_WIDTH 8
-#define ED_INFTY 65536
 
 /** Maximum filename length that can be entered. */
@@ -507,4 +506,5 @@
 static void key_handle_movement(unsigned int key, bool select)
 {
+	spt_t pt;
 	switch (key) {
 	case KC_LEFT:
@@ -521,8 +521,12 @@
 		break;
 	case KC_HOME:
-		caret_move_relative(0, -ED_INFTY, dir_after, select);
+		tag_get_pt(&pane.caret_pos, &pt);
+		pt_get_sol(&pt, &pt);
+		caret_move(pt, select, true);
 		break;
 	case KC_END:
-		caret_move_relative(0, +ED_INFTY, dir_before, select);
+		tag_get_pt(&pane.caret_pos, &pt);
+		pt_get_eol(&pt, &pt);
+		caret_move(pt, select, true);
 		break;
 	case KC_PAGE_UP:
Index: uspace/app/top/screen.h
===================================================================
--- uspace/app/top/screen.h	(revision 131d9a4ae105fe5f519d8dbbfda588ef5358a648)
+++ uspace/app/top/screen.h	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -36,4 +36,5 @@
 
 #include <io/console.h>
+#include <io/verify.h>
 #include "top.h"
 
@@ -43,5 +44,6 @@
 extern void screen_done(void);
 extern void print_data(data_t *);
-extern void show_warning(const char *, ...);
+extern void show_warning(const char *, ...)
+    PRINTF_ATTRIBUTE(1, 2);
 
 extern int tgetchar(unsigned int);
Index: uspace/dist/src/c/demos/top/screen.h
===================================================================
--- uspace/dist/src/c/demos/top/screen.h	(revision 131d9a4ae105fe5f519d8dbbfda588ef5358a648)
+++ uspace/dist/src/c/demos/top/screen.h	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -36,4 +36,5 @@
 
 #include <io/console.h>
+#include <io/verify.h>
 #include "top.h"
 
@@ -43,5 +44,6 @@
 extern void screen_done(void);
 extern void print_data(data_t *);
-extern void print_warning(const char *, ...);
+extern void print_warning(const char *, ...)
+    PRINTF_ATTRIBUTE(1, 2);
 
 extern int tgetchar(unsigned int);
Index: uspace/drv/bus/isa/i8237.c
===================================================================
--- uspace/drv/bus/isa/i8237.c	(revision 131d9a4ae105fe5f519d8dbbfda588ef5358a648)
+++ uspace/drv/bus/isa/i8237.c	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -351,5 +351,6 @@
 	
 	/* 16 bit transfers are a bit special */
-	ddf_msg(LVL_DEBUG, "Unspoiled address: %p and size: %zu.", pa, size);
+	ddf_msg(LVL_DEBUG, "Unspoiled address %#" PRIx32 " (size %" PRIu16 ")",
+	    pa, size);
 	if (channel > 4) {
 		/* Size must be aligned to 16 bits */
@@ -367,6 +368,6 @@
 	const dma_channel_t dma_channel = controller_8237.channels[channel];
 	
-	ddf_msg(LVL_DEBUG, "Setting channel %u, to address %p(%zu), mode %hhx.",
-	    channel, pa, size, mode);
+	ddf_msg(LVL_DEBUG, "Setting channel %u to address %#" PRIx32 " "
+	    "(size %" PRIu16 "), mode %hhx.", channel, pa, size, mode);
 	
 	/* Mask DMA request */
Index: uspace/drv/char/ps2mouse/ps2mouse.c
===================================================================
--- uspace/drv/char/ps2mouse/ps2mouse.c	(revision 131d9a4ae105fe5f519d8dbbfda588ef5358a648)
+++ uspace/drv/char/ps2mouse/ps2mouse.c	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -75,5 +75,5 @@
 	const ssize_t size = chardev_read(sess, &data, 1); \
 	if (size != 1) { \
-		ddf_msg(LVL_ERROR, "Failed reading byte: %d)", size);\
+		ddf_msg(LVL_ERROR, "Failed reading byte: %zd)", size);\
 		return size < 0 ? size : EIO; \
 	} \
Index: uspace/drv/nic/rtl8139/driver.c
===================================================================
--- uspace/drv/nic/rtl8139/driver.c	(revision 131d9a4ae105fe5f519d8dbbfda588ef5358a648)
+++ uspace/drv/nic/rtl8139/driver.c	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -620,6 +620,6 @@
 		/* Check if the header is valid, otherwise we are lost in the buffer */
 		if (size == 0 || size > RTL8139_FRAME_MAX_LENGTH) {
-			ddf_msg(LVL_ERROR, "Receiver error -> receiver reset (size: %4"PRIu16", "
-			    "header 0x%4"PRIx16". Offset: %zu)", size, frame_header, 
+			ddf_msg(LVL_ERROR, "Receiver error -> receiver reset (size: %4" PRIu16 ", "
+			    "header 0x%4" PRIx16 ". Offset: %d)", size, frame_header,
 			    rx_offset);
 			goto rx_err;
@@ -1162,5 +1162,5 @@
 
 	/* Allocate buffer for receiver */
-	ddf_msg(LVL_DEBUG, "Allocating receiver buffer of the size %zu bytes",
+	ddf_msg(LVL_DEBUG, "Allocating receiver buffer of the size %d bytes",
 	    RxBUF_TOT_LENGTH);
 
@@ -1249,5 +1249,5 @@
 	/* Gain control over port's registers. */
 	if (pio_enable(rtl8139->io_addr, RTL8139_IO_SIZE, &rtl8139->io_port)) {
-		ddf_msg(LVL_ERROR, "Cannot gain the port %lx for device %s.", rtl8139->io_addr,
+		ddf_msg(LVL_ERROR, "Cannot gain the port %p for device %s.", rtl8139->io_addr,
 		    ddf_dev_get_name(dev));
 		return EADDRNOTAVAIL;
@@ -1296,5 +1296,5 @@
 
 	assert(dev);
-	ddf_msg(LVL_NOTE, "RTL8139_dev_add %s (handle = %d)",
+	ddf_msg(LVL_NOTE, "RTL8139_dev_add %s (handle = %zu)",
 	    ddf_dev_get_name(dev), ddf_dev_get_handle(dev));
 
@@ -1328,5 +1328,5 @@
 	rc = nic_connect_to_services(nic_data);
 	if (rc != EOK) {
-		ddf_msg(LVL_ERROR, "Failed to connect to services", rc);
+		ddf_msg(LVL_ERROR, "Failed to connect to services (%d)", rc);
 		goto err_irq;
 	}
@@ -2139,7 +2139,8 @@
 		pio_write_32(rtl8139->io_port + TCTR, 0);
 
-		ddf_msg(LVL_DEBUG, "Periodic mode. Interrupt mask %"PRIx16", poll.full_skips %"
-		    PRIu32", last timer %"PRIu32".", rtl8139->int_mask, 
-		    rtl8139->poll_timer.full_skips, rtl8139->poll_timer.last_val);
+		ddf_msg(LVL_DEBUG, "Periodic mode. Interrupt mask %" PRIx16 ", "
+		    "poll.full_skips %zu, last timer %" PRIu32,
+		    rtl8139->int_mask, rtl8139->poll_timer.full_skips,
+		    rtl8139->poll_timer.last_val);
 		break;
 	default:
Index: uspace/lib/c/Makefile
===================================================================
--- uspace/lib/c/Makefile	(revision 131d9a4ae105fe5f519d8dbbfda588ef5358a648)
+++ uspace/lib/c/Makefile	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -95,4 +95,5 @@
 	generic/inetping.c \
 	generic/io/asprintf.c \
+	generic/io/input.c \
 	generic/io/io.c \
 	generic/io/chargrid.c \
@@ -106,4 +107,5 @@
 	generic/io/vsnprintf.c \
 	generic/io/printf_core.c \
+	generic/io/con_srv.c \
 	generic/io/console.c \
 	generic/io/visualizer.c \
Index: uspace/lib/c/arch/abs32le/_link.ld.in
===================================================================
--- uspace/lib/c/arch/abs32le/_link.ld.in	(revision 131d9a4ae105fe5f519d8dbbfda588ef5358a648)
+++ uspace/lib/c/arch/abs32le/_link.ld.in	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -15,14 +15,7 @@
 #ifdef LOADER
 	. = 0x70001000 + SIZEOF_HEADERS;
-	
-	.interp : {
-		*(.interp);
-	} :interp :text
 #else
 	. = 0x1000 + SIZEOF_HEADERS;
 #endif
-	
-	/* Make sure the code is aligned reasonably */
-	. = ALIGN(., 16);
 	
 	.text : {
@@ -30,4 +23,10 @@
 		*(.rodata .rodata.*);
 	} :text
+	
+#ifdef LOADER
+	.interp : {
+		*(.interp);
+	} :interp :text
+#endif
 	
 	. = . + 0x1000;
Index: uspace/lib/c/arch/abs32le/include/types.h
===================================================================
--- uspace/lib/c/arch/abs32le/include/types.h	(revision 131d9a4ae105fe5f519d8dbbfda588ef5358a648)
+++ uspace/lib/c/arch/abs32le/include/types.h	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -47,4 +47,5 @@
 
 typedef uint32_t sysarg_t;
+typedef int32_t native_t;
 
 typedef int32_t ssize_t;
Index: uspace/lib/c/arch/amd64/_link.ld.in
===================================================================
--- uspace/lib/c/arch/amd64/_link.ld.in	(revision 131d9a4ae105fe5f519d8dbbfda588ef5358a648)
+++ uspace/lib/c/arch/amd64/_link.ld.in	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -16,14 +16,7 @@
 #ifdef LOADER
 	. = 0x70001000 + SIZEOF_HEADERS;
-	
-	.interp : {
-		*(.interp);
-	} :interp :text
 #else
 	. = 0x1000 + SIZEOF_HEADERS;
 #endif
-	
-	/* Make sure the code is aligned reasonably */
-	. = ALIGN(., 16);
 	
 	.init : {
@@ -35,4 +28,10 @@
 		*(.rodata .rodata.*);
 	} :text
+	
+#ifdef LOADER
+	.interp : {
+		*(.interp);
+	} :interp :text
+#endif
 	
 	. = . + 0x1000;
Index: uspace/lib/c/arch/amd64/include/types.h
===================================================================
--- uspace/lib/c/arch/amd64/include/types.h	(revision 131d9a4ae105fe5f519d8dbbfda588ef5358a648)
+++ uspace/lib/c/arch/amd64/include/types.h	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -47,4 +47,5 @@
 
 typedef uint64_t sysarg_t;
+typedef int64_t native_t;
 
 typedef int64_t ssize_t;
Index: uspace/lib/c/arch/arm32/_link.ld.in
===================================================================
--- uspace/lib/c/arch/arm32/_link.ld.in	(revision 131d9a4ae105fe5f519d8dbbfda588ef5358a648)
+++ uspace/lib/c/arch/arm32/_link.ld.in	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -15,14 +15,7 @@
 #ifdef LOADER
 	. = 0x70001000 + SIZEOF_HEADERS;
-	
-	.interp : {
-		*(.interp);
-	} :interp :text
 #else
 	. = 0x1000 + SIZEOF_HEADERS;
 #endif
-	
-	/* Make sure the code is aligned reasonably */
-	. = ALIGN(., 8);
 	
 	.init : {
@@ -34,4 +27,10 @@
 		*(.rodata .rodata.*);
 	} :text
+	
+#ifdef LOADER
+	.interp : {
+		*(.interp);
+	} :interp :text
+#endif
 	
 	. = . + 0x1000;
Index: uspace/lib/c/arch/arm32/include/types.h
===================================================================
--- uspace/lib/c/arch/arm32/include/types.h	(revision 131d9a4ae105fe5f519d8dbbfda588ef5358a648)
+++ uspace/lib/c/arch/arm32/include/types.h	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -48,4 +48,5 @@
 
 typedef uint32_t sysarg_t;
+typedef int32_t native_t;
 
 typedef int32_t ssize_t;
Index: uspace/lib/c/arch/ia32/_link.ld.in
===================================================================
--- uspace/lib/c/arch/ia32/_link.ld.in	(revision 131d9a4ae105fe5f519d8dbbfda588ef5358a648)
+++ uspace/lib/c/arch/ia32/_link.ld.in	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -24,13 +24,4 @@
 	. = 0x1000 + SIZEOF_HEADERS;
 #endif
-	
-#if defined(LOADER) || defined(DLEXE)
-	.interp : {
-		*(.interp);
-	} :interp :text
-#endif
-	
-	/* Make sure the code is aligned reasonably */
-	. = ALIGN(., 16);
 	
 	.init : {
@@ -71,4 +62,11 @@
 	} :text
 #endif
+	
+#if defined(LOADER) || defined(DLEXE)
+	.interp : {
+		*(.interp);
+	} :interp :text
+#endif
+	
 	. = . + 0x1000;
 	
Index: uspace/lib/c/arch/ia32/include/types.h
===================================================================
--- uspace/lib/c/arch/ia32/include/types.h	(revision 131d9a4ae105fe5f519d8dbbfda588ef5358a648)
+++ uspace/lib/c/arch/ia32/include/types.h	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -47,4 +47,5 @@
 
 typedef uint32_t sysarg_t;
+typedef int32_t native_t;
 
 typedef int32_t ssize_t;
Index: uspace/lib/c/arch/ia64/_link.ld.in
===================================================================
--- uspace/lib/c/arch/ia64/_link.ld.in	(revision 131d9a4ae105fe5f519d8dbbfda588ef5358a648)
+++ uspace/lib/c/arch/ia64/_link.ld.in	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -15,13 +15,9 @@
 #ifdef LOADER
 	. = 0x800000000 + SIZEOF_HEADERS;
-	
-	.interp : {
-		*(.interp);
-	} :interp :text
 #else
 	. = 0x4000 + SIZEOF_HEADERS;
 #endif
 	
-	/* Make sure the code is aligned reasonably */
+	/* Workaround proper alignment of the .init section */
 	. = ALIGN(., 16);
 	
@@ -34,4 +30,10 @@
 		*(.rodata .rodata.*);
 	} :text
+	
+#ifdef LOADER
+	.interp : {
+		*(.interp);
+	} :interp :text
+#endif
 	
 	. = . + 0x4000;
Index: uspace/lib/c/arch/ia64/include/types.h
===================================================================
--- uspace/lib/c/arch/ia64/include/types.h	(revision 131d9a4ae105fe5f519d8dbbfda588ef5358a648)
+++ uspace/lib/c/arch/ia64/include/types.h	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -57,4 +57,5 @@
 
 typedef uint64_t sysarg_t;
+typedef int64_t native_t;
 
 typedef int64_t ssize_t;
Index: uspace/lib/c/arch/mips32/_link.ld.in
===================================================================
--- uspace/lib/c/arch/mips32/_link.ld.in	(revision 131d9a4ae105fe5f519d8dbbfda588ef5358a648)
+++ uspace/lib/c/arch/mips32/_link.ld.in	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -15,14 +15,7 @@
 #ifdef LOADER
 	. = 0x70004000 + SIZEOF_HEADERS;
-	
-	.interp : {
-		*(.interp);
-	} :interp :text
 #else
 	. = 0x4000 + SIZEOF_HEADERS;
 #endif
-	
-	/* Make sure the code is aligned reasonably */
-	. = ALIGN(., 16);
 	
 	.init : {
@@ -34,4 +27,10 @@
 		*(.rodata .rodata.*);
 	} :text
+	
+#ifdef LOADER
+	.interp : {
+		*(.interp);
+	} :interp :text
+#endif
 	
 	. = . + 0x4000;
Index: uspace/lib/c/arch/mips32/include/types.h
===================================================================
--- uspace/lib/c/arch/mips32/include/types.h	(revision 131d9a4ae105fe5f519d8dbbfda588ef5358a648)
+++ uspace/lib/c/arch/mips32/include/types.h	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -48,4 +48,5 @@
 
 typedef uint32_t sysarg_t;
+typedef int32_t native_t;
 
 typedef int32_t ssize_t;
Index: uspace/lib/c/arch/mips64/_link.ld.in
===================================================================
--- uspace/lib/c/arch/mips64/_link.ld.in	(revision 131d9a4ae105fe5f519d8dbbfda588ef5358a648)
+++ uspace/lib/c/arch/mips64/_link.ld.in	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -16,14 +16,7 @@
 #ifdef LOADER
 	. = 0x70004000 + SIZEOF_HEADERS;
-	
-	.interp : {
-		*(.interp);
-	} :interp :text
 #else
 	. = 0x4000 + SIZEOF_HEADERS;
 #endif
-	
-	/* Make sure the code is aligned reasonably */
-	. = ALIGN(., 16);
 	
 	.init : {
@@ -35,4 +28,10 @@
 		*(.rodata .rodata.*);
 	} :text
+	
+#ifdef LOADER
+	.interp : {
+		*(.interp);
+	} :interp :text
+#endif
 	
 	. = . + 0x4000;
Index: uspace/lib/c/arch/mips64/include/types.h
===================================================================
--- uspace/lib/c/arch/mips64/include/types.h	(revision 131d9a4ae105fe5f519d8dbbfda588ef5358a648)
+++ uspace/lib/c/arch/mips64/include/types.h	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -48,4 +48,5 @@
 
 typedef uint64_t sysarg_t;
+typedef int64_t native_t;
 
 typedef int64_t ssize_t;
Index: uspace/lib/c/arch/ppc32/_link.ld.in
===================================================================
--- uspace/lib/c/arch/ppc32/_link.ld.in	(revision 131d9a4ae105fe5f519d8dbbfda588ef5358a648)
+++ uspace/lib/c/arch/ppc32/_link.ld.in	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -16,14 +16,7 @@
 #ifdef LOADER
 	. = 0x70001000 + SIZEOF_HEADERS;
-	
-	.interp : {
-		*(.interp);
-	} :interp :text
 #else
 	. = 0x1000 + SIZEOF_HEADERS;
 #endif
-	
-	/* Make sure the code is aligned reasonably */
-	. = ALIGN(., 4);
 	
 	.init : {
@@ -35,4 +28,10 @@
 		*(.rodata .rodata.*);
 	} :text
+	
+#ifdef LOADER
+	.interp : {
+		*(.interp);
+	} :interp :text
+#endif
 	
 	. = . + 0x1000;
Index: uspace/lib/c/arch/ppc32/include/types.h
===================================================================
--- uspace/lib/c/arch/ppc32/include/types.h	(revision 131d9a4ae105fe5f519d8dbbfda588ef5358a648)
+++ uspace/lib/c/arch/ppc32/include/types.h	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -47,4 +47,5 @@
 
 typedef uint32_t sysarg_t;
+typedef int32_t native_t;
 
 typedef int32_t ssize_t;
Index: uspace/lib/c/arch/sparc64/_link.ld.in
===================================================================
--- uspace/lib/c/arch/sparc64/_link.ld.in	(revision 131d9a4ae105fe5f519d8dbbfda588ef5358a648)
+++ uspace/lib/c/arch/sparc64/_link.ld.in	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -15,14 +15,7 @@
 #ifdef LOADER
 	. = 0x70004000 + SIZEOF_HEADERS;
-	
-	.interp : {
-		*(.interp);
-	} :interp :text
 #else
 	. = 0x4000 + SIZEOF_HEADERS;
 #endif
-	
-	/* Make sure the code is aligned reasonably */
-	. = ALIGN(., 16);
 	
 	.init : {
@@ -34,4 +27,10 @@
 		*(.rodata .rodata.*);
 	} :text
+	
+#ifdef LOADER
+	.interp : {
+		*(.interp);
+	} :interp :text
+#endif
 	
 	. = . + 0x4000;
Index: uspace/lib/c/arch/sparc64/include/types.h
===================================================================
--- uspace/lib/c/arch/sparc64/include/types.h	(revision 131d9a4ae105fe5f519d8dbbfda588ef5358a648)
+++ uspace/lib/c/arch/sparc64/include/types.h	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -47,4 +47,5 @@
 
 typedef uint64_t sysarg_t;
+typedef int64_t native_t;
 
 typedef int64_t ssize_t;
Index: uspace/lib/c/generic/io/con_srv.c
===================================================================
--- uspace/lib/c/generic/io/con_srv.c	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
+++ uspace/lib/c/generic/io/con_srv.c	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -0,0 +1,409 @@
+/*
+ * Copyright (c) 2012 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 libc
+ * @{
+ */
+/**
+ * @file
+ * @brief Console protocol server stub
+ */
+#include <errno.h>
+#include <ipc/console.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+#include <io/con_srv.h>
+
+static void con_read_srv(con_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	void *buf;
+	size_t size;
+	int rc;
+	ipc_callid_t rcallid;
+
+	if (!async_data_read_receive(&rcallid, &size)) {
+		async_answer_0(callid, EINVAL);
+		return;
+	}
+
+	buf = malloc(size);
+	if (buf == NULL) {
+		async_answer_0(rcallid, ENOMEM);
+		async_answer_0(callid, ENOMEM);
+		return;
+	}
+
+	if (srv->srvs->ops->read == NULL) {
+		async_answer_0(rcallid, ENOTSUP);
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	rc = srv->srvs->ops->read(srv, buf, size);
+	if (rc < 0) {
+		async_answer_0(rcallid, rc);
+		async_answer_0(callid, rc);
+		return;
+	}
+
+	async_data_read_finalize(rcallid, buf, size);
+	free(buf);
+
+	if (rc >= 0)
+		async_answer_1(callid, EOK, rc);
+	else
+		async_answer_0(callid, rc);
+}
+
+static void con_write_srv(con_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	void *data;
+	size_t size;
+	int rc;
+
+	rc = async_data_write_accept(&data, false, 0, 0, 0, &size);
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+		return;
+	}
+
+	if (srv->srvs->ops->write == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	rc = srv->srvs->ops->write(srv, data, size);
+	free(data);
+
+	if (rc >= 0)
+		async_answer_1(callid, EOK, rc);
+	else
+		async_answer_0(callid, rc);
+}
+
+static void con_sync_srv(con_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	if (srv->srvs->ops->sync == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	srv->srvs->ops->sync(srv);
+	async_answer_0(callid, EOK);
+}
+
+static void con_clear_srv(con_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	if (srv->srvs->ops->clear == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	srv->srvs->ops->clear(srv);
+	async_answer_0(callid, EOK);
+}
+
+static void con_set_pos_srv(con_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	sysarg_t col;
+	sysarg_t row;
+
+	col = IPC_GET_ARG1(*call);
+	row = IPC_GET_ARG2(*call);
+
+	if (srv->srvs->ops->set_pos == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	srv->srvs->ops->set_pos(srv, col, row);
+	async_answer_0(callid, EOK);
+}
+
+static void con_get_pos_srv(con_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	int rc;
+	sysarg_t col;
+	sysarg_t row;
+
+	if (srv->srvs->ops->get_pos == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	rc = srv->srvs->ops->get_pos(srv, &col, &row);
+	async_answer_2(callid, rc, col, row);
+}
+
+static void con_get_size_srv(con_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	int rc;
+	sysarg_t cols;
+	sysarg_t rows;
+
+	if (srv->srvs->ops->get_size == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	rc = srv->srvs->ops->get_size(srv, &cols, &rows);
+	async_answer_2(callid, rc, cols, rows);
+}
+
+static void con_get_color_cap_srv(con_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	int rc;
+	console_caps_t ccap;
+
+	if (srv->srvs->ops->get_color_cap == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	rc = srv->srvs->ops->get_color_cap(srv, &ccap);
+	async_answer_1(callid, rc, (sysarg_t)ccap);
+}
+
+static void con_set_style_srv(con_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	console_style_t style;
+
+	style = IPC_GET_ARG1(*call);
+
+	if (srv->srvs->ops->set_style == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	srv->srvs->ops->set_style(srv, style);
+	async_answer_0(callid, EOK);
+}
+
+static void con_set_color_srv(con_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	console_color_t bgcolor;
+	console_color_t fgcolor;
+	console_color_attr_t flags;
+
+	bgcolor = IPC_GET_ARG1(*call);
+	fgcolor = IPC_GET_ARG2(*call);
+	flags = IPC_GET_ARG3(*call);
+
+	if (srv->srvs->ops->set_color == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	srv->srvs->ops->set_color(srv, bgcolor, fgcolor, flags);
+	async_answer_0(callid, EOK);
+}
+
+static void con_set_rgb_color_srv(con_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	pixel_t bgcolor;
+	pixel_t fgcolor;
+
+	bgcolor = IPC_GET_ARG1(*call);
+	fgcolor = IPC_GET_ARG2(*call);
+
+	if (srv->srvs->ops->set_rgb_color == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	srv->srvs->ops->set_rgb_color(srv, bgcolor, fgcolor);
+	async_answer_0(callid, EOK);
+}
+
+static void con_set_cursor_visibility_srv(con_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	bool show;
+
+	show = IPC_GET_ARG1(*call);
+
+	if (srv->srvs->ops->set_cursor_visibility == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	srv->srvs->ops->set_cursor_visibility(srv, show);
+	async_answer_0(callid, EOK);
+}
+
+static void con_get_event_srv(con_srv_t *srv, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	int rc;
+	kbd_event_t event;
+
+	if (srv->srvs->ops->get_event == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	rc = srv->srvs->ops->get_event(srv, &event);
+	async_answer_4(callid, rc, event.type, event.key, event.mods, event.c);
+}
+
+static con_srv_t *con_srv_create(con_srvs_t *srvs)
+{
+	con_srv_t *srv;
+
+	srv = calloc(1, sizeof(*srv));
+	if (srv == NULL)
+		return NULL;
+
+	srv->srvs = srvs;
+	return srv;
+}
+
+void con_srvs_init(con_srvs_t *srvs)
+{
+	srvs->ops = NULL;
+	srvs->sarg = NULL;
+	srvs->abort_timeout = 0;
+	srvs->aborted = false;
+}
+
+int con_conn(ipc_callid_t iid, ipc_call_t *icall, con_srvs_t *srvs)
+{
+	con_srv_t *srv;
+	int rc;
+
+	/* Accept the connection */
+	async_answer_0(iid, EOK);
+
+	srv = con_srv_create(srvs);
+	if (srv == NULL)
+		return ENOMEM;
+
+/*	async_sess_t *sess = async_callback_receive(EXCHANGE_SERIALIZE);
+	if (sess == NULL)
+		return ENOMEM;
+
+	srv->client_sess = sess;
+*/
+	srv->client_sess = NULL;
+
+	rc = srvs->ops->open(srvs, srv);
+	if (rc != EOK)
+		return rc;
+
+	while (true) {
+		ipc_call_t call;
+		ipc_callid_t callid = 0;
+
+		while (callid == 0) {
+			/* XXX Need to be able to abort immediately */
+			callid = async_get_call_timeout(&call,
+			    srvs->abort_timeout);
+
+			if (srv->srvs->aborted) {
+				if (callid != 0)
+					async_answer_0(callid, EINTR);
+				break;
+			}
+		}
+
+		if (callid == 0)
+			break;
+
+		sysarg_t method = IPC_GET_IMETHOD(call);
+
+		if (!method) {
+			/* The other side has hung up */
+			async_answer_0(callid, EOK);
+			break;
+		}
+
+		switch (method) {
+		case VFS_OUT_READ:
+			con_read_srv(srv, callid, &call);
+			break;
+		case VFS_OUT_WRITE:
+			con_write_srv(srv, callid, &call);
+			break;
+		case VFS_OUT_SYNC:
+			con_sync_srv(srv, callid, &call);
+			break;
+		case CONSOLE_CLEAR:
+			con_clear_srv(srv, callid, &call);
+			break;
+		case CONSOLE_SET_POS:
+			con_set_pos_srv(srv, callid, &call);
+			break;
+		case CONSOLE_GET_POS:
+			con_get_pos_srv(srv, callid, &call);
+			break;
+		case CONSOLE_GET_SIZE:
+			con_get_size_srv(srv, callid, &call);
+			break;
+		case CONSOLE_GET_COLOR_CAP:
+			con_get_color_cap_srv(srv, callid, &call);
+			break;
+		case CONSOLE_SET_STYLE:
+			con_set_style_srv(srv, callid, &call);
+			break;
+		case CONSOLE_SET_COLOR:
+			con_set_color_srv(srv, callid, &call);
+			break;
+		case CONSOLE_SET_RGB_COLOR:
+			con_set_rgb_color_srv(srv, callid, &call);
+			break;
+		case CONSOLE_SET_CURSOR_VISIBILITY:
+			con_set_cursor_visibility_srv(srv, callid, &call);
+			break;
+		case CONSOLE_GET_EVENT:
+			con_get_event_srv(srv, callid, &call);
+			break;
+		default:
+			async_answer_0(callid, ENOTSUP);
+		}
+	}
+
+	rc = srvs->ops->close(srv);
+	free(srv);
+
+	return rc;
+}
+
+/** @}
+ */
Index: uspace/lib/c/generic/io/console.c
===================================================================
--- uspace/lib/c/generic/io/console.c	(revision 131d9a4ae105fe5f519d8dbbfda588ef5358a648)
+++ uspace/lib/c/generic/io/console.c	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -38,5 +38,4 @@
 #include <async.h>
 #include <errno.h>
-#include <stdio.h>
 #include <malloc.h>
 #include <vfs/vfs_sess.h>
@@ -126,5 +125,5 @@
 {
 	async_exch_t *exch = async_exchange_begin(ctrl->output_sess);
-	async_req_1_0(exch, CONSOLE_CURSOR_VISIBILITY, (show != false));
+	async_req_1_0(exch, CONSOLE_SET_CURSOR_VISIBILITY, (show != false));
 	async_exchange_end(exch);
 }
@@ -151,5 +150,5 @@
 {
 	async_exch_t *exch = async_exchange_begin(ctrl->output_sess);
-	async_req_2_0(exch, CONSOLE_GOTO, col, row);
+	async_req_2_0(exch, CONSOLE_SET_POS, col, row);
 	async_exchange_end(exch);
 }
Index: uspace/lib/c/generic/io/input.c
===================================================================
--- uspace/lib/c/generic/io/input.c	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
+++ uspace/lib/c/generic/io/input.c	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 2012 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 libc
+ * @{
+ */
+/**
+ * @file
+ * @brief Input protocol client stub
+ */
+
+#include <async.h>
+#include <assert.h>
+#include <errno.h>
+#include <io/kbd_event.h>
+#include <io/input.h>
+#include <ipc/input.h>
+#include <stdlib.h>
+
+static void input_cb_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg);
+
+int input_open(async_sess_t *sess, input_ev_ops_t *ev_ops,
+    void *arg, input_t **rinput)
+{
+	input_t *input = calloc(1, sizeof(input_t));
+	if (input == NULL)
+		return ENOMEM;
+
+	input->sess = sess;
+	input->ev_ops = ev_ops;
+	input->user = arg;
+
+	async_exch_t *exch = async_exchange_begin(sess);
+
+	int rc = async_connect_to_me(exch, 0, 0, 0, input_cb_conn, input);
+	async_exchange_end(exch);
+
+	if (rc != EOK)
+		goto error;
+
+	*rinput = input;
+	return EOK;
+
+error:
+	if (input != NULL)
+		free(input);
+
+	return rc;
+}
+
+void input_close(input_t *input)
+{
+	/* XXX Synchronize with input_cb_conn */
+	free(input);
+}
+
+int input_yield(input_t *input)
+{
+	async_exch_t *exch = async_exchange_begin(input->sess);
+
+	int rc = async_req_0_0(exch, INPUT_YIELD);
+	async_exchange_end(exch);
+
+	return rc;
+}
+
+int input_reclaim(input_t *input)
+{
+	async_exch_t *exch = async_exchange_begin(input->sess);
+
+	int rc = async_req_0_0(exch, INPUT_RECLAIM);
+	async_exchange_end(exch);
+
+	return rc;
+}
+
+static void input_ev_key(input_t *input, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	kbd_event_type_t type;
+	keycode_t key;
+	keymod_t mods;
+	wchar_t c;
+	int rc;
+
+	type = IPC_GET_ARG1(*call);
+	key = IPC_GET_ARG2(*call);
+	mods = IPC_GET_ARG3(*call);
+	c = IPC_GET_ARG4(*call);
+
+	rc = input->ev_ops->key(input, type, key, mods, c);
+	async_answer_0(callid, rc);
+}
+
+static void input_ev_move(input_t *input, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	int dx;
+	int dy;
+	int rc;
+
+	dx = IPC_GET_ARG1(*call);
+	dy = IPC_GET_ARG2(*call);
+
+	rc = input->ev_ops->move(input, dx, dy);
+	async_answer_0(callid, rc);
+}
+
+static void input_ev_abs_move(input_t *input, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	unsigned x;
+	unsigned y;
+	unsigned max_x;
+	unsigned max_y;
+	int rc;
+
+	x = IPC_GET_ARG1(*call);
+	y = IPC_GET_ARG2(*call);
+	max_x = IPC_GET_ARG3(*call);
+	max_y = IPC_GET_ARG4(*call);
+
+	rc = input->ev_ops->abs_move(input, x, y, max_x, max_y);
+	async_answer_0(callid, rc);
+}
+
+static void input_ev_button(input_t *input, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	int bnum;
+	int press;
+	int rc;
+
+	bnum = IPC_GET_ARG1(*call);
+	press = IPC_GET_ARG2(*call);
+
+	rc = input->ev_ops->button(input, bnum, press);
+	async_answer_0(callid, rc);
+}
+
+static void input_cb_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
+{
+	input_t *input = (input_t *)arg;
+
+	while (true) {
+		ipc_call_t call;
+		ipc_callid_t callid = async_get_call(&call);
+
+		if (!IPC_GET_IMETHOD(call)) {
+			/* TODO: Handle hangup */
+			return;
+		}
+
+		switch (IPC_GET_IMETHOD(call)) {
+		case INPUT_EVENT_KEY:
+			input_ev_key(input, callid, &call);
+			break;
+		case INPUT_EVENT_MOVE:
+			input_ev_move(input, callid, &call);
+			break;
+		case INPUT_EVENT_ABS_MOVE:
+			input_ev_abs_move(input, callid, &call);
+			break;
+		case INPUT_EVENT_BUTTON:
+			input_ev_button(input, callid, &call);
+			break;
+		default:
+			async_answer_0(callid, ENOTSUP);
+		}
+	}
+}
+
+/** @}
+ */
Index: uspace/lib/c/generic/io/output.c
===================================================================
--- uspace/lib/c/generic/io/output.c	(revision 131d9a4ae105fe5f519d8dbbfda588ef5358a648)
+++ uspace/lib/c/generic/io/output.c	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -37,4 +37,5 @@
 #include <as.h>
 #include <ipc/output.h>
+#include <io/concaps.h>
 #include <io/output.h>
 
Index: uspace/lib/c/generic/tls.c
===================================================================
--- uspace/lib/c/generic/tls.c	(revision 131d9a4ae105fe5f519d8dbbfda588ef5358a648)
+++ uspace/lib/c/generic/tls.c	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -42,4 +42,5 @@
 #include <str.h>
 #include <align.h>
+#include <unistd.h>
 
 /** Create TLS (Thread Local Storage) data structures.
@@ -57,4 +58,6 @@
 	
 	tcb = __alloc_tls(&data, tls_size);
+	if (!tcb)
+		return NULL;
 	
 	/*
@@ -89,5 +92,8 @@
 
 	result = malloc(sizeof(tcb_t) + size);
+	if (!result)
+		return NULL;
 	*data = ((void *)result) + sizeof(tcb_t);
+
 	return result;
 }
@@ -118,5 +124,6 @@
 	size = ALIGN_UP(size, &_tls_alignment);
 	*data = memalign((uintptr_t) &_tls_alignment, sizeof(tcb_t) + size);
-
+	if (!*data)
+		return NULL;
 	tcb = (tcb_t *) (*data + size);
 	tcb->self = tcb;
Index: uspace/lib/c/include/io/con_srv.h
===================================================================
--- uspace/lib/c/include/io/con_srv.h	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
+++ uspace/lib/c/include/io/con_srv.h	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2012 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 libc
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_CON_SRV_H_
+#define LIBC_CON_SRV_H_
+
+#include <adt/list.h>
+#include <async.h>
+#include <fibril_synch.h>
+#include <io/color.h>
+#include <io/concaps.h>
+#include <io/kbd_event.h>
+#include <io/pixel.h>
+#include <io/style.h>
+#include <bool.h>
+#include <sys/time.h>
+#include <sys/types.h>
+
+typedef struct con_ops con_ops_t;
+
+/** Service setup (per sevice) */
+typedef struct {
+	con_ops_t *ops;
+	void *sarg;
+	/** Period to check for abort */
+	suseconds_t abort_timeout;
+	bool aborted;
+} con_srvs_t;
+
+/** Server structure (per client session) */
+typedef struct {
+	con_srvs_t *srvs;
+	async_sess_t *client_sess;
+	void *carg;
+} con_srv_t;
+
+typedef struct con_ops {
+	int (*open)(con_srvs_t *, con_srv_t *);
+	int (*close)(con_srv_t *);
+	int (*read)(con_srv_t *, void *, size_t);
+	int (*write)(con_srv_t *, void *, size_t);
+	void (*sync)(con_srv_t *);
+	void (*clear)(con_srv_t *);
+	void (*set_pos)(con_srv_t *, sysarg_t col, sysarg_t row);
+	int (*get_pos)(con_srv_t *, sysarg_t *, sysarg_t *);
+	int (*get_size)(con_srv_t *, sysarg_t *, sysarg_t *);
+	int (*get_color_cap)(con_srv_t *, console_caps_t *);
+	void (*set_style)(con_srv_t *, console_style_t);
+	void (*set_color)(con_srv_t *, console_color_t, console_color_t,
+	    console_color_attr_t);
+	void (*set_rgb_color)(con_srv_t *, pixel_t, pixel_t);
+	void (*set_cursor_visibility)(con_srv_t *, bool);
+	int (*get_event)(con_srv_t *, kbd_event_t *);
+} con_ops_t;
+
+extern void con_srvs_init(con_srvs_t *);
+
+extern int con_conn(ipc_callid_t, ipc_call_t *, con_srvs_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/include/io/concaps.h
===================================================================
--- uspace/lib/c/include/io/concaps.h	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
+++ uspace/lib/c/include/io/concaps.h	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2012 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 libcipc
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_IO_CONCAPS_H_
+#define LIBC_IO_CONCAPS_H_
+
+typedef enum {
+	CONSOLE_CAP_NONE = 0,
+	CONSOLE_CAP_STYLE = 1,
+	CONSOLE_CAP_INDEXED = 2,
+	CONSOLE_CAP_RGB = 4
+} console_caps_t;
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/include/io/console.h
===================================================================
--- uspace/lib/c/include/io/console.h	(revision 131d9a4ae105fe5f519d8dbbfda588ef5358a648)
+++ uspace/lib/c/include/io/console.h	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -37,15 +37,10 @@
 
 #include <sys/time.h>
+#include <io/concaps.h>
+#include <io/kbd_event.h>
 #include <io/keycode.h>
 #include <async.h>
 #include <bool.h>
 #include <stdio.h>
-
-typedef enum {
-	CONSOLE_CAP_NONE = 0,
-	CONSOLE_CAP_STYLE = 1,
-	CONSOLE_CAP_INDEXED = 2,
-	CONSOLE_CAP_RGB = 4
-} console_caps_t;
 
 /** Console control structure. */
@@ -69,27 +64,4 @@
 	aid_t input_aid;
 } console_ctrl_t;
-
-typedef enum {
-	KEY_PRESS,
-	KEY_RELEASE
-} kbd_event_type_t;
-
-/** Console event structure. */
-typedef struct {
-	/** List handle */
-	link_t link;
-	
-	/** Press or release event. */
-	kbd_event_type_t type;
-	
-	/** Keycode of the key that was pressed or released. */
-	keycode_t key;
-	
-	/** Bitmask of modifiers held. */
-	keymod_t mods;
-	
-	/** The character that was generated or '\0' for none. */
-	wchar_t c;
-} kbd_event_t;
 
 extern console_ctrl_t *console_init(FILE *, FILE *);
Index: uspace/lib/c/include/io/input.h
===================================================================
--- uspace/lib/c/include/io/input.h	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
+++ uspace/lib/c/include/io/input.h	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2012 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 libc
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_IO_INPUT_H_
+#define LIBC_IO_INPUT_H_
+
+#include <async.h>
+#include <io/kbd_event.h>
+#include <sys/types.h>
+
+struct input_ev_ops;
+
+typedef struct {
+	async_sess_t *sess;
+	struct input_ev_ops *ev_ops;
+	void *user;
+} input_t;
+
+typedef struct input_ev_ops {
+	int (*key)(input_t *, kbd_event_type_t, keycode_t, keymod_t, wchar_t);
+	int (*move)(input_t *, int, int);
+	int (*abs_move)(input_t *, unsigned, unsigned, unsigned, unsigned);
+	int (*button)(input_t *, int, int);
+} input_ev_ops_t;
+
+extern int input_open(async_sess_t *, input_ev_ops_t *, void *, input_t **);
+extern void input_close(input_t *);
+extern int input_yield(input_t *);
+extern int input_reclaim(input_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/include/io/kbd_event.h
===================================================================
--- uspace/lib/c/include/io/kbd_event.h	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
+++ uspace/lib/c/include/io/kbd_event.h	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2012 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 libc
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_IO_KBD_EVENT_H_
+#define LIBC_IO_KBD_EVENT_H_
+
+#include <adt/list.h>
+#include <io/keycode.h>
+
+typedef enum {
+	KEY_PRESS,
+	KEY_RELEASE
+} kbd_event_type_t;
+
+/** Console event structure. */
+typedef struct {
+	/** List handle */
+	link_t link;
+	
+	/** Press or release event. */
+	kbd_event_type_t type;
+	
+	/** Keycode of the key that was pressed or released. */
+	keycode_t key;
+	
+	/** Bitmask of modifiers held. */
+	keymod_t mods;
+	
+	/** The character that was generated or '\0' for none. */
+	wchar_t c;
+} kbd_event_t;
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/include/io/klog.h
===================================================================
--- uspace/lib/c/include/io/klog.h	(revision 131d9a4ae105fe5f519d8dbbfda588ef5358a648)
+++ uspace/lib/c/include/io/klog.h	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -38,8 +38,10 @@
 #include <sys/types.h>
 #include <stdarg.h>
+#include <io/verify.h>
 
 extern size_t klog_write(const void *, size_t);
 extern void klog_update(void);
-extern int klog_printf(const char *, ...);
+extern int klog_printf(const char *, ...)
+    PRINTF_ATTRIBUTE(1, 2);
 extern int klog_vprintf(const char *, va_list);
 
Index: uspace/lib/c/include/io/log.h
===================================================================
--- uspace/lib/c/include/io/log.h	(revision 131d9a4ae105fe5f519d8dbbfda588ef5358a648)
+++ uspace/lib/c/include/io/log.h	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -37,5 +37,5 @@
 #include <stdarg.h>
 #include <inttypes.h>
-#include <bool.h>
+#include <io/verify.h>
 
 typedef enum {
@@ -46,5 +46,5 @@
 	LVL_DEBUG,
 	LVL_DEBUG2,
-
+	
 	/** For checking range of values */
 	LVL_LIMIT
@@ -62,5 +62,6 @@
 extern log_t log_create(const char *, log_t);
 
-extern void log_msg(log_t, log_level_t, const char *, ...);
+extern void log_msg(log_t, log_level_t, const char *, ...)
+    PRINTF_ATTRIBUTE(3, 4);
 extern void log_msgv(log_t, log_level_t, const char *, va_list);
 
Index: uspace/lib/c/include/io/verify.h
===================================================================
--- uspace/lib/c/include/io/verify.h	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
+++ uspace/lib/c/include/io/verify.h	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2012 Martin Decky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libc
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_IO_VERIFY_H_
+#define LIBC_IO_VERIFY_H_
+
+#ifndef NVERIFY_PRINTF
+
+#define PRINTF_ATTRIBUTE(start, end) \
+	__attribute__((format(gnu_printf, start, end)))
+
+#else /* NVERIFY_PRINTF */
+
+#define PRINTF_ATTRIBUTE(start, end)
+
+#endif /* NVERIFY_PRINTF */
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/include/ipc/console.h
===================================================================
--- uspace/lib/c/include/ipc/console.h	(revision 131d9a4ae105fe5f519d8dbbfda588ef5358a648)
+++ uspace/lib/c/include/ipc/console.h	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -43,10 +43,10 @@
 	CONSOLE_GET_EVENT,
 	CONSOLE_GET_POS,
-	CONSOLE_GOTO,
+	CONSOLE_SET_POS,
 	CONSOLE_CLEAR,
 	CONSOLE_SET_STYLE,
 	CONSOLE_SET_COLOR,
 	CONSOLE_SET_RGB_COLOR,
-	CONSOLE_CURSOR_VISIBILITY
+	CONSOLE_SET_CURSOR_VISIBILITY
 } console_request_t;
 
Index: uspace/lib/c/include/stdio.h
===================================================================
--- uspace/lib/c/include/stdio.h	(revision 131d9a4ae105fe5f519d8dbbfda588ef5358a648)
+++ uspace/lib/c/include/stdio.h	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -39,15 +39,5 @@
 #include <stdarg.h>
 #include <str.h>
-
-#ifndef NVERIFY_PRINTF
-
-#define PRINTF_ATTRIBUTE(start, end) \
-	__attribute__((format(gnu_printf, start, end)))
-
-#else /* NVERIFY_PRINTF */
-
-#define PRINTF_ATTRIBUTE(start, end)
-
-#endif /* NVERIFY_PRINTF */
+#include <io/verify.h>
 
 #define EOF  (-1)
Index: uspace/lib/draw/surface.c
===================================================================
--- uspace/lib/draw/surface.c	(revision 131d9a4ae105fe5f519d8dbbfda588ef5358a648)
+++ uspace/lib/draw/surface.c	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -44,14 +44,14 @@
 	surface_flags_t flags;
 
-	sysarg_t dirty_x_lo;
-	sysarg_t dirty_x_hi;
-	sysarg_t dirty_y_lo;
-	sysarg_t dirty_y_hi;
+	surface_coord_t dirty_x_lo;
+	surface_coord_t dirty_x_hi;
+	surface_coord_t dirty_y_lo;
+	surface_coord_t dirty_y_hi;
 
 	pixelmap_t pixmap;
 };
 
-surface_t *surface_create(
-    sysarg_t width, sysarg_t height, pixel_t *pixbuf, surface_flags_t flags)
+surface_t *surface_create(surface_coord_t width, surface_coord_t height,
+    pixel_t *pixbuf, surface_flags_t flags)
 {
 	surface_t *surface = (surface_t *) malloc(sizeof(surface_t));
@@ -118,5 +118,5 @@
 }
 
-void surface_get_resolution(surface_t *surface, sysarg_t *width, sysarg_t *height)
+void surface_get_resolution(surface_t *surface, surface_coord_t *width, surface_coord_t *height)
 {
 	assert(width);
@@ -127,6 +127,6 @@
 }
 
-void surface_get_damaged_region(surface_t *surface, sysarg_t *x, sysarg_t *y,
-    sysarg_t *width, sysarg_t *height)
+void surface_get_damaged_region(surface_t *surface, surface_coord_t *x, surface_coord_t *y,
+    surface_coord_t *width, surface_coord_t *height)
 {
 	assert(x);
@@ -151,5 +151,5 @@
 }
 
-void surface_put_pixel(surface_t *surface, sysarg_t x, sysarg_t y, pixel_t pixel)
+void surface_put_pixel(surface_t *surface, surface_coord_t x, surface_coord_t y, pixel_t pixel)
 {
 	surface->dirty_x_lo = surface->dirty_x_lo > x ? x : surface->dirty_x_lo;
@@ -163,5 +163,5 @@
 }
 
-pixel_t surface_get_pixel(surface_t *surface, sysarg_t x, sysarg_t y)
+pixel_t surface_get_pixel(surface_t *surface, surface_coord_t x, surface_coord_t y)
 {
 	if (x < surface->pixmap.width && y < surface->pixmap.height) {
Index: uspace/lib/draw/surface.h
===================================================================
--- uspace/lib/draw/surface.h	(revision 131d9a4ae105fe5f519d8dbbfda588ef5358a648)
+++ uspace/lib/draw/surface.h	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -45,4 +45,6 @@
 typedef struct surface surface_t;
 
+typedef sysarg_t surface_coord_t;
+
 typedef enum {
 	SURFACE_FLAG_NONE = 0,
@@ -50,5 +52,5 @@
 } surface_flags_t;
 
-extern surface_t *surface_create(sysarg_t, sysarg_t, pixel_t *, surface_flags_t);
+extern surface_t *surface_create(surface_coord_t, surface_coord_t, pixel_t *, surface_flags_t);
 extern void surface_destroy(surface_t *);
 
@@ -56,11 +58,11 @@
 extern pixel_t *surface_direct_access(surface_t *);
 extern pixelmap_t *surface_pixmap_access(surface_t *);
-extern void surface_get_resolution(surface_t *, sysarg_t *, sysarg_t *);
-extern void surface_get_damaged_region(surface_t *, sysarg_t *, sysarg_t *,
-    sysarg_t *, sysarg_t *);
+extern void surface_get_resolution(surface_t *, surface_coord_t *, surface_coord_t *);
+extern void surface_get_damaged_region(surface_t *, surface_coord_t *, surface_coord_t *,
+    surface_coord_t *, surface_coord_t *);
 extern void surface_reset_damaged_region(surface_t *);
 
-extern void surface_put_pixel(surface_t *, sysarg_t, sysarg_t, pixel_t);
-extern pixel_t surface_get_pixel(surface_t *, sysarg_t, sysarg_t);
+extern void surface_put_pixel(surface_t *, surface_coord_t, surface_coord_t, pixel_t);
+extern pixel_t surface_get_pixel(surface_t *, surface_coord_t, surface_coord_t);
 
 #endif
Index: uspace/lib/drv/include/ddf/log.h
===================================================================
--- uspace/lib/drv/include/ddf/log.h	(revision 131d9a4ae105fe5f519d8dbbfda588ef5358a648)
+++ uspace/lib/drv/include/ddf/log.h	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -35,7 +35,9 @@
 
 #include <io/log.h>
+#include <io/verify.h>
 
 extern int ddf_log_init(const char *);
-extern void ddf_msg(log_level_t, const char *, ...);
+extern void ddf_msg(log_level_t, const char *, ...)
+    PRINTF_ATTRIBUTE(2, 3);
 
 extern void ddf_dump_buffer(char *, size_t, const void *, size_t, size_t,
Index: uspace/lib/ext4/libext4_filesystem.c
===================================================================
--- uspace/lib/ext4/libext4_filesystem.c	(revision 131d9a4ae105fe5f519d8dbbfda588ef5358a648)
+++ uspace/lib/ext4/libext4_filesystem.c	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -1284,4 +1284,9 @@
 	block_t *block;
 	while (level > 0) {
+		
+		/* Sparse check */
+		if (current_block == 0)
+			return EOK;
+		
 		int rc = block_get(&block, fs->device, current_block, 0);
 		if (rc != EOK)
Index: uspace/lib/gui/terminal.c
===================================================================
--- uspace/lib/gui/terminal.c	(revision 131d9a4ae105fe5f519d8dbbfda588ef5358a648)
+++ uspace/lib/gui/terminal.c	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -39,6 +39,7 @@
 #include <surface.h>
 #include <gfx/font-8x16.h>
+#include <io/con_srv.h>
+#include <io/concaps.h>
 #include <io/console.h>
-#include <ipc/console.h>
 #include <task.h>
 #include <adt/list.h>
@@ -60,4 +61,44 @@
 
 static LIST_INITIALIZE(terms);
+
+static int term_open(con_srvs_t *, con_srv_t *);
+static int term_close(con_srv_t *);
+static int term_read(con_srv_t *, void *, size_t);
+static int term_write(con_srv_t *, void *, size_t);
+static void term_sync(con_srv_t *);
+static void term_clear(con_srv_t *);
+static void term_set_pos(con_srv_t *, sysarg_t col, sysarg_t row);
+static int term_get_pos(con_srv_t *, sysarg_t *, sysarg_t *);
+static int term_get_size(con_srv_t *, sysarg_t *, sysarg_t *);
+static int term_get_color_cap(con_srv_t *, console_caps_t *);
+static void term_set_style(con_srv_t *, console_style_t);
+static void term_set_color(con_srv_t *, console_color_t, console_color_t,
+    console_color_attr_t);
+static void term_set_rgb_color(con_srv_t *, pixel_t, pixel_t);
+static void term_set_cursor_visibility(con_srv_t *, bool);
+static int term_get_event(con_srv_t *, kbd_event_t *);
+
+static con_ops_t con_ops = {
+	.open = term_open,
+	.close = term_close,
+	.read = term_read,
+	.write = term_write,
+	.sync = term_sync,
+	.clear = term_clear,
+	.set_pos = term_set_pos,
+	.get_pos = term_get_pos,
+	.get_size = term_get_size,
+	.get_color_cap = term_get_color_cap,
+	.set_style = term_set_style,
+	.set_color = term_set_color,
+	.set_rgb_color = term_set_rgb_color,
+	.set_cursor_visibility = term_set_cursor_visibility,
+	.get_event = term_get_event
+};
+
+static terminal_t *srv_to_terminal(con_srv_t *srv)
+{
+	return srv->srvs->sarg;
+}
 
 static void getterm(const char *svc, const char *app)
@@ -341,39 +382,18 @@
 }
 
-static void term_set_cursor(terminal_t *term, sysarg_t col, sysarg_t row)
-{
-	fibril_mutex_lock(&term->mtx);
-	chargrid_set_cursor(term->frontbuf, col, row);
-	fibril_mutex_unlock(&term->mtx);
-	
-	term_update(term);
-}
-
-static void term_set_cursor_visibility(terminal_t *term, bool visible)
-{
-	fibril_mutex_lock(&term->mtx);
-	chargrid_set_cursor_visibility(term->frontbuf, visible);
-	fibril_mutex_unlock(&term->mtx);
-	
-	term_update(term);
-}
-
-static void term_read(terminal_t *term, ipc_callid_t iid, ipc_call_t *icall)
-{
-	ipc_callid_t callid;
-	size_t size;
-	if (!async_data_read_receive(&callid, &size)) {
-		async_answer_0(callid, EINVAL);
-		async_answer_0(iid, EINVAL);
-		return;
-	}
-	
-	char *buf = (char *) malloc(size);
-	if (buf == NULL) {
-		async_answer_0(callid, ENOMEM);
-		async_answer_0(iid, ENOMEM);
-		return;
-	}
-	
+static int term_open(con_srvs_t *srvs, con_srv_t *srv)
+{
+	return EOK;
+}
+
+static int term_close(con_srv_t *srv)
+{
+	return EOK;
+}
+
+static int term_read(con_srv_t *srv, void *buf, size_t size)
+{
+	terminal_t *term = srv_to_terminal(srv);
+	uint8_t *bbuf = buf;
 	size_t pos = 0;
 	
@@ -386,5 +406,5 @@
 		/* Copy to the buffer remaining characters. */
 		while ((pos < size) && (term->char_remains_len > 0)) {
-			buf[pos] = term->char_remains[0];
+			bbuf[pos] = term->char_remains[0];
 			pos++;
 			
@@ -416,7 +436,5 @@
 	}
 	
-	(void) async_data_read_finalize(callid, buf, size);
-	async_answer_1(iid, EOK, size);
-	free(buf);
+	return size;
 }
 
@@ -449,25 +467,26 @@
 }
 
-static void term_write(terminal_t *term, ipc_callid_t iid, ipc_call_t *icall)
-{
-	void *buf;
-	size_t size;
-	int rc = async_data_write_accept(&buf, false, 0, 0, 0, &size);
-	
-	if (rc != EOK) {
-		async_answer_0(iid, rc);
-		return;
-	}
+static int term_write(con_srv_t *srv, void *data, size_t size)
+{
+	terminal_t *term = srv_to_terminal(srv);
 	
 	size_t off = 0;
 	while (off < size)
-		term_write_char(term, str_decode(buf, &off, size));
-	
-	async_answer_1(iid, EOK, size);
-	free(buf);
-}
-
-static void term_clear(terminal_t *term)
-{
+		term_write_char(term, str_decode(data, &off, size));
+	
+	return size;
+}
+
+static void term_sync(con_srv_t *srv)
+{
+	terminal_t *term = srv_to_terminal(srv);
+	
+	term_update(term);
+}
+
+static void term_clear(con_srv_t *srv)
+{
+	terminal_t *term = srv_to_terminal(srv);
+	
 	fibril_mutex_lock(&term->mtx);
 	chargrid_clear(term->frontbuf);
@@ -477,18 +496,50 @@
 }
 
-static void term_get_cursor(terminal_t *term, ipc_callid_t iid, ipc_call_t *icall)
-{
-	sysarg_t col;
-	sysarg_t row;
-	
-	fibril_mutex_lock(&term->mtx);
-	chargrid_get_cursor(term->frontbuf, &col, &row);
-	fibril_mutex_unlock(&term->mtx);
-	
-	async_answer_2(iid, EOK, col, row);
-}
-
-static void term_set_style(terminal_t *term, console_style_t style)
-{
+static void term_set_pos(con_srv_t *srv, sysarg_t col, sysarg_t row)
+{
+	terminal_t *term = srv_to_terminal(srv);
+	
+	fibril_mutex_lock(&term->mtx);
+	chargrid_set_cursor(term->frontbuf, col, row);
+	fibril_mutex_unlock(&term->mtx);
+	
+	term_update(term);
+}
+
+static int term_get_pos(con_srv_t *srv, sysarg_t *col, sysarg_t *row)
+{
+	terminal_t *term = srv_to_terminal(srv);
+	
+	fibril_mutex_lock(&term->mtx);
+	chargrid_get_cursor(term->frontbuf, col, row);
+	fibril_mutex_unlock(&term->mtx);
+	
+	return EOK;
+}
+
+static int term_get_size(con_srv_t *srv, sysarg_t *cols, sysarg_t *rows)
+{
+	terminal_t *term = srv_to_terminal(srv);
+	
+	fibril_mutex_lock(&term->mtx);
+	*cols = term->cols;
+	*rows = term->rows;
+	fibril_mutex_unlock(&term->mtx);
+	
+	return EOK;
+}
+
+static int term_get_color_cap(con_srv_t *srv, console_caps_t *caps)
+{
+	(void) srv;
+	*caps = TERM_CAPS;
+	
+	return EOK;
+}
+
+static void term_set_style(con_srv_t *srv, console_style_t style)
+{
+	terminal_t *term = srv_to_terminal(srv);
+	
 	fibril_mutex_lock(&term->mtx);
 	chargrid_set_style(term->frontbuf, style);
@@ -496,7 +547,9 @@
 }
 
-static void term_set_color(terminal_t *term, console_color_t bgcolor,
+static void term_set_color(con_srv_t *srv, console_color_t bgcolor,
     console_color_t fgcolor, console_color_attr_t attr)
 {
+	terminal_t *term = srv_to_terminal(srv);
+	
 	fibril_mutex_lock(&term->mtx);
 	chargrid_set_color(term->frontbuf, bgcolor, fgcolor, attr);
@@ -504,7 +557,9 @@
 }
 
-static void term_set_rgb_color(terminal_t *term, pixel_t bgcolor,
+static void term_set_rgb_color(con_srv_t *srv, pixel_t bgcolor,
     pixel_t fgcolor)
 {
+	terminal_t *term = srv_to_terminal(srv);
+	
 	fibril_mutex_lock(&term->mtx);
 	chargrid_set_rgb_color(term->frontbuf, bgcolor, fgcolor);
@@ -512,11 +567,24 @@
 }
 
-static void term_get_event(terminal_t *term, ipc_callid_t iid, ipc_call_t *icall)
-{
+static void term_set_cursor_visibility(con_srv_t *srv, bool visible)
+{
+	terminal_t *term = srv_to_terminal(srv);
+	
+	fibril_mutex_lock(&term->mtx);
+	chargrid_set_cursor_visibility(term->frontbuf, visible);
+	fibril_mutex_unlock(&term->mtx);
+	
+	term_update(term);
+}
+
+static int term_get_event(con_srv_t *srv, kbd_event_t *event)
+{
+	terminal_t *term = srv_to_terminal(srv);
 	link_t *link = prodcons_consume(&term->input_pc);
-	kbd_event_t *event = list_get_instance(link, kbd_event_t, link);
-	
-	async_answer_4(iid, EOK, event->type, event->key, event->mods, event->c);
-	free(event);
+	kbd_event_t *kevent = list_get_instance(link, kbd_event_t, link);
+	
+	*event = *kevent;
+	free(kevent);
+	return EOK;
 }
 
@@ -612,68 +680,7 @@
 	
 	if (atomic_postinc(&term->refcnt) == 0)
-		term_set_cursor_visibility(term, true);
-	
-	/* Accept the connection */
-	async_answer_0(iid, EOK);
-	
-	while (true) {
-		ipc_call_t call;
-		ipc_callid_t callid = async_get_call(&call);
-		
-		if (!IPC_GET_IMETHOD(call))
-			return;
-		
-		switch (IPC_GET_IMETHOD(call)) {
-		case VFS_OUT_READ:
-			term_read(term, callid, &call);
-			break;
-		case VFS_OUT_WRITE:
-			term_write(term, callid, &call);
-			break;
-		case VFS_OUT_SYNC:
-			term_update(term);
-			async_answer_0(callid, EOK);
-			break;
-		case CONSOLE_CLEAR:
-			term_clear(term);
-			async_answer_0(callid, EOK);
-			break;
-		case CONSOLE_GOTO:
-			term_set_cursor(term, IPC_GET_ARG1(call), IPC_GET_ARG2(call));
-			async_answer_0(callid, EOK);
-			break;
-		case CONSOLE_GET_POS:
-			term_get_cursor(term, callid, &call);
-			break;
-		case CONSOLE_GET_SIZE:
-			async_answer_2(callid, EOK, term->cols, term->rows);
-			break;
-		case CONSOLE_GET_COLOR_CAP:
-			async_answer_1(callid, EOK, TERM_CAPS);
-			break;
-		case CONSOLE_SET_STYLE:
-			term_set_style(term, IPC_GET_ARG1(call));
-			async_answer_0(callid, EOK);
-			break;
-		case CONSOLE_SET_COLOR:
-			term_set_color(term, IPC_GET_ARG1(call), IPC_GET_ARG2(call),
-			    IPC_GET_ARG3(call));
-			async_answer_0(callid, EOK);
-			break;
-		case CONSOLE_SET_RGB_COLOR:
-			term_set_rgb_color(term, IPC_GET_ARG1(call), IPC_GET_ARG2(call));
-			async_answer_0(callid, EOK);
-			break;
-		case CONSOLE_CURSOR_VISIBILITY:
-			term_set_cursor_visibility(term, IPC_GET_ARG1(call));
-			async_answer_0(callid, EOK);
-			break;
-		case CONSOLE_GET_EVENT:
-			term_get_event(term, callid, &call);
-			break;
-		default:
-			async_answer_0(callid, EINVAL);
-		}
-	}
+		chargrid_set_cursor_visibility(term->frontbuf, true);
+	
+	con_conn(iid, icall, &term->srvs);
 }
 
@@ -727,4 +734,8 @@
 	
 	async_set_client_connection(term_connection);
+	con_srvs_init(&term->srvs);
+	term->srvs.ops = &con_ops;
+	term->srvs.sarg = term;
+	
 	int rc = loc_server_register(NAME);
 	if (rc != EOK) {
Index: uspace/lib/gui/terminal.h
===================================================================
--- uspace/lib/gui/terminal.h	(revision 131d9a4ae105fe5f519d8dbbfda588ef5358a648)
+++ uspace/lib/gui/terminal.h	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -41,4 +41,5 @@
 #include <font.h>
 #include <io/chargrid.h>
+#include <io/con_srv.h>
 #include <adt/list.h>
 #include <adt/prodcons.h>
@@ -66,4 +67,5 @@
 	
 	service_id_t dsid;
+	con_srvs_t srvs;
 } terminal_t;
 
Index: uspace/srv/fs/udf/Makefile
===================================================================
--- uspace/srv/fs/udf/Makefile	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
+++ uspace/srv/fs/udf/Makefile	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -0,0 +1,45 @@
+#
+# Copyright (c) 2005 Martin Decky
+# Copyright (c) 2007 Jakub Jermar
+# Copyright (c) 2012 Julia Medvedeva
+# 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 = udf
+
+SOURCES = \
+	udf.c \
+	udf_volume.c \
+	udf_ops.c \
+	udf_osta.c \
+	udf_cksum.c \
+	udf_file.c \
+	udf_idx.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/srv/fs/udf/udf.c
===================================================================
--- uspace/srv/fs/udf/udf.c	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
+++ uspace/srv/fs/udf/udf.c	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2006 Martin Decky
+ * Copyright (c) 2008 Jakub Jermar
+ * Copyright (c) 2012 Julia Medvedeva
+ * 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 udf.c
+ * @brief UDF 1.02 file system driver for HelenOS.
+ */
+
+#include <ipc/services.h>
+#include <ns.h>
+#include <async.h>
+#include <errno.h>
+#include <unistd.h>
+#include <task.h>
+#include <libfs.h>
+#include <str.h>
+#include <io/log.h>
+#include "../../vfs/vfs.h"
+#include "udf.h"
+#include "udf_idx.h"
+
+#define NAME  "udf"
+
+vfs_info_t udf_vfs_info = {
+	.name = NAME,
+	.concurrent_read_write = false,
+	.write_retains_size = false,
+	.instance = 0,
+};
+
+int main(int argc, char *argv[])
+{
+	log_init(NAME);
+	log_msg(LOG_DEFAULT, LVL_NOTE, "HelenOS UDF 1.02 file system server");
+	
+	if (argc == 3) {
+		if (!str_cmp(argv[1], "--instance"))
+			udf_vfs_info.instance = strtol(argv[2], NULL, 10);
+		else {
+			log_msg(LOG_DEFAULT, LVL_FATAL, "Unrecognized parameters");
+			return 1;
+		}
+	}
+	
+	async_sess_t *vfs_sess =
+	    service_connect_blocking(EXCHANGE_SERIALIZE, SERVICE_VFS, 0, 0);
+	if (!vfs_sess) {
+		log_msg(LOG_DEFAULT, LVL_FATAL, "Failed to connect to VFS");
+		return 2;
+	}
+	
+	int rc = fs_register(vfs_sess, &udf_vfs_info, &udf_ops,
+	    &udf_libfs_ops);
+	if (rc != EOK)
+		goto err;
+	
+	rc = udf_idx_init();
+	if (rc != EOK)
+		goto err;
+	
+	log_msg(LOG_DEFAULT, LVL_NOTE, "Accepting connections");
+	task_retval(0);
+	async_manager();
+	
+	/* Not reached */
+	return 0;
+	
+err:
+	log_msg(LOG_DEFAULT, LVL_FATAL, "Failed to register file system (%d)", rc);
+	return rc;
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/fs/udf/udf.h
===================================================================
--- uspace/srv/fs/udf/udf.h	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
+++ uspace/srv/fs/udf/udf.h	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2008 Jakub Jermar
+ * Copyright (c) 2012 Julia Medvedeva
+ * 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 UDF_UDF_H_
+#define UDF_UDF_H_
+
+#include <fibril_synch.h>
+#include <libfs.h>
+#include <atomic.h>
+#include <sys/types.h>
+#include <bool.h>
+#include "../../vfs/vfs.h"
+#include "udf_types.h"
+
+#define UDF_NODE(node) \
+	((node) ? (udf_node_t *) (node)->data : NULL)
+
+#define FS_NODE(node) \
+	((node) ? (fs_node_t *) ((node)->fs_node) : NULL)
+
+#define BS_BLOCK     0
+#define MIN_SIZE     512
+#define MAX_SIZE     8192
+#define DEFAULT_VOL  0
+
+#define NODE_DIR   0
+#define NODE_FILE  1
+
+#define MAX_FILE_NAME_LEN  512
+
+#define MIN_FID_LEN  38
+
+#define SPACE_TABLE   0
+#define SPACE_BITMAP  1
+
+typedef struct udf_partition {
+	/* Partition info */
+	uint16_t number;
+	uint32_t access_type;
+	uint32_t start;
+	uint32_t lenght;
+} udf_partition_t;
+
+typedef struct udf_lvolume {
+	udf_partition_t **partitions;
+	size_t partition_cnt;
+	uint32_t logical_block_size;
+	fs_index_t root_dir;
+} udf_lvolume_t;
+
+typedef struct {
+	service_id_t service_id;
+	size_t open_nodes_count;
+	udf_charspec_t charset;
+	
+	uint32_t sector_size;
+	udf_lvolume_t *volumes;
+	udf_partition_t *partitions;
+	size_t partition_cnt;
+	udf_unallocated_space_descriptor_t *uasd;
+	uint64_t uaspace_start;
+	uint64_t uaspace_lenght;
+	uint8_t space_type;
+} udf_instance_t;
+
+typedef struct udf_allocator {
+	uint32_t length;
+	uint32_t position;
+} udf_allocator_t;
+
+typedef struct udf_node {
+	udf_instance_t *instance;
+	fs_node_t *fs_node;
+	fibril_mutex_t lock;
+	
+	fs_index_t index;  /* FID logical block */
+	link_t link;
+	size_t ref_cnt;
+	size_t link_cnt;
+	
+	uint8_t type;  /* 1 - file, 0 - directory */
+	uint64_t data_size;
+	uint8_t *data;
+	udf_allocator_t *allocators;
+	size_t alloc_size;
+} udf_node_t;
+
+extern vfs_out_ops_t udf_ops;
+extern libfs_ops_t udf_libfs_ops;
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/srv/fs/udf/udf_cksum.c
===================================================================
--- uspace/srv/fs/udf/udf_cksum.c	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
+++ uspace/srv/fs/udf/udf_cksum.c	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2012 Julia Medvedeva
+ * 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 udf_cksum.c
+ * @brief Implementation of various checksum functions.
+ */
+
+#include "udf_cksum.h"
+
+/** CRC 010041 */
+static uint16_t crc_table[256] = {
+	0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
+	0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
+	0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
+	0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
+	0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
+	0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
+	0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
+	0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
+	0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
+	0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
+	0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
+	0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
+	0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
+	0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
+	0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
+	0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
+	0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
+	0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
+	0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
+	0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
+	0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
+	0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
+	0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
+	0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
+	0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
+	0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
+	0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
+	0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
+	0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
+	0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
+	0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
+	0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
+};
+
+/** Unicode checksum
+ *
+ */
+uint16_t udf_unicode_cksum(uint16_t *buf, size_t len)
+{
+	uint16_t crc = 0;
+	
+	while (len-- > 0) {
+		/*
+		 * Take high order byte first (corresponds to a big endian
+		 * byte stream).
+		 */
+		crc = crc_table[(crc >> 8 ^ (*buf >> 8)) & 0xff] ^ (crc << 8);
+		crc = crc_table[(crc >> 8 ^ (*buf++ & 0xff)) & 0xff] ^ (crc << 8);
+	}
+	
+	return crc;
+}
+
+/** Calculate descriptor tag checksum
+ *
+ */
+uint8_t udf_tag_checksum(uint8_t *tag)
+{
+	uint8_t result = 0;
+	
+	for (size_t i = 0; i < UDF_TAG_SIZE; i++) {
+		if (i == 4)
+			continue;
+		
+		result = (result + tag[i]) % 256;
+	}
+	
+	return result;
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/fs/udf/udf_cksum.h
===================================================================
--- uspace/srv/fs/udf/udf_cksum.h	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
+++ uspace/srv/fs/udf/udf_cksum.h	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2012 Julia Medvedeva
+ * 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 UDF_CKSUM_H_
+#define UDF_CKSUM_H_
+
+#include <sys/types.h>
+#include <bool.h>
+
+#define UDF_TAG_SIZE  16
+
+extern uint16_t udf_unicode_cksum(uint16_t *, size_t);
+extern uint8_t udf_tag_checksum(uint8_t *);
+
+#endif /* UDF_CKSUM_H_ */
+
+/**
+ * @}
+ */
Index: uspace/srv/fs/udf/udf_file.c
===================================================================
--- uspace/srv/fs/udf/udf_file.c	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
+++ uspace/srv/fs/udf/udf_file.c	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -0,0 +1,627 @@
+/*
+ * Copyright (c) 2012 Julia Medvedeva
+ * 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 udf_file.c
+ * @brief Implementation of file operations. Reading and writing functions.
+ */
+
+#include <block.h>
+#include <libfs.h>
+#include <errno.h>
+#include <malloc.h>
+#include <inttypes.h>
+#include <io/log.h>
+#include <mem.h>
+#include "udf.h"
+#include "udf_file.h"
+#include "udf_cksum.h"
+#include "udf_volume.h"
+
+/** Read extended allocator in allocation sequence
+ *
+ * @paran node     UDF node
+ * @param icb_flag Type of allocators in sequence.
+ *                 According to ECMA 167 4/14.8.8
+ * @param pos      Position with which we read
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+static int udf_read_extended_allocator(udf_node_t *node, uint16_t icb_flag,
+    uint32_t pos)
+{
+	block_t *block = NULL;
+	int rc = block_get(&block, node->instance->service_id, pos,
+	    BLOCK_FLAGS_NONE);
+	if (rc != EOK)
+		return rc;
+	
+	udf_ext_ad_t *exd = (udf_ext_ad_t *) block->data;
+	uint32_t start = node->instance->partitions[
+	    FLE16(exd->extent_location.partition_num)].start +
+	    FLE32(exd->extent_location.lblock_num);
+	
+	log_msg(LOG_DEFAULT, LVL_DEBUG,
+	    "Extended allocator: start=%d, block_num=%d, len=%d", start,
+	    FLE32(exd->extent_location.lblock_num), FLE32(exd->info_length));
+	
+	uint32_t len = FLE32(exd->info_length);
+	block_put(block);
+	
+	return udf_read_allocation_sequence(node, NULL, icb_flag, start, len);
+}
+
+/** Read ICB sequence of allocators in (Extended) File entry descriptor
+ *
+ * @parem node     UDF node
+ * @param af       (Extended) File entry descriptor
+ * @param icb_flag Type of allocators in sequence.
+ *                 According to ECMA 167 4/14.8.8
+ * @param start_alloc Offset of the allocator
+ * @param len         Length of sequence
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+int udf_read_allocation_sequence(udf_node_t *node, uint8_t *af,
+    uint16_t icb_flag, uint32_t start_alloc, uint32_t len)
+{
+	node->alloc_size = 0;
+	
+	switch (icb_flag) {
+	case UDF_SHORT_AD:
+		log_msg(LOG_DEFAULT, LVL_DEBUG,
+		    "ICB: sequence of allocation descriptors - icbflag = short_ad_t");
+		
+		/*
+		 * Identify number of current partition. Virtual partition
+		 * could placed inside of physical partition. It means that same
+		 * sector could be inside of both partition physical and virtual.
+		 */
+		size_t pd_num = (size_t) -1;
+		size_t min_start = 0;
+		
+		for (size_t i = 0; i < node->instance->partition_cnt; i++) {
+			if ((node->index >= node->instance->partitions[i].start) &&
+			    (node->index < node->instance->partitions[i].start +
+			    node->instance->partitions[i].lenght)) {
+				if (node->instance->partitions[i].start >= min_start) {
+					min_start = node->instance->partitions[i].start;
+					pd_num = i;
+				}
+			}
+		}
+		
+		if (pd_num == (size_t) -1)
+			return ENOENT;
+		
+		/*
+		 * According to doc, in this we should stop our loop if pass
+		 * all allocators. Count of items in sequence of allocators
+		 * cnt = len / sizeof(udf_long_ad_t)
+		 * But in case of Blu-Ray data len could be zero.
+		 * It means that we have only two conditions for stopping
+		 * which we check inside of loop.
+		 */
+		
+		while (true) {
+			udf_short_ad_t *short_d =
+			    (udf_short_ad_t *) (af + start_alloc +
+			    node->alloc_size * sizeof(udf_short_ad_t));
+			
+			if (FLE32(short_d->length) == 0)
+				break;
+			
+			/*
+			 * ECMA 167 4/12 - next sequence of allocation descriptors
+			 * condition according to 167 4/14.6.8
+			 */
+			if (FLE32(short_d->length) >> 30 == 3) {
+				udf_read_extended_allocator(node, icb_flag,
+				    node->instance->partitions[pd_num].start +
+				    FLE32(short_d->position));
+				break;
+			}
+			
+			node->allocators = realloc(node->allocators,
+			    (node->alloc_size + 1) * sizeof(udf_allocator_t));
+			node->allocators[node->alloc_size].length =
+			    EXT_LENGTH(FLE32(short_d->length));
+			node->allocators[node->alloc_size].position =
+			    node->instance->partitions[pd_num].start + FLE32(short_d->position);
+			node->alloc_size++;
+		}
+		
+		node->allocators = realloc(node->allocators,
+		    node->alloc_size * sizeof(udf_allocator_t));
+		break;
+		
+	case UDF_LONG_AD:
+		log_msg(LOG_DEFAULT, LVL_DEBUG,
+		    "ICB: sequence of allocation descriptors - icbflag = long_ad_t");
+		
+		while (true) {
+			udf_long_ad_t *long_d =
+			    (udf_long_ad_t *) (af + start_alloc +
+			    node->alloc_size * sizeof(udf_long_ad_t));
+			
+			if (FLE32(long_d->length) == 0)
+				break;
+			
+			uint32_t pos_long_ad = udf_long_ad_to_pos(node->instance, long_d);
+			
+			/*
+			 * ECMA 167 4/12 - next sequence of allocation descriptors
+			 * condition according to 167 4/14.6.8
+			 */
+			if (FLE32(long_d->length) >> 30 == 3) {
+				udf_read_extended_allocator(node, icb_flag, pos_long_ad);
+				break;
+			}
+			
+			node->allocators = realloc(node->allocators,
+			    (node->alloc_size + 1) * sizeof(udf_allocator_t));
+			node->allocators[node->alloc_size].length =
+			    EXT_LENGTH(FLE32(long_d->length));
+			node->allocators[node->alloc_size].position = pos_long_ad;
+			
+			node->alloc_size++;
+		}
+		
+		node->allocators = realloc(node->allocators,
+		    node->alloc_size * sizeof(udf_allocator_t));
+		break;
+		
+	case UDF_EXTENDED_AD:
+		log_msg(LOG_DEFAULT, LVL_DEBUG,
+		    "ICB: sequence of allocation descriptors - icbflag = extended_ad_t");
+		break;
+		
+	case UDF_DATA_AD:
+		log_msg(LOG_DEFAULT, LVL_DEBUG,
+		    "ICB: sequence of allocation descriptors - icbflag = 3, node contains data itself");
+		
+		node->data = malloc(node->data_size);
+		if (!node->data)
+			return ENOMEM;
+		
+		memcpy(node->data, (af + start_alloc), node->data_size);
+		node->alloc_size = 0;
+		break;
+	}
+	
+	return EOK;
+}
+
+/** Read ICB sequence of descriptors
+ *
+ * Read sequence of descriptors (file entry descriptors or
+ * extended file entry descriptors). Each descriptor contains
+ * sequence of allocators.
+ *
+ * @param node    UDF node
+ *
+ * @return    EOK on success or a negative error code.
+ */
+int udf_read_icb(udf_node_t *node)
+{
+	while (true) {
+		fs_index_t pos = node->index;
+		
+		block_t *block = NULL;
+		int rc = block_get(&block, node->instance->service_id, pos,
+		    BLOCK_FLAGS_NONE);
+		if (rc != EOK)
+			return rc;
+		
+		udf_descriptor_tag_t *data = (udf_descriptor_tag_t *) block->data;
+		if (data->checksum != udf_tag_checksum((uint8_t *) data)) {
+			block_put(block);
+			return EINVAL;
+		}
+		
+		/* One sector size descriptors */
+		switch (FLE16(data->id)) {
+		case UDF_FILE_ENTRY:
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "ICB: File entry descriptor found");
+			
+			udf_file_entry_descriptor_t *file =
+			    (udf_file_entry_descriptor_t *) block->data;
+			uint16_t icb_flag = FLE16(file->icbtag.flags) & UDF_ICBFLAG_MASK;
+			node->data_size = FLE64(file->info_lenght);
+			node->type = (file->icbtag.file_type == UDF_ICBTYPE_DIR) ? NODE_DIR : NODE_FILE;
+			
+			rc = udf_read_allocation_sequence(node, (uint8_t *) file, icb_flag,
+			    FLE32(file->ea_lenght) + UDF_FE_OFFSET, FLE32(file->ad_lenght));
+			block_put(block);
+			return rc;
+			
+		case UDF_EFILE_ENTRY:
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "ICB: Extended file entry descriptor found");
+			
+			udf_extended_file_entry_descriptor_t *efile =
+			    (udf_extended_file_entry_descriptor_t *) block->data;
+			icb_flag = FLE16(efile->icbtag.flags) & UDF_ICBFLAG_MASK;
+			node->data_size = FLE64(efile->info_lenght);
+			node->type = (efile->icbtag.file_type == UDF_ICBTYPE_DIR) ? NODE_DIR : NODE_FILE;
+			
+			rc = udf_read_allocation_sequence(node, (uint8_t *) efile, icb_flag,
+			    FLE32(efile->ea_lenght) + UDF_EFE_OFFSET, FLE32(efile->ad_lenght));
+			block_put(block);
+			return rc;
+			
+		case UDF_ICB_TERMINAL:
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "ICB: Terminal entry descriptor found");
+			block_put(block);
+			return EOK;
+		}
+		
+		pos++;
+		
+		rc = block_put(block);
+		if (rc != EOK)
+			return rc;
+	}
+	
+	return EOK;
+}
+
+/** Read data from disk - filling UDF node by allocators
+ *
+ * @param node UDF node
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+int udf_node_get_core(udf_node_t *node)
+{
+	node->link_cnt = 1;
+	return udf_read_icb(node);
+}
+
+/** Read directory entry if all FIDs is saved inside of descriptor
+ *
+ * @param fid  Returned value
+ * @param node UDF node
+ * @param pos  Number of FID which we need to find
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+static int udf_get_fid_in_data(udf_file_identifier_descriptor_t **fid,
+    udf_node_t *node, aoff64_t pos)
+{
+	size_t fid_sum = 0;
+	size_t n = 0;
+	
+	while (node->data_size - fid_sum >= MIN_FID_LEN) {
+		udf_descriptor_tag_t *desc =
+		    (udf_descriptor_tag_t *) (node->data + fid_sum);
+		if (desc->checksum != udf_tag_checksum((uint8_t *) desc)) {
+			if (fid_sum == 0)
+				return EINVAL;
+			else
+				return ENOENT;
+		}
+		
+		*fid = (udf_file_identifier_descriptor_t *)
+		    (node->data + fid_sum);
+		
+		/* According to ECMA 167 4/14.4.9 */
+		size_t padding = 4 * (((*fid)->lenght_file_id +
+		    FLE16((*fid)->lenght_iu) + 38 + 3) / 4) -
+		    ((*fid)->lenght_file_id + FLE16((*fid)->lenght_iu) + 38);
+		size_t size_fid = (*fid)->lenght_file_id +
+		    FLE16((*fid)->lenght_iu) + padding + 38;
+		
+		fid_sum += size_fid;
+		
+		/* aAcording to ECMA 167 4/8.6 */
+		if (((*fid)->lenght_file_id != 0) &&
+		    (((*fid)->file_characteristics & 4) == 0)) {
+			n++;
+			
+			if (n == pos + 1)
+				return EOK;
+		}
+	}
+	
+	return ENOENT;
+}
+
+/** Read directory entry
+ *
+ * @param fid   Returned value
+ * @param block Returned value
+ * @param node  UDF node
+ * @param pos   Number of FID which we need to find
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+int udf_get_fid(udf_file_identifier_descriptor_t **fid, block_t **block,
+    udf_node_t *node, aoff64_t pos)
+{
+	if (node->data == NULL)
+		return udf_get_fid_in_allocator(fid, block, node, pos);
+	
+	return udf_get_fid_in_data(fid, node, pos);
+}
+
+/** Read directory entry if all FIDS is saved in allocators.
+ *
+ * @param fid   Returned value
+ * @param block Returned value
+ * @param node  UDF node
+ * @param pos   Number of FID which we need to find
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+int udf_get_fid_in_allocator(udf_file_identifier_descriptor_t **fid,
+    block_t **block, udf_node_t *node, aoff64_t pos)
+{
+	void *buf = malloc(node->instance->sector_size);
+	
+	// FIXME: Check for NULL return value
+	
+	size_t j = 0;
+	size_t n = 0;
+	size_t len = 0;
+	
+	while (j < node->alloc_size) {
+		size_t i = 0;
+		while (i * node->instance->sector_size < node->allocators[j].length) {
+			int rc = block_get(block, node->instance->service_id,
+			    node->allocators[j].position + i, BLOCK_FLAGS_NONE);
+			if (rc != EOK) {
+				// FIXME: Memory leak
+				return rc;
+			}
+			
+			/*
+			 * Last item in allocator is a part of sector. We take
+			 * this fragment and join it to part of sector in next allocator.
+			 */
+			if ((node->allocators[j].length / node->instance->sector_size == i) &&
+			    (node->allocators[j].length - i * node->instance->sector_size <
+			    MIN_FID_LEN)) {
+				size_t len = node->allocators[j].length - i * node->instance->sector_size;
+				memcpy(buf, (*block)->data, len);
+				block_put(*block);
+				*block = NULL;
+				break;
+			}
+			
+			rc = udf_get_fid_in_sector(fid, block, node, pos, &n, &buf, &len);
+			if (rc == EOK) {
+				// FIXME: Memory leak
+				return EOK;
+			}
+			
+			if (rc == EINVAL) {
+				// FIXME: Memory leak
+				return ENOENT;
+			}
+			
+			if (rc == ENOENT) {
+				if (block) {
+					rc = block_put(*block);
+					*block = NULL;
+					
+					if (rc != EOK)
+						return rc;
+				}
+			}
+			
+			i++;
+		}
+		
+		j++;
+	}
+	
+	if (buf)
+		free(buf);
+	
+	return ENOENT;
+}
+
+/** Read FIDs in sector inside of current allocator
+ *
+ * @param fid   Returned value.
+ * @param block Returned value
+ * @param node  UDF node
+ * @param pos   Number FID which we need to find
+ * @param n     Count of FIDs which we already have passed
+ * @param buf   Part of FID from last sector (current allocator or previous)
+ * @param len   Length of buf
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+int udf_get_fid_in_sector(udf_file_identifier_descriptor_t **fid,
+    block_t **block, udf_node_t *node, aoff64_t pos, size_t *n, void **buf,
+    size_t *len)
+{
+	void *fidbuf = malloc(node->instance->sector_size);
+	
+	// FIXME: Check for NULL return value
+	
+	bool buf_flag;
+	
+	if (*len > 0) {
+		memcpy(fidbuf, *buf, *len);
+		buf_flag = true;
+	} else
+		buf_flag = false;
+	
+	size_t fid_sum = 0;
+	while (node->instance->sector_size - fid_sum > 0) {
+		if (node->instance->sector_size - fid_sum >= MIN_FID_LEN) {
+			void *fid_data;
+			
+			if (buf_flag) {
+				memcpy((fidbuf + *len), (*block)->data,
+				    node->instance->sector_size - *len);
+				fid_data = fidbuf;
+			} else
+				fid_data = (*block)->data + fid_sum;
+			
+			udf_descriptor_tag_t *desc =
+			    (udf_descriptor_tag_t *) fid_data;
+			
+			if (desc->checksum != udf_tag_checksum((uint8_t *) desc)) {
+				if (fidbuf)
+					free(fidbuf);
+				
+				if (*buf) {
+					free(*buf);
+					*buf = NULL;
+					*len = 0;
+				}
+				
+				return EINVAL;
+			}
+			
+			*fid = (udf_file_identifier_descriptor_t *) fid_data;
+			
+			/* According to ECMA 167 4/14.4.9 */
+			size_t padding = 4 * (((*fid)->lenght_file_id +
+			    FLE16((*fid)->lenght_iu) + 38 + 3) / 4) -
+			    ((*fid)->lenght_file_id + FLE16((*fid)->lenght_iu) + 38);
+			size_t size_fid = (*fid)->lenght_file_id +
+			    FLE16((*fid)->lenght_iu) + padding + 38;
+			if (buf_flag)
+				fid_sum += size_fid - *len;
+			else
+				fid_sum += size_fid;
+			
+			/* According to ECMA 167 4/8.6 */
+			if (((*fid)->lenght_file_id != 0) &&
+			    (((*fid)->file_characteristics & 4) == 0)) {
+				(*n)++;
+				if (*n == pos + 1) {
+					if (fidbuf)
+						free(fidbuf);
+					
+					return EOK;
+				}
+			}
+			
+			if (fidbuf) {
+				buf_flag = false;
+				free(fidbuf);
+				fidbuf = NULL;
+			}
+			
+			if (*buf) {
+				free(*buf);
+				*buf = NULL;
+				*len = 0;
+			}
+		} else {
+			if (*buf)
+				free(*buf);
+			
+			*len = node->instance->sector_size - fid_sum;
+			*buf = malloc(*len);
+			buf_flag = false;
+			memcpy(*buf, ((*block)->data + fid_sum), *len);
+			
+			return ENOENT;
+		}
+	}
+	
+	return ENOENT;
+}
+
+/** Read file if it is saved in allocators.
+ *
+ * @param read_len Returned value. Length file or part file which we could read.
+ * @param callid
+ * @param node     UDF node
+ * @param pos      Position in file since we have to read.
+ * @param len      Length of data for reading
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+int udf_read_file(size_t *read_len, ipc_callid_t callid, udf_node_t *node,
+    aoff64_t pos, size_t len)
+{
+	size_t i = 0;
+	size_t l = 0;
+	
+	while (i < node->alloc_size) {
+		if (pos >= l + node->allocators[i].length) {
+			l += node->allocators[i].length;
+			i++;
+		} else
+			break;
+	}
+	
+	size_t sector_cnt = ALL_UP(l, node->instance->sector_size);
+	size_t sector_num = pos / node->instance->sector_size;
+	
+	block_t *block = NULL;
+	int rc = block_get(&block, node->instance->service_id,
+	    node->allocators[i].position + (sector_num - sector_cnt),
+	    BLOCK_FLAGS_NONE);
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+		return rc;
+	}
+	
+	size_t sector_pos = pos % node->instance->sector_size;
+	
+	if (sector_pos + len < node->instance->sector_size)
+		*read_len = len;
+	else
+		*read_len = node->instance->sector_size - sector_pos;
+	
+	if (ALL_UP(node->allocators[i].length, node->instance->sector_size) ==
+	    sector_num - sector_cnt + 1) {
+		if (pos + len > node->allocators[i].length + l)
+			*read_len = node->allocators[i].length -
+			    (sector_num - sector_cnt) * node->instance->sector_size -
+			    sector_pos;
+		else
+			*read_len = len;
+	}
+	
+	async_data_read_finalize(callid, block->data + sector_pos, *read_len);
+	return block_put(block);
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/fs/udf/udf_file.h
===================================================================
--- uspace/srv/fs/udf/udf_file.h	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
+++ uspace/srv/fs/udf/udf_file.h	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 2012 Julia Medvedeva
+ * 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 UDF_FILE_H_
+#define UDF_FILE_H_
+
+#include <sys/types.h>
+#include <ipc/loc.h>
+#include <block.h>
+#include "udf_types.h"
+
+#define UDF_TAG_FILESET  256
+#define UDF_TAG_FILEID   257
+
+#define UDF_ICB_TERMINAL   260
+#define UDF_FILE_ENTRY     261
+#define UDF_UASPACE_ENTRY  263
+#define UDF_SPACE_BITMAP   264
+#define UDF_EFILE_ENTRY    266
+
+#define UDF_FE_OFFSET   176
+#define UDF_EFE_OFFSET  216
+#define UDF_SB_OFFSET   24
+
+/* ECMA 4/14.11 */
+#define UDF_UASE_OFFSET  40
+
+/* ECMA 167 4/14.6.8 */
+#define UDF_ICBFLAG_MASK  7
+
+/* ECMA 167 4/17 */
+#define UDF_ICBTYPE_UASE  1
+#define UDF_ICBTYPE_DIR   4
+
+/* ECMA 167 4/14.6.8 */
+#define UDF_SHORT_AD     0
+#define UDF_LONG_AD      1
+#define UDF_EXTENDED_AD  2
+
+/* File in allocation descriptor */
+#define UDF_DATA_AD  3
+
+/* File Set Descriptor (ECMA 167 4/14.1) */
+typedef struct udf_fileset_descriptor {
+	udf_descriptor_tag_t tag;
+	udf_timestamp_t recording_date_and_time;
+	uint16_t interchange_level;
+	uint16_t max_interchange_level;
+	uint32_t charset_list;
+	uint32_t max_charset_list;
+	uint32_t fileset_number;
+	uint32_t fileset_descriptor_number;
+	udf_charspec_t logical_volume_id_charset;
+	udf_dstring logical_volume_id[128];
+	udf_charspec_t fileset_charset;
+	udf_dstring fileset_id[32];
+	udf_dstring copyright_file_id[32];
+	udf_dstring abstract_file_id[32];
+	udf_long_ad_t root_dir_icb;
+	udf_regid_t domain_id;
+	udf_long_ad_t next_extent;
+	udf_long_ad_t system_stream_dir_icb;
+	uint8_t reserved[32];
+} __attribute__((packed)) udf_fileset_descriptor_t;
+
+/* File identifier descriptor format (ECMA 167 4/14.4) */
+typedef struct udf_file_identifier_descriptor {
+	udf_descriptor_tag_t tag;
+	uint16_t file_version_number;
+	uint8_t file_characteristics;
+	uint8_t lenght_file_id;
+	udf_long_ad_t icb;
+	uint16_t lenght_iu;
+	uint8_t implementation_use[0];
+	udf_dstring file_id[0];
+}__attribute__((packed)) udf_file_identifier_descriptor_t;
+
+/* ICB tag - Information Control Block  (ECMA 167 4/14.6) */
+typedef struct udf_icbtag {
+	uint32_t prior_recorder_nimber;
+	uint16_t strategy_type;
+	uint8_t strategy_parameter[2];
+	uint16_t max_number;
+	uint8_t reserved[1];
+	uint8_t file_type;
+	udf_lb_addr_t parent_icb;
+	uint16_t flags;
+} __attribute__((packed)) udf_icbtag_t;
+
+/* File Entry format (ECMA 167 4/14.9) */
+typedef struct udf_file_entry_descriptor {
+	udf_descriptor_tag_t tag;
+	udf_icbtag_t icbtag;
+	uint32_t uid;
+	uint32_t gid;
+	uint32_t permission;
+	uint16_t file_link_count;
+	uint8_t record_format;
+	uint8_t record_display_attributes;
+	uint32_t record_lenght;
+	uint64_t info_lenght;
+	uint64_t lblocks_recorded;
+	udf_timestamp_t access_data_and_time;
+	udf_timestamp_t mod_data_and_time;
+	udf_timestamp_t attribute_data_and_time;
+	uint32_t checkpoint;
+	udf_long_ad_t extended_attribute_icb;
+	udf_regid_t implementation_id;
+	uint64_t unique_id;
+	uint32_t ea_lenght;
+	uint32_t ad_lenght;
+	uint8_t extended_attributes [0];
+	uint8_t allocation_descriptors[0];
+} __attribute__((packed)) udf_file_entry_descriptor_t;
+
+/* Extended File Entry format (ECMA 167 4/14.17) */
+typedef struct udf_extended_file_entry_descriptor {
+	udf_descriptor_tag_t tag;
+	udf_icbtag_t icbtag;
+	uint32_t uid;
+	uint32_t gid;
+	uint32_t permission;
+	uint16_t file_link_count;
+	uint8_t record_format;
+	uint8_t record_display_attributes;
+	uint32_t record_lenght;
+	uint64_t info_lenght;
+	uint64_t object_size;
+	uint64_t lblocks_recorded;
+	udf_timestamp_t access_data_and_time;
+	udf_timestamp_t mod_data_and_time;
+	udf_timestamp_t creation_data_and_time;
+	udf_timestamp_t attribute_data_and_time;
+	uint32_t checkpoint;
+	udf_long_ad_t extended_attribute_icb;
+	udf_regid_t implementation_id;
+	uint64_t unique_id;
+	uint32_t ea_lenght;
+	uint32_t ad_lenght;
+	uint8_t extended_attributes [0];
+	uint8_t allocation_descriptors[0];
+} __attribute__((packed)) udf_extended_file_entry_descriptor_t;
+
+/* Terminal Entry Descriptor (ECMA 167 4/14.8) */
+typedef struct terminal_entry_descriptor {
+	udf_descriptor_tag_t tag;
+	udf_icbtag_t icbtag;
+} __attribute__((packed)) udf_terminal_entry_descriptor;
+
+/* Unallocated Space Entry format (ECMA 167 4/14.11)*/
+typedef struct udf_unallocated_space_entry_descriptor {
+	udf_descriptor_tag_t tag;
+	udf_icbtag_t icbtag;
+	uint32_t ad_lenght;
+	uint8_t allocation_descriptors[0];
+}__attribute__((packed)) udf_unallocated_space_entry_descriptor_t;
+
+/* Space Bitmap Descriptor format (ECMA 167 4/14.12) */
+typedef struct udf_space_bitmap_descriptor {
+	udf_descriptor_tag_t tag;
+	uint32_t bits_number;
+	uint32_t byts_number;
+	uint8_t bitmap[0];
+}__attribute__((packed)) udf_space_bitmap_descriptor_t;
+
+extern int udf_node_get_core(udf_node_t *);
+extern int udf_read_icb(udf_node_t *);
+extern int udf_read_allocation_sequence(udf_node_t *, uint8_t *, uint16_t,
+    uint32_t, uint32_t);
+extern int udf_read_file(size_t *, ipc_callid_t, udf_node_t *, aoff64_t,
+    size_t);
+extern int udf_get_fid(udf_file_identifier_descriptor_t **, block_t **,
+    udf_node_t *, aoff64_t);
+extern int udf_get_fid_in_allocator(udf_file_identifier_descriptor_t **,
+    block_t **, udf_node_t *, aoff64_t);
+extern int udf_get_fid_in_sector(udf_file_identifier_descriptor_t **,
+    block_t **, udf_node_t *, aoff64_t, size_t *, void **, size_t *);
+
+#endif /* UDF_FILE_H_ */
+
+/**
+ * @}
+ */
Index: uspace/srv/fs/udf/udf_idx.c
===================================================================
--- uspace/srv/fs/udf/udf_idx.c	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
+++ uspace/srv/fs/udf/udf_idx.c	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 2012 Julia Medvedeva
+ * 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 udf_idx.c
+ * @brief Very simple UDF hashtable for nodes
+ */
+
+#include "../../vfs/vfs.h"
+#include <errno.h>
+#include <str.h>
+#include <assert.h>
+#include <fibril_synch.h>
+#include <malloc.h>
+#include <adt/hash_table.h>
+#include <adt/list.h>
+#include "udf_idx.h"
+#include "udf.h"
+
+#define UDF_IDX_KEYS  2
+#define UDF_IDX_KEY   1
+
+#define UDF_IDX_SERVICE_ID_KEY  0
+#define UDF_IDX_BUCKETS         1024
+
+static FIBRIL_MUTEX_INITIALIZE(udf_idx_lock);
+
+static hash_table_t udf_idx;
+
+/** Calculate value of hash by key
+ *
+ * @param Key for calculation of function
+ *
+ * @return Value of hash function
+ *
+ */
+static hash_index_t udf_idx_hash(unsigned long key[])
+{
+	/* TODO: This is very simple and probably can be improved */
+	return key[UDF_IDX_KEY] % UDF_IDX_BUCKETS;
+}
+
+/** Compare two items of hash table
+ *
+ * @param key  Key of hash table item. Include several items.
+ * @param keys Number of parts of key.
+ * @param item Item of hash table
+ *
+ * @return True if input value of key equivalent key of node from hash table
+ *
+ */
+static int udf_idx_compare(unsigned long key[], hash_count_t keys, link_t *item)
+{
+	assert(keys > 0);
+	
+	udf_node_t *node = hash_table_get_instance(item, udf_node_t, link);
+	
+	if (node->instance->service_id !=
+	    ((service_id_t) key[UDF_IDX_SERVICE_ID_KEY]))
+		return false;
+	
+	assert(keys == 2);
+	return (node->index == key[UDF_IDX_KEY]);
+}
+
+/** Remove callback
+ *
+ */
+static void udf_idx_remove_cb(link_t *link)
+{
+	/* We don't use remove callback for this hash table */
+}
+
+static hash_table_operations_t udf_idx_ops = {
+	.hash = udf_idx_hash,
+	.compare = udf_idx_compare,
+	.remove_callback = udf_idx_remove_cb,
+};
+
+/** Initialization of hash table
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+int udf_idx_init(void)
+{
+	if (!hash_table_create(&udf_idx, UDF_IDX_BUCKETS, UDF_IDX_KEYS,
+	    &udf_idx_ops))
+		return ENOMEM;
+	
+	return EOK;
+}
+
+/** Delete hash table
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+int udf_idx_fini(void)
+{
+	hash_table_destroy(&udf_idx);
+	return EOK;
+}
+
+/** Get node from hash table
+ *
+ * @param udfn     Returned value - UDF node
+ * @param instance UDF instance
+ * @param index    Absolute position of ICB (sector)
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+int udf_idx_get(udf_node_t **udfn, udf_instance_t *instance, fs_index_t index)
+{
+	fibril_mutex_lock(&udf_idx_lock);
+	
+	unsigned long key[] = {
+		[UDF_IDX_SERVICE_ID_KEY] = instance->service_id,
+		[UDF_IDX_KEY] = index
+	};
+	
+	link_t *already_open = hash_table_find(&udf_idx, key);
+	if (already_open) {
+		udf_node_t *node = hash_table_get_instance(already_open,
+		    udf_node_t, link);
+		node->ref_cnt++;
+		
+		*udfn = node;
+		
+		fibril_mutex_unlock(&udf_idx_lock);
+		return EOK;
+	}
+	
+	fibril_mutex_unlock(&udf_idx_lock);
+	return ENOENT;
+}
+
+/** Create new node in hash table
+ *
+ * @param udfn     Returned value - new UDF node
+ * @param instance UDF instance
+ * @param index    Absolute position of ICB (sector)
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+int udf_idx_add(udf_node_t **udfn, udf_instance_t *instance, fs_index_t index)
+{
+	fibril_mutex_lock(&udf_idx_lock);
+	
+	udf_node_t *udf_node = malloc(sizeof(udf_node_t));
+	if (udf_node == NULL) {
+		fibril_mutex_unlock(&udf_idx_lock);
+		return ENOMEM;
+	}
+	
+	fs_node_t *fs_node = malloc(sizeof(fs_node_t));
+	if (fs_node == NULL) {
+		free(udf_node);
+		fibril_mutex_unlock(&udf_idx_lock);
+		return ENOMEM;
+	}
+	
+	fs_node_initialize(fs_node);
+	
+	udf_node->index = index;
+	udf_node->instance = instance;
+	udf_node->ref_cnt = 1;
+	udf_node->link_cnt = 0;
+	udf_node->fs_node = fs_node;
+	udf_node->data = NULL;
+	udf_node->allocators = NULL;
+	
+	fibril_mutex_initialize(&udf_node->lock);
+	link_initialize(&udf_node->link);
+	fs_node->data = udf_node;
+	
+	unsigned long key[] = {
+		[UDF_IDX_SERVICE_ID_KEY] = instance->service_id,
+		[UDF_IDX_KEY] = index
+	};
+	
+	hash_table_insert(&udf_idx, key, &udf_node->link);
+	instance->open_nodes_count++;
+	
+	*udfn = udf_node;
+	
+	fibril_mutex_unlock(&udf_idx_lock);
+	return EOK;
+}
+
+/** Delete node from hash table
+ *
+ * @param node UDF node
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+int udf_idx_del(udf_node_t *node)
+{
+	assert(node->ref_cnt == 0);
+	
+	fibril_mutex_lock(&udf_idx_lock);
+	
+	unsigned long key[] = {
+		[UDF_IDX_SERVICE_ID_KEY] = node->instance->service_id,
+		[UDF_IDX_KEY] = node->index
+	};
+	
+	hash_table_remove(&udf_idx, key, UDF_IDX_KEYS);
+	
+	assert(node->instance->open_nodes_count > 0);
+	node->instance->open_nodes_count--;
+	
+	free(node->fs_node);
+	free(node);
+	
+	fibril_mutex_unlock(&udf_idx_lock);
+	return EOK;
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/fs/udf/udf_idx.h
===================================================================
--- uspace/srv/fs/udf/udf_idx.h	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
+++ uspace/srv/fs/udf/udf_idx.h	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2012 Julia Medvedeva
+ * 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 UDF_IDX_H_
+#define UDF_IDX_H_
+
+#include "udf.h"
+
+extern int udf_idx_init(void);
+extern int udf_idx_fini(void);
+extern int udf_idx_get(udf_node_t **, udf_instance_t *, fs_index_t);
+extern int udf_idx_add(udf_node_t **, udf_instance_t *, fs_index_t);
+extern int udf_idx_del(udf_node_t *);
+
+#endif /* UDF_IDX_H_ */
+
+/**
+ * @}
+ */
Index: uspace/srv/fs/udf/udf_ops.c
===================================================================
--- uspace/srv/fs/udf/udf_ops.c	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
+++ uspace/srv/fs/udf/udf_ops.c	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -0,0 +1,530 @@
+/*
+ * Copyright (c) 2008 Jakub Jermar
+ * Copyright (c) 2012 Julia Medvedeva
+ * 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 udf_ops.c
+ * @brief Implementation of VFS operations for the UDF file system
+ *        server.
+ */
+
+#include <libfs.h>
+#include <block.h>
+#include <ipc/services.h>
+#include <ipc/loc.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>
+#include <malloc.h>
+#include <inttypes.h>
+#include <io/log.h>
+#include "../../vfs/vfs.h"
+#include "udf.h"
+#include "udf_cksum.h"
+#include "udf_volume.h"
+#include "udf_idx.h"
+#include "udf_file.h"
+#include "udf_osta.h"
+
+/** Mutex protecting the list of cached free nodes. */
+static FIBRIL_MUTEX_INITIALIZE(ffn_mutex);
+
+/** List of cached free nodes. */
+static LIST_INITIALIZE(ffn_list);
+
+static int udf_node_get(fs_node_t **rfn, service_id_t service_id,
+    fs_index_t index)
+{
+	udf_instance_t *instance;
+	int rc = fs_instance_get(service_id, (void **) &instance);
+	if (rc != EOK)
+		return rc;
+	
+	udf_node_t *node;
+	rc = udf_idx_get(&node, instance, index);
+	if (rc != EOK) {
+		rc = udf_idx_add(&node, instance, index);
+		if (rc != EOK)
+			return rc;
+		
+		rc = udf_node_get_core(node);
+		if (rc != EOK) {
+			udf_idx_del(node);
+			return rc;
+		}
+	}
+	
+	*rfn = FS_NODE(node);
+	return EOK;
+}
+
+static int udf_root_get(fs_node_t **rfn, service_id_t service_id)
+{
+	udf_instance_t *instance;
+	int rc = fs_instance_get(service_id, (void **) &instance);
+	if (rc != EOK)
+		return rc;
+	
+	return udf_node_get(rfn, service_id,
+	    instance->volumes[DEFAULT_VOL].root_dir);
+}
+
+static service_id_t udf_service_get(fs_node_t *node)
+{
+	udf_node_t *udfn = UDF_NODE(node);
+	if (udfn)
+		return udfn->instance->service_id;
+	
+	return 0;
+}
+
+static int udf_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
+{
+	char *name = malloc(MAX_FILE_NAME_LEN + 1);
+	if (name == NULL)
+		return ENOMEM;
+	
+	block_t *block = NULL;
+	udf_file_identifier_descriptor_t *fid = NULL;
+	size_t pos = 0;
+	
+	while (udf_get_fid(&fid, &block, UDF_NODE(pfn), pos) == EOK) {
+		udf_long_ad_t long_ad = fid->icb;
+		
+		udf_to_unix_name(name, MAX_FILE_NAME_LEN,
+		    (char *) fid->implementation_use + FLE16(fid->lenght_iu),
+		    fid->lenght_file_id, &UDF_NODE(pfn)->instance->charset);
+		
+		if (stricmp(name, component) == 0) {
+			int rc = udf_node_get(rfn, udf_service_get(pfn),
+			    udf_long_ad_to_pos(UDF_NODE(pfn)->instance, &long_ad));
+			
+			if (block != NULL)
+				block_put(block);
+			
+			free(name);
+			return rc;
+		}
+		
+		if (block != NULL) {
+			int rc = block_put(block);
+			if (rc != EOK)
+				return rc;
+		}
+		
+		pos++;
+	}
+	
+	free(name);
+	return ENOENT;
+}
+
+static int udf_node_open(fs_node_t *fn)
+{
+	return EOK;
+}
+
+static int udf_node_put(fs_node_t *fn)
+{
+	udf_node_t *node = UDF_NODE(fn);
+	if (!node)
+		return EINVAL;
+	
+	fibril_mutex_lock(&node->lock);
+	node->ref_cnt--;
+	fibril_mutex_unlock(&node->lock);
+	
+	/* Delete node from hash table and memory */
+	if (!node->ref_cnt)
+		udf_idx_del(node);
+	
+	return EOK;
+}
+
+static int udf_create_node(fs_node_t **rfn, service_id_t service_id, int flags)
+{
+	return ENOTSUP;
+}
+
+static int udf_destroy_node(fs_node_t *fn)
+{
+	return ENOTSUP;
+}
+
+static int udf_link(fs_node_t *pfn, fs_node_t *cfn, const char *name)
+{
+	return ENOTSUP;
+}
+
+static int udf_unlink(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
+{
+	return ENOTSUP;
+}
+
+static int udf_has_children(bool *has_children, fs_node_t *fn)
+{
+	*has_children = true;
+	return EOK;
+}
+
+static fs_index_t udf_index_get(fs_node_t *fn)
+{
+	udf_node_t *node = UDF_NODE(fn);
+	if (node)
+		return node->index;
+	
+	return 0;
+}
+
+static aoff64_t udf_size_get(fs_node_t *fn)
+{
+	udf_node_t *node = UDF_NODE(fn);
+	if (node)
+		return node->data_size;
+	
+	return 0;
+}
+
+static unsigned int udf_lnkcnt_get(fs_node_t *fn)
+{
+	udf_node_t *node = UDF_NODE(fn);
+	if (node)
+		return node->link_cnt;
+	
+	return 0;
+}
+
+static bool udf_is_directory(fs_node_t *fn)
+{
+	udf_node_t *node = UDF_NODE(fn);
+	if (node)
+		return node->type == NODE_DIR;
+	
+	return false;
+}
+
+static bool udf_is_file(fs_node_t *fn)
+{
+	udf_node_t *node = UDF_NODE(fn);
+	if (node)
+		return node->type == NODE_FILE;
+	
+	return false;
+}
+
+libfs_ops_t udf_libfs_ops = {
+	.root_get = udf_root_get,
+	.match = udf_match,
+	.node_get = udf_node_get,
+	.node_open = udf_node_open,
+	.node_put = udf_node_put,
+	.create = udf_create_node,
+	.destroy = udf_destroy_node,
+	.link = udf_link,
+	.unlink = udf_unlink,
+	.has_children = udf_has_children,
+	.index_get = udf_index_get,
+	.size_get = udf_size_get,
+	.lnkcnt_get = udf_lnkcnt_get,
+	.is_directory = udf_is_directory,
+	.is_file = udf_is_file,
+	.service_get = udf_service_get
+};
+
+static int udf_mounted(service_id_t service_id, const char *opts,
+    fs_index_t *index, aoff64_t *size, unsigned *linkcnt)
+{
+	enum cache_mode cmode;
+	
+	/* Check for option enabling write through. */
+	if (str_cmp(opts, "wtcache") == 0)
+		cmode = CACHE_MODE_WT;
+	else
+		cmode = CACHE_MODE_WB;
+	
+	udf_instance_t *instance = malloc(sizeof(udf_instance_t));
+	if (!instance)
+		return ENOMEM;
+	
+	instance->sector_size = 0;
+	
+	/* Check for block size. Will be enhanced later */
+	if (str_cmp(opts, "bs=512") == 0)
+		instance->sector_size = 512;
+	else if (str_cmp(opts, "bs=1024") == 0)
+		instance->sector_size = 1024;
+	else if (str_cmp(opts, "bs=2048") == 0)
+		instance->sector_size = 2048;
+	
+	/* initialize block cache */
+	int rc = block_init(EXCHANGE_SERIALIZE, service_id, MAX_SIZE);
+	if (rc != EOK)
+		return rc;
+	
+	rc = fs_instance_create(service_id, instance);
+	if (rc != EOK) {
+		free(instance);
+		block_fini(service_id);
+		return rc;
+	}
+	
+	instance->service_id = service_id;
+	instance->open_nodes_count = 0;
+	
+	/* Check Volume Recognition Sequence */
+	rc = udf_volume_recongnition(service_id);
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_NOTE, "VRS failed");
+		fs_instance_destroy(service_id);
+		free(instance);
+		block_fini(service_id);
+		return rc;
+	}
+	
+	/* Search for Anchor Volume Descriptor */
+	udf_anchor_volume_descriptor_t avd;
+	rc = udf_get_anchor_volume_descriptor(service_id, &avd);
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_NOTE, "Anchor read failed");
+		fs_instance_destroy(service_id);
+		free(instance);
+		block_fini(service_id);
+		return rc;
+	}
+	
+	log_msg(LOG_DEFAULT, LVL_DEBUG,
+	    "Volume: Anchor volume descriptor found. Sector size=%" PRIu32,
+	    instance->sector_size);
+	log_msg(LOG_DEFAULT, LVL_DEBUG,
+	    "Anchor: main sequence [length=%" PRIu32 " (bytes), start=%"
+	    PRIu32 " (sector)]", avd.main_extent.length,
+	    avd.main_extent.location);
+	log_msg(LOG_DEFAULT, LVL_DEBUG,
+	    "Anchor: reserve sequence [length=%" PRIu32 " (bytes), start=%"
+	    PRIu32 " (sector)]", avd.reserve_extent.length,
+	    avd.reserve_extent.location);
+	
+	/* Initialize the block cache */
+	rc = block_cache_init(service_id, instance->sector_size, 0, cmode);
+	if (rc != EOK) {
+		fs_instance_destroy(service_id);
+		free(instance);
+		block_fini(service_id);
+		return rc;
+	}
+	
+	/* Read Volume Descriptor Sequence */
+	rc = udf_read_volume_descriptor_sequence(service_id, avd.main_extent);
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_NOTE, "Volume Descriptor Sequence read failed");
+		fs_instance_destroy(service_id);
+		free(instance);
+		block_cache_fini(service_id);
+		block_fini(service_id);
+		return rc;
+	}
+	
+	fs_node_t *rfn;
+	rc = udf_node_get(&rfn, service_id, instance->volumes[DEFAULT_VOL].root_dir);
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_NOTE, "Can't create root node");
+		fs_instance_destroy(service_id);
+		free(instance);
+		block_cache_fini(service_id);
+		block_fini(service_id);
+		return rc;
+	}
+	
+	udf_node_t *node = UDF_NODE(rfn);
+	*index = instance->volumes[DEFAULT_VOL].root_dir;
+	*size = node->data_size;
+	*linkcnt = node->link_cnt;
+	
+	return EOK;
+}
+
+static int udf_unmounted(service_id_t service_id)
+{
+	fs_node_t *fn;
+	int rc = udf_root_get(&fn, service_id);
+	if (rc != EOK)
+		return rc;
+	
+	udf_node_t *nodep = UDF_NODE(fn);
+	udf_instance_t *instance = nodep->instance;
+	
+	/*
+	 * We expect exactly two references on the root node.
+	 * One for the udf_root_get() above and one created in
+	 * udf_mounted().
+	 */
+	if (nodep->ref_cnt != 2) {
+		udf_node_put(fn);
+		return EBUSY;
+	}
+	
+	/*
+	 * Put the root node twice.
+	 */
+	udf_node_put(fn);
+	udf_node_put(fn);
+	
+	fs_instance_destroy(service_id);
+	free(instance);
+	block_cache_fini(service_id);
+	block_fini(service_id);
+	
+	return EOK;
+}
+
+static int udf_read(service_id_t service_id, fs_index_t index, aoff64_t pos,
+    size_t *rbytes)
+{
+	udf_instance_t *instance;
+	int rc = fs_instance_get(service_id, (void **) &instance);
+	if (rc != EOK)
+		return rc;
+	
+	fs_node_t *rfn;
+	rc = udf_node_get(&rfn, service_id, index);
+	if (rc != EOK)
+		return rc;
+	
+	udf_node_t *node = UDF_NODE(rfn);
+	
+	ipc_callid_t callid;
+	size_t len = 0;
+	if (!async_data_read_receive(&callid, &len)) {
+		async_answer_0(callid, EINVAL);
+		udf_node_put(rfn);
+		return EINVAL;
+	}
+	
+	if (node->type == NODE_FILE) {
+		if (pos >= node->data_size) {
+			*rbytes = 0;
+			async_data_read_finalize(callid, NULL, 0);
+			udf_node_put(rfn);
+			return EOK;
+		}
+		
+		size_t read_len = 0;
+		if (node->data == NULL)
+			rc = udf_read_file(&read_len, callid, node, pos, len);
+		else {
+			/* File in allocation descriptors area */
+			read_len = (len < node->data_size) ? len : node->data_size;
+			async_data_read_finalize(callid, node->data + pos, read_len);
+			rc = EOK;
+		}
+		
+		*rbytes = read_len;
+		(void) udf_node_put(rfn);
+		return rc;
+	} else {
+		block_t *block = NULL;
+		udf_file_identifier_descriptor_t *fid = NULL;
+		if (udf_get_fid(&fid, &block, node, pos) == EOK) {
+			char *name = malloc(MAX_FILE_NAME_LEN + 1);
+			
+			// FIXME: Check for NULL return value
+			
+			udf_to_unix_name(name, MAX_FILE_NAME_LEN,
+			    (char *) fid->implementation_use + FLE16(fid->lenght_iu),
+			    fid->lenght_file_id, &node->instance->charset);
+			
+			async_data_read_finalize(callid, name, str_size(name) + 1);
+			*rbytes = 1;
+			free(name);
+			udf_node_put(rfn);
+			
+			if (block != NULL)
+				return block_put(block);
+			
+			return EOK;
+		} else {
+			*rbytes = 0;
+			udf_node_put(rfn);
+			async_answer_0(callid, ENOENT);
+			return ENOENT;
+		}
+	}
+}
+
+static int udf_close(service_id_t service_id, fs_index_t index)
+{
+	return EOK;
+}
+
+static int udf_sync(service_id_t service_id, fs_index_t index)
+{
+	return ENOTSUP;
+}
+
+static int udf_write(service_id_t service_id, fs_index_t index, aoff64_t pos,
+    size_t *wbytes, aoff64_t *nsize)
+{
+	return ENOTSUP;
+}
+
+static int udf_truncate(service_id_t service_id, fs_index_t index,
+    aoff64_t size)
+{
+	return ENOTSUP;
+}
+
+static int udf_destroy(service_id_t service_id, fs_index_t index)
+{
+	return ENOTSUP;
+}
+
+vfs_out_ops_t udf_ops = {
+	.mounted = udf_mounted,
+	.unmounted = udf_unmounted,
+	.read = udf_read,
+	.write = udf_write,
+	.truncate = udf_truncate,
+	.close = udf_close,
+	.destroy = udf_destroy,
+	.sync = udf_sync
+};
+
+/**
+ * @}
+ */
Index: uspace/srv/fs/udf/udf_osta.c
===================================================================
--- uspace/srv/fs/udf/udf_osta.c	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
+++ uspace/srv/fs/udf/udf_osta.c	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -0,0 +1,317 @@
+/*
+ * Copyright (c) 2012 Julia Medvedeva
+ * 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.
+ */
+
+/*
+ * OSTA compliant Unicode compression, uncompression routines,
+ * file name translation routine for OS/2, Windows 95, Windows NT,
+ * Macintosh and UNIX.
+ * Copyright 1995 Micro Design International, Inc.
+ * Written by Jason M. Rinn.
+ * Micro Design International gives permission for the free use of the
+ * following source code.
+ */
+
+/** @addtogroup fs
+ * @{
+ */
+/**
+ * @file udf_osta.c
+ * @brief OSTA compliant functions.
+ */
+
+#include <malloc.h>
+#include <str.h>
+#include <macros.h>
+#include <errno.h>
+#include "udf_osta.h"
+#include "udf_cksum.h"
+
+/** Calculate length of UTF-16 string
+ *
+ * FIXME: This is wrong! UTF-16 is not a fixed-width encoding,
+ *        it is a variable-width encoding (mind the surrogate
+ *        pairs).
+ *
+ */
+static size_t utf16_length(uint16_t *string) {
+	size_t len = 0;
+	
+	while (*string++ != 0)
+		len++;
+	
+	return len;
+}
+
+/** Illegal UNIX characters are NULL and slash.
+ *
+ */
+static bool legal_check(uint16_t ch)
+{
+	if ((ch == 0x0000) || (ch == 0x002F))
+		return false;
+	
+	return true;
+}
+
+/** Convert OSTA CS0 compressed Unicode name to Unicode.
+ *
+ * The Unicode output will be in the byte order that the local compiler
+ * uses for 16-bit values.
+ *
+ * NOTE: This routine only performs error checking on the comp_id.
+ * It is up to the user to ensure that the Unicode buffer is large
+ * enough, and that the compressed Unicode name is correct.
+ *
+ * @param[in]  number_of_bytes Number of bytes read from media
+ * @param[in]  udf_compressed  Bytes read from media
+ * @param[out] unicode         Uncompressed unicode characters
+ * @param[in]  unicode_max_len Size of output array
+ *
+ * @return Number of Unicode characters which were uncompressed.
+ *
+ */
+static size_t udf_uncompress_unicode(size_t number_of_bytes,
+    uint8_t *udf_compressed, uint16_t *unicode, size_t unicode_max_len)
+{
+	/* Use udf_compressed to store current byte being read. */
+	uint8_t comp_id = udf_compressed[0];
+	
+	/* First check for valid compID. */
+	if ((comp_id != 8) && (comp_id != 16))
+		return 0;
+	
+	size_t unicode_idx = 0;
+	size_t byte_idx = 1;
+	
+	/* Loop through all the bytes. */
+	while ((byte_idx < number_of_bytes) && (unicode_idx < unicode_max_len)) {
+		if (comp_id == 16) {
+			/*
+			 * Move the first byte to the high bits of the
+			 * Unicode char.
+			 */
+			unicode[unicode_idx] = udf_compressed[byte_idx++] << 8;
+		} else
+			unicode[unicode_idx] = 0;
+		
+		if (byte_idx < number_of_bytes) {
+			/* Then the next byte to the low bits. */
+			unicode[unicode_idx] |= udf_compressed[byte_idx++];
+		}
+		
+		unicode_idx++;
+	}
+	
+	return unicode_idx;
+}
+
+/** Translate a long file name
+ *
+ * Translate a long file name to one using a MAXLEN and an illegal char set
+ * in accord with the OSTA requirements. Assumes the name has already been
+ * translated to Unicode.
+ *
+ * @param[out] new_name Translated name. Must be of length MAXLEN
+ * @param[in]  udf_name Name from UDF volume
+ * @param[in]  udf_len  Length of UDF Name
+ *
+ * @return Number of Unicode characters in translated name.
+ *
+ */
+size_t udf_translate_name(uint16_t *new_name, uint16_t *udf_name,
+    size_t udf_len)
+{
+	bool needs_crc = false;
+	bool has_ext = false;
+	size_t ext_idx = 0;
+	size_t new_idx = 0;
+	size_t new_ext_idx = 0;
+	
+	for (size_t idx = 0; idx < udf_len; idx++) {
+		uint16_t current = udf_name[idx];
+		
+		if ((!legal_check(current)) || (!ascii_check(current))) {
+			needs_crc = true;
+			
+			/*
+			 * Replace Illegal and non-displayable chars with
+			 * underscore.
+			 */
+			current = ILLEGAL_CHAR_MARK;
+			
+			/*
+			 * Skip any other illegal or non-displayable
+			 * characters.
+			 */
+			while ((idx + 1 < udf_len) &&
+			    (!legal_check(udf_name[idx + 1]) ||
+			    (!ascii_check(udf_name[idx + 1]))))
+				idx++;
+		}
+		
+		/* Record position of extension, if one is found. */
+		if ((current == PERIOD) && ((udf_len - idx - 1) <= EXT_SIZE)) {
+			if (udf_len == idx + 1) {
+				/* A trailing period is NOT an extension. */
+				has_ext = false;
+			} else {
+				has_ext = true;
+				ext_idx = idx;
+				new_ext_idx = new_idx;
+			}
+		}
+		
+		if (new_idx < MAXLEN)
+			new_name[new_idx++] = current;
+		else
+			needs_crc = true;
+	}
+	
+	if (needs_crc) {
+		uint16_t ext[EXT_SIZE];
+		size_t local_ext_idx = 0;
+		
+		if (has_ext) {
+			size_t max_filename_len;
+			
+			/* Translate extension, and store it in ext. */
+			for (size_t idx = 0; (idx < EXT_SIZE) &&
+			    (ext_idx + idx + 1 < udf_len); idx++) {
+				uint16_t current = udf_name[ext_idx + idx + 1];
+				
+				if ((!legal_check(current)) || (!ascii_check(current))) {
+					needs_crc = true;
+					
+					/*
+					 * Replace Illegal and non-displayable
+					 * chars with underscore.
+					 */
+					current = ILLEGAL_CHAR_MARK;
+					
+					/*
+					 * Skip any other illegal or
+					 * non-displayable characters.
+					 */
+					while ((idx + 1 < EXT_SIZE) &&
+					    ((!legal_check(udf_name[ext_idx + idx + 2])) ||
+					    (!ascii_check(udf_name[ext_idx + idx + 2]))))
+						idx++;
+				}
+				
+				ext[local_ext_idx++] = current;
+			}
+			
+			/*
+			 * Truncate filename to leave room for extension and
+			 * CRC.
+			 */
+			max_filename_len = ((MAXLEN - 5) - local_ext_idx - 1);
+			if (new_idx > max_filename_len)
+				new_idx = max_filename_len;
+			else
+				new_idx = new_ext_idx;
+		} else if (new_idx > MAXLEN - 5) {
+			/* If no extension, make sure to leave room for CRC. */
+			new_idx = MAXLEN - 5;
+		}
+		
+		/* Add mark for CRC. */
+		new_name[new_idx++] = CRC_MARK;
+		
+		/* Calculate CRC from original filename. */
+		uint16_t value_crc = udf_unicode_cksum(udf_name, udf_len);
+		
+		/* Convert 16-bits of CRC to hex characters. */
+		const char hex_char[] = "0123456789ABCDEF";
+		
+		new_name[new_idx++] = hex_char[(value_crc & 0xf000) >> 12];
+		new_name[new_idx++] = hex_char[(value_crc & 0x0f00) >> 8];
+		new_name[new_idx++] = hex_char[(value_crc & 0x00f0) >> 4];
+		new_name[new_idx++] = hex_char[(value_crc & 0x000f)];
+		
+		/* Place a translated extension at end, if found. */
+		if (has_ext) {
+			new_name[new_idx++] = PERIOD;
+			
+			for (size_t idx = 0; idx < local_ext_idx; idx++)
+				new_name[new_idx++] = ext[idx];
+		}
+	}
+	
+	return new_idx;
+}
+
+/** Decode from dchar to utf8
+ *
+ * @param result     Returned value - utf8 string
+ * @param result_len Length of output string
+ * @param id         Input string
+ * @param len        Length of input string
+ * @param chsp       Decode method
+ *
+ */
+void udf_to_unix_name(char *result, size_t result_len, char *id, size_t len,
+    udf_charspec_t *chsp)
+{
+	const char *osta_id = "OSTA Compressed Unicode";
+	size_t ucode_chars, nice_uchars;
+	
+	uint16_t *raw_name = malloc(MAX_BUF * sizeof(uint16_t));
+	uint16_t *unix_name = malloc(MAX_BUF * sizeof(uint16_t));
+	
+	// FIXME: Check for malloc returning NULL
+	
+	bool is_osta_typ0 = (chsp->type == 0) &&
+	    (str_cmp((char *) chsp->info, osta_id) == 0);
+	
+	if (is_osta_typ0) {
+		*raw_name = 0;
+		*unix_name = 0;
+		
+		ucode_chars =
+		    udf_uncompress_unicode(len, (uint8_t *) id, raw_name, MAX_BUF);
+		ucode_chars = min(ucode_chars, utf16_length(raw_name));
+		nice_uchars =
+		    udf_translate_name(unix_name, raw_name, ucode_chars);
+		
+		/* Output UTF-8 */
+		unix_name[nice_uchars] = 0;
+		utf16_to_str(result, result_len, unix_name);
+	} else {
+		/* Assume 8 bit char length byte Latin-1 */
+		str_ncpy(result, result_len, (char *) (id + 1),
+		    str_size((char *) (id + 1)));
+	}
+	
+	free(raw_name);
+	free(unix_name);
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/fs/udf/udf_osta.h
===================================================================
--- uspace/srv/fs/udf/udf_osta.h	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
+++ uspace/srv/fs/udf/udf_osta.h	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2012 Julia Medvedeva
+ * 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.
+ */
+
+/*
+ * OSTA compliant Unicode compression, uncompression routines,
+ * file name translation routine for OS/2, Windows 95, Windows NT,
+ * Macintosh and UNIX.
+ * Copyright 1995 Micro Design International, Inc.
+ * Written by Jason M. Rinn.
+ * Micro Design International gives permission for the free use of the
+ * following source code.
+ */
+
+#ifndef UDF_OSTA_H_
+#define UDF_OSTA_H_
+
+#include <sys/types.h>
+#include <bool.h>
+#include "udf_types.h"
+
+#define MAXLEN    255
+#define MAX_BUF   1024
+#define EXT_SIZE  5
+
+#define ILLEGAL_CHAR_MARK  0x005F
+#define CRC_MARK           0x0023
+#define PERIOD             0x002E
+
+extern size_t udf_translate_name(uint16_t *, uint16_t *, size_t);
+extern void udf_to_unix_name(char *, size_t, char *, size_t, udf_charspec_t *);
+
+#endif /* UDF_OSTA_H_ */
Index: uspace/srv/fs/udf/udf_types.h
===================================================================
--- uspace/srv/fs/udf/udf_types.h	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
+++ uspace/srv/fs/udf/udf_types.h	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2012 Julia Medvedeva
+ * 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 udf_types.h
+ * @brief UDF common types
+ */
+
+#ifndef UDF_UDF_TYPES_H_
+#define UDF_UDF_TYPES_H_
+
+#include <sys/types.h>
+#include <bool.h>
+#include <byteorder.h>
+
+#define GET_LE16(x)  x = uint16_t_le2host(x)
+#define GET_LE32(x)  x = uint32_t_le2host(x)
+
+#define FLE16(x)  uint16_t_le2host(x)
+#define FLE32(x)  uint32_t_le2host(x)
+#define FLE64(x)  uint64_t_le2host(x)
+
+#define ALL_UP(n, b)  ((n) / (b) + ((n) % (b) != 0))
+
+#define EXT_LENGTH(x)  (x & 0x3FFFFFFF)
+
+typedef uint8_t udf_dstring;
+
+/* Timestamp descriptor (ECMA 167 1/7.3) */
+typedef struct udf_timestamp {
+	uint16_t type_and_tz;
+	uint16_t year;
+	uint8_t month;
+	uint8_t day;
+	uint8_t hour;
+	uint8_t min;
+	uint8_t sec;
+	uint8_t centisec;
+	uint8_t h_of_mcsec;
+	uint8_t mcsec;
+} __attribute__((packed)) udf_timestamp_t;
+
+/* Universal descriptor tag (ECMA 167 3/7.2) */
+typedef struct udf_descriptor_tag {
+	uint16_t id;
+	uint16_t version;
+	uint8_t checksum;
+	uint8_t reserved;
+	uint16_t serial;
+	uint16_t descriptor_crc;
+	uint16_t descriptor_crc_length;
+	uint32_t location;
+} __attribute__((packed)) udf_descriptor_tag_t;
+
+/* Entity descriptor (ECMA 167 1/7.4) */
+typedef struct udf_regid {
+	uint8_t flags;
+	uint8_t id[23];
+	uint8_t id_suffix[8];
+} __attribute__((packed)) udf_regid_t;
+
+/* Character set specification (ECMA 167 1/7.2.1) */
+typedef struct udf_charspec {
+	uint8_t type;
+	uint8_t info[63];
+} __attribute__((packed)) udf_charspec_t;
+
+/* Recorded address (ECMA 167 4/7.1) */
+typedef struct udf_lb_addr {
+	uint32_t lblock_num;     /* Relative to start of the partition (from 0) */
+	uint16_t partition_num;  /* Relative to logical volume or not? */
+} __attribute__((packed)) udf_lb_addr_t;
+
+/* Long Allocation Descriptor (ECMA 167 4/14.14.2) */
+typedef struct udf_long_ad {
+	uint32_t length;
+	udf_lb_addr_t location;
+	uint8_t implementation_use[6];
+} __attribute__((packed)) udf_long_ad_t;
+
+/* Short Allocation Descriptor (ECMA 167 4/14.14.1) */
+typedef struct udf_short_ad {
+	uint32_t length;
+	uint32_t position;
+} __attribute__((packed)) udf_short_ad_t;
+
+/* Extended Allocation Descriptor (ECMA 167 4/14.14.3) */
+typedef struct udf_ext_ad {
+	uint32_t extent_length;
+	uint32_t recorded_length;
+	uint32_t info_length;
+	udf_lb_addr_t extent_location;
+	uint8_t implementation_use[2];
+} __attribute__((packed)) udf_ext_ad_t;
+
+/* Extent descriptor (ECMA 167 3/7.1) */
+typedef struct udf_extent {
+	uint32_t length;    /* Bytes */
+	uint32_t location;  /* Sectors */
+} __attribute__((packed)) udf_extent_t;
+
+/* Terminating Descriptor (ECMA 167 3/10.9) */
+typedef struct udf_terminating_descriptor {
+	udf_descriptor_tag_t tag;
+	uint8_t reserved[496];
+} __attribute__((packed)) udf_terminating_descriptor_t;
+
+/* Unallocated Space Descriptor (ECMA 167 3/10.8) */
+typedef struct udf_unallocated_space_descriptor {
+	udf_descriptor_tag_t tag;
+	uint32_t sequence_number;
+	uint32_t allocation_descriptors_num;
+	udf_extent_t allocation_descriptors[0];
+} __attribute__((packed)) udf_unallocated_space_descriptor_t;
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/srv/fs/udf/udf_volume.c
===================================================================
--- uspace/srv/fs/udf/udf_volume.c	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
+++ uspace/srv/fs/udf/udf_volume.c	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -0,0 +1,850 @@
+/*
+ * Copyright (c) 2012 Julia Medvedeva
+ * 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 udf_volume.c
+ * @brief Implementation of volume recognition operations.
+ */
+
+#include <byteorder.h>
+#include <block.h>
+#include <libfs.h>
+#include <errno.h>
+#include <str.h>
+#include <malloc.h>
+#include <mem.h>
+#include <inttypes.h>
+#include <io/log.h>
+#include "udf.h"
+#include "udf_volume.h"
+#include "udf_osta.h"
+#include "udf_cksum.h"
+#include "udf_file.h"
+
+/** Convert long_ad to absolute sector position
+ *
+ * Convert address sector concerning origin of partition to position
+ * sector concerning origin of start of disk.
+ *
+ * @param instance UDF instance
+ * @param long_ad  UDF long address
+ *
+ * @return Position of sector concerning origin of start of disk.
+ *
+ */
+fs_index_t udf_long_ad_to_pos(udf_instance_t *instance, udf_long_ad_t *long_ad)
+{
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "Long_Ad to Pos: "
+	    "partition_num=%" PRIu16 ", partition_block=%" PRIu32,
+	    FLE16(long_ad->location.partition_num),
+	    FLE32(long_ad->location.lblock_num));
+	
+	return instance->partitions[
+	    FLE16(long_ad->location.partition_num)].start +
+	    FLE32(long_ad->location.lblock_num);
+}
+
+/** Check type and version of VRS
+ *
+ * Not exactly clear which values could have type and version.
+ *
+ * @param service_id
+ * @param addr       Position sector with Volume Descriptor
+ * @param vd         Returned value - Volume Descriptor.
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+static int udf_volume_recongnition_structure_test(service_id_t service_id,
+    aoff64_t addr, udf_vrs_descriptor_t *vd)
+{
+	return block_read_bytes_direct(service_id, addr,
+	    sizeof(udf_vrs_descriptor_t), vd);
+}
+
+/** Read Volume Recognition Sequence
+ *
+ * It is a first udf data which we read.
+ * It stars from fixed address VRS_ADDR = 32768 (bytes)
+ *
+ * @param service_id
+ *
+ * @return    EOK on success or a negative error code.
+ */
+int udf_volume_recongnition(service_id_t service_id) 
+{
+	aoff64_t addr = VRS_ADDR;
+	bool nsr_found = false;
+
+	udf_vrs_descriptor_t *vd = malloc(sizeof(udf_vrs_descriptor_t));
+	if (!vd)
+		return ENOMEM;
+	
+	int rc = udf_volume_recongnition_structure_test(service_id, addr, vd);
+	if (rc != EOK) {
+		free(vd);
+		return rc;
+	}
+	
+	for (size_t i = 0; i < VRS_DEPTH; i++) {
+		addr += sizeof(udf_vrs_descriptor_t);
+		
+		rc = udf_volume_recongnition_structure_test(service_id, addr, vd);
+		if (rc != EOK) {
+			free(vd);
+			return rc;
+		}
+		
+		/*
+		 * UDF standard identifier. According to ECMA 167 2/9.1.2
+		 */
+		if ((str_lcmp(VRS_NSR2, (char *) vd->identifier, VRS_ID_LEN) == 0) ||
+		    (str_lcmp(VRS_NSR3, (char *) vd->identifier, VRS_ID_LEN) == 0)) {
+			nsr_found = true;
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "VRS: NSR found");
+			continue;
+		}
+		
+		if (str_lcmp(VRS_END, (char *) vd->identifier, VRS_ID_LEN) == 0) {
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "VRS: end found");
+			break;
+		}
+	}
+	
+	free(vd);
+	
+	if (nsr_found)
+		return EOK;
+	else
+		return EINVAL;
+}
+
+/** Convert descriptor tag fields from little-endian to current byte order
+ *
+ */
+static void udf_prepare_tag(udf_descriptor_tag_t *tag)
+{
+	GET_LE16(tag->id);
+	GET_LE16(tag->version);
+	GET_LE16(tag->serial);
+	GET_LE16(tag->descriptor_crc);
+	GET_LE16(tag->descriptor_crc_length);
+	GET_LE32(tag->location);
+}
+
+/** Read AVD by using one of default sector size from array
+ *
+ * @param service_id
+ * @param avd         Returned value - Anchor Volume Descriptor
+ * @param sector_size Expected sector size
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+static int udf_get_anchor_volume_descriptor_by_ssize(service_id_t service_id,
+    udf_anchor_volume_descriptor_t *avd, uint32_t sector_size)
+{
+	int rc = block_read_bytes_direct(service_id,
+	    UDF_AVDP_SECTOR * sector_size,
+	    sizeof(udf_anchor_volume_descriptor_t), avd);
+	if (rc != EOK)
+		return rc;
+	
+	if (avd->tag.checksum != udf_tag_checksum((uint8_t *) &avd->tag))
+		return EINVAL;
+	
+	// TODO: Should be tested in big-endian mode
+	udf_prepare_tag(&avd->tag);
+	
+	if (avd->tag.id != UDF_TAG_AVDP)
+		return EINVAL;
+	
+	GET_LE32(avd->main_extent.length);
+	GET_LE32(avd->main_extent.location);
+	GET_LE32(avd->reserve_extent.length);
+	GET_LE32(avd->reserve_extent.location);
+	
+	return EOK;
+}
+
+/** Identification of the sector size
+ *
+ * We try to read Anchor Volume Descriptor by using one item from
+ * sequence of default values. If we could read avd, we found sector size.
+ *
+ * @param service_id
+ * @param avd        Returned value - Anchor Volume Descriptor
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+int udf_get_anchor_volume_descriptor(service_id_t service_id,
+    udf_anchor_volume_descriptor_t *avd)
+{
+	uint32_t default_sector_size[] = {512, 1024, 2048, 4096, 8192, 0};
+	
+	udf_instance_t *instance;
+	int rc = fs_instance_get(service_id, (void **) &instance);
+	if (rc != EOK)
+		return rc;
+	
+	if (instance->sector_size) {
+		return udf_get_anchor_volume_descriptor_by_ssize(service_id, avd,
+		    instance->sector_size);
+	} else {
+		size_t i = 0;
+		while (default_sector_size[i] != 0) {
+			rc = udf_get_anchor_volume_descriptor_by_ssize(service_id, avd,
+			    default_sector_size[i]);
+			if (rc == EOK) {
+				instance->sector_size = default_sector_size[i];
+				return EOK;
+			}
+			
+			i++;
+		}
+	}
+	
+	return EINVAL;
+}
+
+/** Check on prevailing primary volume descriptor
+ *
+ * Some discs couldn't be rewritten and new information is identified
+ * by descriptors with same data as one of already created descriptors.
+ * We should find prevailing descriptor (descriptor with the highest number)
+ * and delete old descriptor.
+ *
+ * @param pvd  Array of primary volumes descriptors
+ * @param cnt  Count of items in array
+ * @param desc Descriptor which could prevail over one
+ *             of descriptors in array.
+ *
+ * @return True if desc prevails over some descriptor in array
+ *
+ */
+static bool udf_check_prevailing_pvd(udf_primary_volume_descriptor_t *pvd,
+    size_t cnt, udf_primary_volume_descriptor_t *desc)
+{
+	for (size_t i = 0; i < cnt; i++) {
+		/*
+		 * According to ECMA 167 3/8.4.3
+		 * PVD, each of which has same contents of the corresponding
+		 * Volume Identifier, Volume set identifier
+		 * and Descriptor char set field.
+		 */
+		if ((bcmp((uint8_t *) pvd[i].volume_id,
+		    (uint8_t *) desc->volume_id, 32) == 0) &&
+		    (bcmp((uint8_t *) pvd[i].volume_set_id,
+		    (uint8_t *) desc->volume_set_id, 128) == 0) &&
+		    (bcmp((uint8_t *) &pvd[i].descriptor_charset,
+		    (uint8_t *) &desc->descriptor_charset, 64) == 0) &&
+		    (FLE32(desc->sequence_number) > FLE32(pvd[i].sequence_number))) {
+			memcpy(&pvd[i], desc, sizeof(udf_primary_volume_descriptor_t));
+			return true;
+		}
+	}
+	
+	return false;
+}
+
+/** Check on prevailing logic volume descriptor
+ *
+ * Some discs couldn't be rewritten and new information is identified
+ * by descriptors with same data as one of already created descriptors.
+ * We should find  prevailing descriptor (descriptor with the highest number)
+ * and delete old descriptor.
+ *
+ * @param lvd  Array of logic volumes descriptors
+ * @param cnt  Count of items in array
+ * @param desc Descriptor which could prevail over one
+ *             of descriptors in array.
+ *
+ * @return True if desc prevails over some descriptor in array
+ *
+ */
+static bool udf_check_prevailing_lvd(udf_logical_volume_descriptor_t *lvd,
+    size_t cnt, udf_logical_volume_descriptor_t *desc)
+{
+	for (size_t i = 0; i < cnt; i++) {
+		/*
+		 * According to ECMA 167 3/8.4.3
+		 * LVD, each of which has same contents of the corresponding
+		 * Logic Volume Identifier and Descriptor char set field.
+		 */
+		if ((bcmp((uint8_t *) lvd[i].logical_volume_id,
+		    (uint8_t *) desc->logical_volume_id, 128) == 0) &&
+		    (bcmp((uint8_t *) &lvd[i].charset,
+		    (uint8_t *) &desc->charset, 64) == 0) &&
+		    (FLE32(desc->sequence_number) > FLE32(lvd[i].sequence_number))) {
+			memcpy(&lvd[i], desc, sizeof(udf_logical_volume_descriptor_t));
+			return true;
+		}
+	}
+	
+	return false;
+}
+
+/** Check on prevailing partition descriptor
+ *
+ * Some discs couldn't be rewritten and new information is identified
+ * by descriptors with same data as one of already created descriptors.
+ * We should find  prevailing descriptor (descriptor with the highest number)
+ * and delete old descriptor.
+ *
+ * @param pvd  Array of partition descriptors
+ * @param cnt  Count of items in array
+ * @param desc Descriptor which could prevail over one
+ *             of descriptors in array.
+ *
+ * @return True if desc prevails over some descriptor in array
+ *
+ */
+static bool udf_check_prevailing_pd(udf_partition_descriptor_t *pd, size_t cnt,
+    udf_partition_descriptor_t *desc)
+{
+	for (size_t i = 0; i < cnt; i++) {
+		/*
+		 * According to ECMA 167 3/8.4.3
+		 * Partition descriptors with identical Partition Number
+		 */
+		if ((FLE16(pd[i].number) == FLE16(desc->number)) &&
+		    (FLE32(desc->sequence_number) > FLE32(pd[i].sequence_number))) {
+			memcpy(&pd[i], desc, sizeof(udf_partition_descriptor_t));
+			return true;
+		}
+	}
+	
+	return false;
+}
+
+/** Read information about virtual partition
+ *
+ * Fill start and length fields for partition. This function quite similar of
+ * udf_read_icd. But in this we can meet only two descriptors and
+ * we have to read only one allocator.
+ *
+ * @param instance UDF instance
+ * @param pos      Position (Extended) File entry descriptor
+ * @param id       Index of partition in instance::partitions array
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+static int udf_read_virtual_partition(udf_instance_t *instance, uint32_t pos,
+    uint32_t id)
+{
+	block_t *block = NULL;
+	int rc = block_get(&block, instance->service_id, pos,
+	    BLOCK_FLAGS_NONE);
+	if (rc != EOK)
+		return rc;
+	
+	udf_descriptor_tag_t *desc = (udf_descriptor_tag_t *) (block->data);
+	if (desc->checksum != udf_tag_checksum((uint8_t *) desc)) {
+		block_put(block);
+		return EINVAL;
+	}
+	
+	/*
+	 * We think that we have only one allocator. It is means that virtual
+	 * partition, like physical, isn't fragmented.
+	 * According to doc the type of allocator is short_ad.
+	 */
+	switch (FLE16(desc->id)) {
+	case UDF_FILE_ENTRY:
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "ICB: File entry descriptor found");
+		
+		udf_file_entry_descriptor_t *fed =
+		    (udf_file_entry_descriptor_t *) block->data;
+		uint32_t start_alloc = FLE32(fed->ea_lenght) + UDF_FE_OFFSET;
+		udf_short_ad_t *short_d =
+		    (udf_short_ad_t *) ((uint8_t *) fed + start_alloc);
+		instance->partitions[id].start = FLE32(short_d->position);
+		instance->partitions[id].lenght = FLE32(short_d->length);
+		break;
+		
+	case UDF_EFILE_ENTRY:
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "ICB: Extended file entry descriptor found");
+		
+		udf_extended_file_entry_descriptor_t *efed =
+		    (udf_extended_file_entry_descriptor_t *) block->data;
+		start_alloc = FLE32(efed->ea_lenght) + UDF_EFE_OFFSET;
+		short_d = (udf_short_ad_t *) ((uint8_t *) efed + start_alloc);
+		instance->partitions[id].start = FLE32(short_d->position);
+		instance->partitions[id].lenght = FLE32(short_d->length);
+		break;
+	}
+	
+	return block_put(block);
+}
+
+/** Search partition in array of partitions
+ *
+ * Used only in function udf_fill_volume_info
+ *
+ * @param pd     Array of partitions
+ * @param pd_cnt Count items in array
+ * @param id     Number partition (not index) which we want to find
+ *
+ * @return Index of partition or (size_t) -1 if we didn't find anything
+ *
+ */
+static size_t udf_find_partition(udf_partition_descriptor_t *pd, size_t pd_cnt,
+    size_t id)
+{
+	for (size_t i = 0; i < pd_cnt; i++) {
+		if (FLE16(pd[i].number) == id)
+			return i;
+	}
+	
+	return (size_t) -1;
+}
+
+/** Fill instance structures by information about partitions and logic
+ *
+ * @param lvd      Array of logic volumes descriptors
+ * @param lvd_cnt  Count of items in lvd array
+ * @param pd       Array of partition descriptors
+ * @param pd_cnt   Count of items in pd array
+ * @param instance UDF instance
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+static int udf_fill_volume_info(udf_logical_volume_descriptor_t *lvd,
+    size_t lvd_cnt, udf_partition_descriptor_t *pd, size_t pd_cnt,
+    udf_instance_t *instance)
+{
+	instance->volumes = calloc(lvd_cnt, sizeof(udf_lvolume_t));
+	if (instance->volumes == NULL)
+		return ENOMEM;
+	
+	instance->partitions = calloc(pd_cnt, sizeof(udf_partition_t));
+	if (instance->partitions == NULL) {
+		free(instance->volumes);
+		return ENOMEM;
+	}
+	
+	instance->partition_cnt = pd_cnt;
+	
+	/*
+	 * Fill information about logical volumes. We will save
+	 * information about all partitions placed inside each volumes.
+	 */
+	
+	size_t vir_pd_cnt = 0;
+	for (size_t i = 0; i < lvd_cnt; i++) {
+		instance->volumes[i].partitions =
+		    calloc(FLE32(lvd[i].number_of_partitions_maps),
+		    sizeof(udf_partition_t *));
+		if (instance->volumes[i].partitions == NULL) {
+			// FIXME: Memory leak, cleanup code missing
+			return ENOMEM;
+		}
+		
+		instance->volumes[i].partition_cnt = 0;
+		instance->volumes[i].logical_block_size =
+		    FLE32(lvd[i].logical_block_size);
+		
+		/*
+		 * In theory we could have more than 1 logical volume. But now
+		 * for current work of driver we will think that it single and all
+		 * partitions from array pd belong to only first lvd
+		 */
+		
+		uint8_t *idx = lvd[i].partition_map;
+		for (size_t j = 0; j < FLE32(lvd[i].number_of_partitions_maps);
+		    j++) {
+			udf_type1_partition_map_t *pm1 =
+			    (udf_type1_partition_map_t *) idx;
+			
+			if (pm1->partition_map_type == 1) {
+				size_t pd_num = udf_find_partition(pd, pd_cnt,
+				    FLE16(pm1->partition_number));
+				if (pd_num == (size_t) -1) {
+					// FIXME: Memory leak, cleanup code missing
+					return ENOENT;
+				}
+				
+				/*
+				 * Fill information about physical partitions. We will save all
+				 * partitions (physical and virtual) inside one array
+				 * instance::partitions
+				 */
+				instance->partitions[j].access_type =
+				    FLE32(pd[pd_num].access_type);
+				instance->partitions[j].lenght =
+				    FLE32(pd[pd_num].length);
+				instance->partitions[j].number =
+				    FLE16(pm1->partition_number);
+				instance->partitions[j].start =
+				    FLE32(pd[pd_num].starting_location);
+				
+				instance->volumes[i].partitions[
+				    instance->volumes[i].partition_cnt] =
+				    &instance->partitions[j];
+				
+				log_msg(LOG_DEFAULT, LVL_DEBUG, "Volume[%" PRIun "]: partition [type %u] "
+				    "found and filled", i, pm1->partition_map_type);
+				
+				instance->volumes[i].partition_cnt++;
+				idx += pm1->partition_map_lenght;
+				continue;
+			}
+			
+			udf_type2_partition_map_t *pm2 =
+			    (udf_type2_partition_map_t *) idx;
+			
+			if (pm2->partition_map_type == 2) {
+				// TODO: check partition_ident for metadata_partition_map
+				
+				udf_metadata_partition_map_t *metadata =
+				    (udf_metadata_partition_map_t *) idx;
+				
+				log_msg(LOG_DEFAULT, LVL_DEBUG, "Metadata file location=%u",
+				    FLE32(metadata->metadata_fileloc));
+				
+				vir_pd_cnt++;
+				instance->partitions = realloc(instance->partitions,
+				    (pd_cnt + vir_pd_cnt) * sizeof(udf_partition_t));
+				if (instance->partitions == NULL) {
+					// FIXME: Memory leak, cleanup code missing
+					return ENOMEM;
+				}
+				
+				instance->partition_cnt++;
+				
+				size_t pd_num = udf_find_partition(pd, pd_cnt,
+				    FLE16(metadata->partition_number));
+				if (pd_num == (size_t) -1) {
+					// FIXME: Memory leak, cleanup code missing
+					return ENOENT;
+				}
+				
+				instance->partitions[j].number =
+				    FLE16(metadata->partition_number);
+				int rc = udf_read_virtual_partition(instance,
+				    FLE32(metadata->metadata_fileloc) +
+				    FLE32(pd[pd_num].starting_location), j);
+				if (rc != EOK) {
+					// FIXME: Memory leak, cleanup code missing
+					return rc;
+				}
+				
+				/* Virtual partition placed inside physical */
+				instance->partitions[j].start +=
+				    FLE32(pd[pd_num].starting_location);
+				
+				instance->volumes[i].partitions[
+				    instance->volumes[i].partition_cnt] =
+				    &instance->partitions[j];
+				
+				log_msg(LOG_DEFAULT, LVL_DEBUG, "Virtual partition: num=%d, start=%d",
+				    instance->partitions[j].number,
+				    instance->partitions[j].start);
+				log_msg(LOG_DEFAULT, LVL_DEBUG, "Volume[%" PRIun "]: partition [type %u] "
+				    "found and filled", i, pm2->partition_map_type);
+				
+				instance->volumes[i].partition_cnt++;
+				idx += metadata->partition_map_length;
+				continue;
+			}
+			
+			/* Not type 1 nor type 2 */
+			udf_general_type_t *pm = (udf_general_type_t *) idx;
+			
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "Volume[%" PRIun "]: partition [type %u] "
+			    "found and skipped", i, pm->partition_map_type);
+			
+			idx += pm->partition_map_lenght;
+		}
+	}
+	
+	return EOK;
+}
+
+/** Read volume descriptors sequence
+ *
+ * @param service_id
+ * @param addr       UDF extent descriptor (ECMA 167 3/7.1)
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+int udf_read_volume_descriptor_sequence(service_id_t service_id,
+    udf_extent_t addr)
+{
+	udf_instance_t *instance;
+	int rc = fs_instance_get(service_id, (void **) &instance);
+	if (rc != EOK)
+		return rc;
+	
+	aoff64_t pos = addr.location;
+	aoff64_t end = pos + (addr.length / instance->sector_size) - 1;
+	
+	if (pos == end)
+		return EINVAL;
+	
+	size_t max_descriptors = ALL_UP(addr.length, instance->sector_size);
+	
+	udf_primary_volume_descriptor_t *pvd = calloc(max_descriptors,
+	    sizeof(udf_primary_volume_descriptor_t));
+	if (pvd == NULL)
+		return ENOMEM;
+	
+	udf_logical_volume_descriptor_t *lvd = calloc(max_descriptors,
+	    instance->sector_size);
+	if (lvd == NULL) {
+		free(pvd);
+		return ENOMEM;
+	}
+	
+	udf_partition_descriptor_t *pd = calloc(max_descriptors,
+	    sizeof(udf_partition_descriptor_t));
+	if (pd == NULL) {
+		free(pvd);
+		free(lvd);
+		return ENOMEM;
+	}
+	
+	size_t pvd_cnt = 0;
+	size_t lvd_cnt = 0;
+	size_t pd_cnt = 0;
+	
+	while (pos <= end) {
+		block_t *block = NULL;
+		rc = block_get(&block, service_id, pos, BLOCK_FLAGS_NONE);
+		if (rc != EOK) {
+			free(pvd);
+			free(lvd);
+			free(pd);
+			return rc;
+		}
+		
+		udf_volume_descriptor_t *vol =
+		    (udf_volume_descriptor_t *) block->data;
+		
+		switch (FLE16(vol->common.tag.id)) {
+		/* One sector size descriptors */
+		case UDF_TAG_PVD:
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "Volume: Primary volume descriptor found");
+			
+			if (!udf_check_prevailing_pvd(pvd, pvd_cnt, &vol->volume)) {
+				memcpy(&pvd[pvd_cnt], &vol->volume,
+				    sizeof(udf_primary_volume_descriptor_t));
+				pvd_cnt++;
+			}
+			
+			pos++;
+			break;
+			
+		case UDF_TAG_VDP:
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "Volume: Volume descriptor pointer found");
+			pos++;
+			break;
+			
+		case UDF_TAG_IUVD:
+			log_msg(LOG_DEFAULT, LVL_DEBUG,
+			    "Volume: Implementation use volume descriptor found");
+			pos++;
+			break;
+			
+		case UDF_TAG_PD:
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "Volume: Partition descriptor found");
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "Partition number: %u, contents: '%.6s', "
+			    "access type: %" PRIu32, FLE16(vol->partition.number),
+			    vol->partition.contents.id, FLE32(vol->partition.access_type));
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "Partition start: %" PRIu32 " (sector), "
+			    "size: %" PRIu32 " (sectors)",
+			    FLE32(vol->partition.starting_location),
+			    FLE32(vol->partition.length));
+			
+			if (!udf_check_prevailing_pd(pd, pd_cnt, &vol->partition)) {
+				memcpy(&pd[pd_cnt], &vol->partition,
+				    sizeof(udf_partition_descriptor_t));
+				pd_cnt++;
+			}
+			
+			udf_partition_header_descriptor_t *phd =
+			    (udf_partition_header_descriptor_t *) vol->partition.contents_use;
+			if (FLE32(phd->unallocated_space_table.length)) {
+				log_msg(LOG_DEFAULT, LVL_DEBUG,
+				    "space table: length=%" PRIu32 ", pos=%" PRIu32,
+				    FLE32(phd->unallocated_space_table.length),
+				    FLE32(phd->unallocated_space_table.position));
+				
+				instance->space_type = SPACE_TABLE;
+				instance->uaspace_start =
+				    FLE32(vol->partition.starting_location) +
+				    FLE32(phd->unallocated_space_table.position);
+				instance->uaspace_lenght =
+				    FLE32(phd->unallocated_space_table.length);
+			}
+			
+			if (FLE32(phd->unallocated_space_bitmap.length)) {
+				log_msg(LOG_DEFAULT, LVL_DEBUG,
+				    "space bitmap: length=%" PRIu32 ", pos=%" PRIu32,
+				    FLE32(phd->unallocated_space_bitmap.length),
+				    FLE32(phd->unallocated_space_bitmap.position));
+				
+				instance->space_type = SPACE_BITMAP;
+				instance->uaspace_start =
+				    FLE32(vol->partition.starting_location) +
+				    FLE32(phd->unallocated_space_bitmap.position);
+				instance->uaspace_lenght =
+				    FLE32(phd->unallocated_space_bitmap.length);
+			}
+			
+			pos++;
+			break;
+			
+		/* Relative size descriptors */
+		case UDF_TAG_LVD:
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "Volume: Logical volume descriptor found");
+			
+			aoff64_t sct =
+			    ALL_UP((sizeof(udf_logical_volume_descriptor_t) +
+			    FLE32(vol->logical.map_table_length)),
+			    sizeof(udf_common_descriptor_t));
+			pos += sct;
+			char tmp[130];
+			
+			udf_to_unix_name(tmp, 129,
+			    (char *) vol->logical.logical_volume_id, 128,
+			    &vol->logical.charset);
+			
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "Logical Volume ID: '%s', "
+			    "logical block size: %" PRIu32 " (bytes)", tmp,
+			    FLE32(vol->logical.logical_block_size));
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "Map table size: %" PRIu32 " (bytes), "
+			    "number of partition maps: %" PRIu32,
+			    FLE32(vol->logical.map_table_length),
+			    FLE32(vol->logical.number_of_partitions_maps));
+			
+			if (!udf_check_prevailing_lvd(lvd, lvd_cnt, &vol->logical)) {
+				memcpy(&lvd[lvd_cnt], &vol->logical,
+				    sizeof(udf_logical_volume_descriptor_t) +
+				    FLE32(vol->logical.map_table_length));
+				lvd_cnt++;
+			}
+			
+			break;
+			
+		case UDF_TAG_USD:
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "Volume: Unallocated space descriptor found");
+			
+			sct = ALL_UP((sizeof(udf_unallocated_space_descriptor_t) +
+			    FLE32(vol->unallocated.allocation_descriptors_num)*
+			    sizeof(udf_extent_t)), sizeof(udf_common_descriptor_t));
+			instance->uaspace_start = pos;
+			instance->uaspace_lenght = sct;
+			instance->uasd = (udf_unallocated_space_descriptor_t *)
+			    malloc(sct * instance->sector_size);
+			if (instance->uasd == NULL) {
+				// FIXME: Memory leak, cleanup missing
+				return ENOMEM;
+			}
+			
+			memcpy(instance->uasd, block->data, instance->sector_size);
+			pos += sct;
+			break;
+			
+		case UDF_TAG_LVID:
+			log_msg(LOG_DEFAULT, LVL_DEBUG,
+			    "Volume: Logical volume integrity descriptor found");
+			
+			pos++;
+			break;
+			
+		case UDF_TAG_TD:
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "Volume: Terminating descriptor found");
+			
+			/* Found terminating descriptor. Exiting */
+			pos = end + 1;
+			break;
+			
+		default:
+			pos++;
+		}
+		
+		rc = block_put(block);
+		if (rc != EOK) {
+			free(pvd);
+			free(lvd);
+			free(pd);
+			return rc;
+		}
+	}
+	
+	/* Fill the instance */
+	udf_fill_volume_info(lvd, lvd_cnt, pd, pd_cnt, instance);
+	
+	for (size_t i = 0; i < lvd_cnt; i++) {
+		pos = udf_long_ad_to_pos(instance,
+		    (udf_long_ad_t *) &lvd[i].logical_volume_conents_use);
+		
+		block_t *block = NULL;
+		rc = block_get(&block, instance->service_id, pos,
+		    BLOCK_FLAGS_NONE);
+		if (rc != EOK) {
+			// FIXME: Memory leak, cleanup missing
+			return rc;
+		}
+		
+		udf_descriptor_tag_t *desc = block->data;
+		
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "First tag ID=%" PRIu16, desc->id);
+		
+		if (desc->checksum != udf_tag_checksum((uint8_t *) desc)) {
+			// FIXME: Memory leak, cleanup missing
+			return EINVAL;
+		}
+		
+		udf_prepare_tag(desc);
+		
+		udf_fileset_descriptor_t *fd = block->data;
+		memcpy((uint8_t *) &instance->charset,
+		    (uint8_t *) &fd->fileset_charset, sizeof(fd->fileset_charset));
+		
+		instance->volumes[i].root_dir = udf_long_ad_to_pos(instance,
+		    &fd->root_dir_icb);
+	}
+	
+	free(pvd);
+	free(lvd);
+	free(pd);
+	return EOK;
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/fs/udf/udf_volume.h
===================================================================
--- uspace/srv/fs/udf/udf_volume.h	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
+++ uspace/srv/fs/udf/udf_volume.h	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2012 Julia Medvedeva
+ * 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 UDF_UDF_VOLUME_H_
+#define UDF_UDF_VOLUME_H_
+
+#include <sys/types.h>
+#include <ipc/loc.h>
+#include "udf_types.h"
+
+/* Descriptor Tag Identifier (ECMA 167 3/7.2.1) */
+#define UDF_TAG_PVD   0x0001  /* Primary Volume Descriptor */
+#define UDF_TAG_AVDP  0x0002  /* Anchor Volume Descriptor */
+#define UDF_TAG_VDP   0x0003  /* Volume Descriptor Pointer */
+#define UDF_TAG_IUVD  0x0004  /* Implementation Use Volume Descriptor */
+#define UDF_TAG_PD    0x0005  /* Partition Descriptor */
+#define UDF_TAG_LVD   0x0006  /* Logical Volume Descriptor */
+#define UDF_TAG_USD   0x0007  /* Unallocated Space Descriptor */
+#define UDF_TAG_TD    0x0008  /* Terminating Descriptor */
+#define UDF_TAG_LVID  0x0009  /* Logical Volume Integrity Descriptor */
+
+/* Start adress of Anchor Volume Descriptor */
+#define UDF_AVDP_SECTOR  256
+
+/* Volume Recognition Sequence params */
+#define VRS_ADDR     32768
+#define VRS_TYPE     0
+#define VRS_VERSION  1
+#define VRS_BEGIN    "BEA01"
+#define VRS_END      "TEA01"
+#define VRS_NSR2     "NSR02"
+#define VRS_NSR3     "NSR03"
+#define VRS_DEPTH    10
+#define VRS_ID_LEN   5
+
+/* Volume Structure Descriptor (ECMA 167 2/9.1) */
+typedef struct udf_vrs_descriptor {
+	uint8_t type;           /* Structure type */
+	uint8_t identifier[5];  /* Standart identifier */
+	uint8_t version;        /* Structure version */
+	uint8_t data[2041];     /* Structure data */
+} __attribute__((packed)) udf_vrs_descriptor_t;
+
+/* Anchor volume descriptor (ECMA 167 3/10.2) */
+typedef struct udf_anchor_volume_descriptor {
+	udf_descriptor_tag_t tag;     /* Descriptor tag */
+	udf_extent_t main_extent;     /* Main Volume Descriptor Sequence Extent */
+	udf_extent_t reserve_extent;  /* Reserve Volume Descriptor Sequence Extent */
+	uint8_t reserved[480];        /* Structure data */
+} __attribute__((packed)) udf_anchor_volume_descriptor_t;
+
+/* Common Volume Descriptor */
+typedef struct udf_common_descriptor {
+	udf_descriptor_tag_t tag;
+	uint8_t reserved[496];
+} __attribute__((packed)) udf_common_descriptor_t;
+
+/* Volume Descriptor Pointer (ECMA 167 3/10.3) */
+typedef struct udf_volume_pointer_descriptor {
+	udf_descriptor_tag_t tag;
+	uint32_t sequence_number;
+	udf_extent_t next_sequence;
+	uint8_t reserved[484];
+} __attribute__((packed)) udf_volume_pointer_descriptor_t;
+
+/* Primary Volume Descriptor (ECMA 167 3/10.1) */
+typedef struct udf_primary_volume_descriptor {
+	udf_descriptor_tag_t tag;
+	uint32_t sequence_number;
+	uint32_t primary_volume_descriptor_num;
+	udf_dstring volume_id[32];
+	uint16_t max_sequence_number;
+	uint16_t interchange_level;
+	uint16_t max_interchange_level;
+	uint32_t charset_list;
+	uint32_t max_charset_list;
+	udf_dstring volume_set_id[128];
+	udf_charspec_t descriptor_charset;
+	udf_charspec_t explanatory_charset;
+	udf_extent_t volume_abstract;
+	udf_extent_t volume_copyright_notice;
+	udf_regid_t application_id;
+	udf_timestamp_t recording_data_and_time;
+	udf_regid_t implementation_id;
+	uint8_t implementation_use[64];
+	uint32_t predecessor_vds_location;
+	uint16_t flags;
+	uint8_t reserved[22];
+} __attribute__((packed)) udf_primary_volume_descriptor_t;
+
+
+/* Partition Descriptor (ECMA 167 3/10.5) */
+typedef struct udf_partition_descriptor {
+	udf_descriptor_tag_t tag;
+	uint32_t sequence_number;
+	uint16_t flags;
+	uint16_t number;
+	udf_regid_t contents;
+	uint8_t contents_use[128];
+	uint32_t access_type;
+	uint32_t starting_location;
+	uint32_t length;
+	udf_regid_t implementation_id;
+	uint8_t implementation_use[128];
+	uint8_t reserved[156];
+} __attribute__((packed)) udf_partition_descriptor_t;
+
+/* Logical Volume Descriptor (ECMA 167 3/10.6) */
+typedef struct udf_logical_volume_descriptor {
+	udf_descriptor_tag_t tag;
+	uint32_t sequence_number;
+	udf_charspec_t charset;
+	udf_dstring logical_volume_id[128];
+	uint32_t logical_block_size;
+	udf_regid_t domain_id;
+	uint8_t logical_volume_conents_use[16];
+	uint32_t map_table_length;
+	uint32_t number_of_partitions_maps;
+	udf_regid_t implementation_id;
+	uint8_t implementation_use[128];
+	udf_extent_t integrity_sequence_extent;
+	uint8_t partition_map[0];
+} __attribute__((packed)) udf_logical_volume_descriptor_t;
+
+typedef struct udf_volume_descriptor {
+	union {
+		udf_common_descriptor_t common;
+		udf_terminating_descriptor_t terminating;
+		udf_volume_pointer_descriptor_t pointer;
+		udf_partition_descriptor_t partition;
+		udf_logical_volume_descriptor_t logical;
+		udf_unallocated_space_descriptor_t unallocated;
+		udf_primary_volume_descriptor_t volume;
+	};
+} __attribute__((packed)) udf_volume_descriptor_t;
+
+typedef struct udf_general_type {
+	uint8_t partition_map_type;
+	uint8_t partition_map_lenght;
+} __attribute__((packed)) udf_general_type_t;
+
+typedef struct udf_type1_partition_map {
+	uint8_t partition_map_type;
+	uint8_t partition_map_lenght;
+	uint16_t volume_sequence_number;
+	uint16_t partition_number;
+} __attribute__((packed)) udf_type1_partition_map_t;
+
+typedef struct udf_type2_partition_map {
+	uint8_t partition_map_type;
+	uint8_t partition_map_length;
+	uint8_t reserved1[2];
+	udf_regid_t partition_ident;
+	uint16_t volume_sequence_number;
+	uint16_t partition_number;
+} __attribute__((packed)) udf_type2_partition_map_t;
+
+/* Metadata Partition Map (UDF 2.4.0 2.2.10) */
+typedef struct udf_metadata_partition_map {
+	uint8_t partition_map_type;
+	uint8_t partition_map_length;
+	uint8_t reserved1[2];
+	udf_regid_t partition_ident;
+	uint16_t volume_sequence_number;
+	uint16_t partition_number;
+	uint32_t metadata_fileloc;
+	uint32_t metadata_mirror_fileloc;
+	uint32_t metadata_bitmap_fileloc;
+	uint32_t alloc_unit_size;
+	uint16_t align_unit_size;
+	uint8_t flags;
+	uint8_t reserved2[5];
+} __attribute__((packed)) udf_metadata_partition_map_t;
+
+/* Partition Header Descriptor (ECMA 167 4/14.3) */
+typedef struct udf_partition_header_descriptor {
+	udf_short_ad_t unallocated_space_table;
+	udf_short_ad_t unallocated_space_bitmap;
+	udf_short_ad_t partition_integrity_table;
+	udf_short_ad_t freed_space_table;
+	udf_short_ad_t freed_space_bitmap;
+	uint8_t reserved[88];
+} __attribute__((packed)) udf_partition_header_descriptor_t;
+
+extern int udf_volume_recongnition(service_id_t);
+extern int udf_get_anchor_volume_descriptor(service_id_t,
+    udf_anchor_volume_descriptor_t *);
+extern int udf_read_volume_descriptor_sequence(service_id_t, udf_extent_t);
+extern fs_index_t udf_long_ad_to_pos(udf_instance_t *, udf_long_ad_t *);
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/srv/hid/compositor/compositor.c
===================================================================
--- uspace/srv/hid/compositor/compositor.c	(revision 131d9a4ae105fe5f519d8dbbfda588ef5358a648)
+++ uspace/srv/hid/compositor/compositor.c	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -49,6 +49,6 @@
 #include <adt/prodcons.h>
 #include <adt/list.h>
+#include <io/input.h>
 #include <ipc/graph.h>
-#include <ipc/input.h>
 #include <ipc/window.h>
 
@@ -92,11 +92,8 @@
 	sysarg_t id;
 	uint8_t state;
-	sysarg_t hpos;
-	sysarg_t vpos;
+	desktop_point_t pos;
 	sysarg_t btn_num;
-	sysarg_t btn_hpos;
-	sysarg_t btn_vpos;
-	int accum_dx;
-	int accum_dy;
+	desktop_point_t btn_pos;
+	desktop_vector_t accum;
 	sysarg_t grab_flags;
 	bool pressed;
@@ -135,6 +132,5 @@
 	vslmode_t mode;
 	async_sess_t *sess;
-	sysarg_t hpos;
-	sysarg_t vpos;
+	desktop_point_t pos;
 	surface_t *surface;
 } viewport_t;
@@ -143,5 +139,26 @@
 static LIST_INITIALIZE(viewport_list);
 
-static async_sess_t *input_sess;
+/** Input server proxy */
+static input_t *input;
+
+static int comp_key_press(input_t *, kbd_event_type_t, keycode_t, keymod_t, wchar_t);
+static int comp_mouse_move(input_t *, int, int);
+static int comp_abs_move(input_t *, unsigned, unsigned, unsigned, unsigned);
+static int comp_mouse_button(input_t *, int, int);
+
+static input_ev_ops_t input_ev_ops = {
+	.key = comp_key_press,
+	.move = comp_mouse_move,
+	.abs_move = comp_abs_move,
+	.button = comp_mouse_button
+};
+
+static void input_disconnect(void);
+
+
+static pointer_t *input_pointer(input_t *input)
+{
+	return input->user;
+}
 
 static pointer_t *pointer_create()
@@ -153,11 +170,10 @@
 
 	link_initialize(&p->link);
-	p->hpos = coord_origin;
-	p->vpos = coord_origin;
+	p->pos.x = coord_origin;
+	p->pos.y = coord_origin;
 	p->btn_num = 1;
-	p->btn_hpos = p->hpos;
-	p->btn_vpos = p->vpos;
-	p->accum_dx = 0;
-	p->accum_dy = 0;
+	p->btn_pos = p->pos;
+	p->accum.x = 0;
+	p->accum.y = 0;
 	p->grab_flags = GF_EMPTY;
 	p->pressed = false;
@@ -286,5 +302,5 @@
 		bool isec_vp = rectangle_intersect(
 		    x_dmg_glob, y_dmg_glob, w_dmg_glob, h_dmg_glob,
-		    vp->hpos, vp->vpos, w_dmg_vp, h_dmg_vp,
+		    vp->pos.x, vp->pos.y, w_dmg_vp, h_dmg_vp,
 		    &x_dmg_vp, &y_dmg_vp, &w_dmg_vp, &h_dmg_vp);
 
@@ -292,6 +308,6 @@
 
 			/* Paint background color. */
-			for (sysarg_t y = y_dmg_vp - vp->vpos; y <  y_dmg_vp - vp->vpos + h_dmg_vp; ++y) {
-				for (sysarg_t x = x_dmg_vp - vp->hpos; x < x_dmg_vp - vp->hpos + w_dmg_vp; ++x) {
+			for (sysarg_t y = y_dmg_vp - vp->pos.y; y <  y_dmg_vp - vp->pos.y + h_dmg_vp; ++y) {
+				for (sysarg_t x = x_dmg_vp - vp->pos.x; x < x_dmg_vp - vp->pos.x + w_dmg_vp; ++x) {
 					surface_put_pixel(vp->surface, x, y, bg_color);
 				}
@@ -331,7 +347,8 @@
 					 * coordinates. */
 					transform = win->transform;
-					double hpos = vp->hpos;
-					double vpos = vp->vpos;
-					transform_translate(&transform, -hpos, -vpos);
+					double_point_t pos;
+					pos.x = vp->pos.x;
+					pos.y = vp->pos.y;
+					transform_translate(&transform, -pos.x, -pos.y);
 
 					source_set_transform(&source, transform);				
@@ -340,5 +357,5 @@
 
 					drawctx_transfer(&context,
-					    x_dmg_win - vp->hpos, y_dmg_win - vp->vpos, w_dmg_win, h_dmg_win);
+					    x_dmg_win - vp->pos.x, y_dmg_win - vp->pos.y, w_dmg_win, h_dmg_win);
 				}
 			}
@@ -354,5 +371,5 @@
 				bool isec_ptr = rectangle_intersect(
 				    x_dmg_vp, y_dmg_vp, w_dmg_vp, h_dmg_vp,
-				    ptr->hpos, ptr->vpos, w_dmg_ptr, h_dmg_ptr,
+				    ptr->pos.x, ptr->pos.y, w_dmg_ptr, h_dmg_ptr,
 				    &x_dmg_ptr, &y_dmg_ptr, &w_dmg_ptr, &h_dmg_ptr);
 
@@ -365,8 +382,8 @@
 
 					pixel_t pix = 0;
-					sysarg_t x_vp = x_dmg_ptr - vp->hpos;
-					sysarg_t y_vp = y_dmg_ptr - vp->vpos;
-					sysarg_t x_ptr = x_dmg_ptr - ptr->hpos;
-					sysarg_t y_ptr = y_dmg_ptr - ptr->vpos;
+					sysarg_t x_vp = x_dmg_ptr - vp->pos.x;
+					sysarg_t y_vp = y_dmg_ptr - vp->pos.y;
+					sysarg_t x_ptr = x_dmg_ptr - ptr->pos.x;
+					sysarg_t y_ptr = y_dmg_ptr - ptr->pos.y;
 
 					for (sysarg_t y = 0; y < h_dmg_ptr; ++y) {
@@ -759,5 +776,5 @@
 		fibril_mutex_unlock(&viewport_list_mtx);
 		loc_service_unregister(winreg_id);
-		async_hangup(input_sess);
+		input_disconnect();
 
 		/* Close all clients and their windows. */
@@ -880,6 +897,6 @@
 
 	link_initialize(&vp->link);
-	vp->hpos = coord_origin;
-	vp->vpos = coord_origin;
+	vp->pos.x = coord_origin;
+	vp->pos.y = coord_origin;
 
 	/* Establish output bidirectional connection. */
@@ -981,8 +998,8 @@
 	/* window_list_mtx locked by caller */
 
-	int dx = pointer->accum_dx;
-	int dy = pointer->accum_dy;
-	pointer->accum_dx = 0;
-	pointer->accum_dy = 0;
+	int dx = pointer->accum.x;
+	int dy = pointer->accum.y;
+	pointer->accum.x = 0;
+	pointer->accum.y = 0;
 
 	bool move = (pointer->grab_flags & GF_MOVE_X) || (pointer->grab_flags & GF_MOVE_Y);
@@ -1055,22 +1072,55 @@
 }
 
-static void comp_mouse_move(pointer_t *pointer, ipc_callid_t iid, ipc_call_t *icall)
-{
-	int dx = (int) IPC_GET_ARG1(*icall);
-	int dy = (int) IPC_GET_ARG2(*icall);
+static int comp_abs_move(input_t *input, unsigned x , unsigned y,
+    unsigned max_x, unsigned max_y)
+{
+	/* XXX TODO Use absolute coordinates directly */
+	
+	pointer_t *pointer = input_pointer(input);
+	
+	sysarg_t width, height;
+	
+	fibril_mutex_lock(&viewport_list_mtx);
+	if (list_empty(&viewport_list)) {
+		printf("No viewport found\n");
+		fibril_mutex_unlock(&viewport_list_mtx);
+		return EOK; /* XXX */
+	}
+	link_t *link = list_first(&viewport_list);
+	viewport_t *vp = list_get_instance(link, viewport_t, link);
+	surface_get_resolution(vp->surface, &width, &height);
+	desktop_point_t vp_pos = vp->pos;
+	fibril_mutex_unlock(&viewport_list_mtx);
+
+	desktop_point_t pos_in_viewport;
+	pos_in_viewport.x = x * width / max_x;
+	pos_in_viewport.y = y * height / max_y;
+	
+	/* Calculate offset from pointer */
+	fibril_mutex_lock(&pointer_list_mtx);
+	desktop_vector_t delta;
+	delta.x = (vp_pos.x + pos_in_viewport.x) - pointer->pos.x;
+	delta.y = (vp_pos.y + pos_in_viewport.y) - pointer->pos.y;
+	fibril_mutex_unlock(&pointer_list_mtx);
+	
+	return comp_mouse_move(input, delta.x, delta.y);
+}
+
+static int comp_mouse_move(input_t *input, int dx, int dy)
+{
+	pointer_t *pointer = input_pointer(input);
 
 	/* Update pointer position. */
 	fibril_mutex_lock(&pointer_list_mtx);
-	sysarg_t old_hpos = pointer->hpos;
-	sysarg_t old_vpos = pointer->vpos;
+	desktop_point_t old_pos = pointer->pos;
 	sysarg_t cursor_width;
 	sysarg_t cursor_height;
 	surface_get_resolution(pointer->cursor.states[pointer->state], 
 	     &cursor_width, &cursor_height);
-	pointer->hpos += dx;
-	pointer->vpos += dy;
+	pointer->pos.x += dx;
+	pointer->pos.y += dy;
 	fibril_mutex_unlock(&pointer_list_mtx);
-	comp_damage(old_hpos, old_vpos, cursor_width, cursor_height);
-	comp_damage(old_hpos + dx, old_vpos + dy, cursor_width, cursor_height);
+	comp_damage(old_pos.x, old_pos.y, cursor_width, cursor_height);
+	comp_damage(old_pos.x + dx, old_pos.y + dy, cursor_width, cursor_height);
 
 	fibril_mutex_lock(&window_list_mtx);
@@ -1084,5 +1134,5 @@
 			sysarg_t width, height;
 			surface_get_resolution(top->surface, &width, &height);
-			within_client = comp_coord_to_client(pointer->hpos, pointer->vpos,
+			within_client = comp_coord_to_client(pointer->pos.x, pointer->pos.y,
 			    top->transform, width, height, &point_x, &point_y);
 			fibril_mutex_unlock(&window_list_mtx);
@@ -1103,6 +1153,6 @@
 		} else {
 			/* Pointer is grabbed by top-level window action. */
-			pointer->accum_dx += dx;
-			pointer->accum_dy += dy;
+			pointer->accum.x += dx;
+			pointer->accum.y += dy;
 #if ANIMATE_WINDOW_TRANSFORMS == 1
 			sysarg_t x, y, width, height;
@@ -1118,16 +1168,14 @@
 	}
 
-	async_answer_0(iid, EOK);
-}
-
-static void comp_mouse_button(pointer_t *pointer, ipc_callid_t iid, ipc_call_t *icall)
-{
-	sysarg_t btn_num = IPC_GET_ARG1(*icall);
-	bool pressed = (bool) IPC_GET_ARG2(*icall);
-
-	if (pressed) {
-		pointer->btn_hpos = pointer->hpos;
-		pointer->btn_vpos = pointer->vpos;
-		pointer->btn_num = btn_num;
+	return EOK;
+}
+
+static int comp_mouse_button(input_t *input, int bnum, int bpress)
+{
+	pointer_t *pointer = input_pointer(input);
+
+	if (bpress) {
+		pointer->btn_pos = pointer->pos;
+		pointer->btn_num = bnum;
 		pointer->pressed = true;
 
@@ -1137,10 +1185,9 @@
 		if (!win || !win->surface) {
 			fibril_mutex_unlock(&window_list_mtx);
-			async_answer_0(iid, EOK);
-			return;
+			return EOK;
 		}
 		sysarg_t x, y, width, height;
 		surface_get_resolution(win->surface, &width, &height);
-		bool within_client = comp_coord_to_client(pointer->hpos, pointer->vpos,
+		bool within_client = comp_coord_to_client(pointer->pos.x, pointer->pos.y,
 		    win->transform, width, height, &x, &y);
 		fibril_mutex_unlock(&window_list_mtx);
@@ -1154,14 +1201,13 @@
 				event->data.pos.pos_id = pointer->id;
 				event->data.pos.type = POS_PRESS;
-				event->data.pos.btn_num = btn_num;
+				event->data.pos.btn_num = bnum;
 				event->data.pos.hpos = x;
 				event->data.pos.vpos = y;
 				comp_post_event(event);
 			} else {
-				async_answer_0(iid, ENOMEM);
-				return;
-			}
-		}
-	} else if (pointer->pressed && pointer->btn_num == btn_num) {
+				return ENOMEM;
+			}
+		}
+	} else if (pointer->pressed && pointer->btn_num == (unsigned)bnum) {
 		pointer->pressed = false;
 
@@ -1178,5 +1224,5 @@
 			if (win->surface) {
 				surface_get_resolution(win->surface, &width, &height);
-				within_client = comp_coord_to_client(pointer->hpos, pointer->vpos,
+				within_client = comp_coord_to_client(pointer->pos.x, pointer->pos.y,
 				    win->transform, width, height, &point_x, &point_y);
 			}
@@ -1191,6 +1237,5 @@
 			pointer->grab_flags = GF_EMPTY;
 			fibril_mutex_unlock(&window_list_mtx);
-			async_answer_0(iid, EOK);
-			return;
+			return EOK;
 		}
 
@@ -1257,5 +1302,5 @@
 				event->data.pos.pos_id = pointer->id;
 				event->data.pos.type = POS_RELEASE;
-				event->data.pos.btn_num = btn_num;
+				event->data.pos.btn_num = bnum;
 				event->data.pos.hpos = point_x;
 				event->data.pos.vpos = point_y;
@@ -1263,5 +1308,5 @@
 			pointer->grab_flags = GF_EMPTY;
 			
-		} else if (within_client && (pointer->grab_flags == GF_EMPTY) && (btn_num == 1)) {
+		} else if (within_client && (pointer->grab_flags == GF_EMPTY) && (bnum == 1)) {
 
 			/* Bring the window to the foreground. */
@@ -1286,14 +1331,10 @@
 	}
 
-	async_answer_0(iid, EOK);
-}
-
-static void comp_key_press(ipc_callid_t iid, ipc_call_t *icall)
-{
-	kbd_event_type_t type = IPC_GET_ARG1(*icall);
-	keycode_t key = IPC_GET_ARG2(*icall);
-	keymod_t mods = IPC_GET_ARG3(*icall);
-	wchar_t c = IPC_GET_ARG4(*icall);
-
+	return EOK;
+}
+
+static int comp_key_press(input_t *input, kbd_event_type_t type, keycode_t key,
+    keymod_t mods, wchar_t c)
+{
 	bool win_transform = (mods & KM_ALT) && (
 	    key == KC_W || key == KC_S || key == KC_A || key == KC_D ||
@@ -1378,6 +1419,5 @@
 			if (event == NULL) {
 				fibril_mutex_unlock(&window_list_mtx);
-				async_answer_0(iid, ENOMEM);
-				return;
+				return ENOMEM;
 			}
 
@@ -1448,8 +1488,6 @@
 	} else if (win_close) {
 		window_event_t *event = (window_event_t *) malloc(sizeof(window_event_t));
-		if (event == NULL) {
-			async_answer_0(iid, ENOMEM);
-			return;
-		}
+		if (event == NULL)
+			return ENOMEM;
 
 		link_initialize(&event->link);
@@ -1502,27 +1540,27 @@
 			switch (key) {
 			case KC_I:
-				vp->hpos += 0;
-				vp->vpos += -20;
+				vp->pos.x += 0;
+				vp->pos.y += -20;
 				break;
 			case KC_K:
-				vp->hpos += 0;
-				vp->vpos += 20;
+				vp->pos.x += 0;
+				vp->pos.y += 20;
 				break;
 			case KC_J:
-				vp->hpos += -20;
-				vp->vpos += 0;
+				vp->pos.x += -20;
+				vp->pos.y += 0;
 				break;
 			case KC_L:
-				vp->hpos += 20;
-				vp->vpos += 0;
+				vp->pos.x += 20;
+				vp->pos.y += 0;
 				break;
 			default:
-				vp->hpos += 0;
-				vp->vpos += 0;
+				vp->pos.x += 0;
+				vp->pos.y += 0;
 				break;
 			}
 			
-			sysarg_t x = vp->hpos;
-			sysarg_t y = vp->vpos;
+			sysarg_t x = vp->pos.x;
+			sysarg_t y = vp->pos.y;
 			sysarg_t width, height;
 			surface_get_resolution(vp->surface, &width, &height);
@@ -1594,8 +1632,6 @@
 	} else {
 		window_event_t *event = (window_event_t *) malloc(sizeof(window_event_t));
-		if (event == NULL) {
-			async_answer_0(iid, ENOMEM);
-			return;
-		}
+		if (event == NULL)
+			return ENOMEM;
 
 		link_initialize(&event->link);
@@ -1609,9 +1645,25 @@
 	}
 
-	async_answer_0(iid, EOK);
-}
-
-static void input_events(ipc_callid_t iid, ipc_call_t *icall, void *arg)
-{
+	return EOK;
+}
+
+static int input_connect(const char *svc)
+{
+	async_sess_t *sess;
+	service_id_t dsid;
+
+	int rc = loc_service_get_id(svc, &dsid, 0);
+	if (rc != EOK) {
+		printf("%s: Input service %s not found\n", NAME, svc);
+		return rc;
+	}
+
+	sess = loc_service_connect(EXCHANGE_ATOMIC, dsid, 0);
+	if (sess == NULL) {
+		printf("%s: Unable to connect to input service %s\n", NAME,
+		    svc);
+		return EIO;
+	}
+
 	fibril_mutex_lock(&pointer_list_mtx);
 	pointer_t *pointer = pointer_create();
@@ -1622,63 +1674,26 @@
 	fibril_mutex_unlock(&pointer_list_mtx);
 
-	/* Ignore parameters, the connection is already opened. */
-	while (true) {
-		ipc_call_t call;
-		ipc_callid_t callid = async_get_call(&call);
-
-		if (!IPC_GET_IMETHOD(call)) {
-			fibril_mutex_lock(&pointer_list_mtx);
-			if (pointer != NULL) {
-				list_remove(&pointer->link);
-				pointer_destroy(pointer);
-			}
-			fibril_mutex_unlock(&pointer_list_mtx);
-			async_hangup(input_sess);
-			return;
-		}
-
-		switch (IPC_GET_IMETHOD(call)) {
-		case INPUT_EVENT_KEY:
-			comp_key_press(callid, &call);
-			break;
-		case INPUT_EVENT_MOVE:
-			comp_mouse_move(pointer, callid, &call);
-			break;
-		case INPUT_EVENT_BUTTON:
-			comp_mouse_button(pointer, callid, &call);
-			break;
-		default:
-			async_answer_0(callid, EINVAL);
-		}
-	}
-}
-
-static async_sess_t *input_connect(const char *svc)
-{
-	async_sess_t *sess;
-	service_id_t dsid;
-
-	int rc = loc_service_get_id(svc, &dsid, 0);
-	if (rc == EOK) {
-		sess = loc_service_connect(EXCHANGE_ATOMIC, dsid, 0);
-		if (sess == NULL) {
-			printf("%s: Unable to connect to input service %s\n", NAME, svc);
-			return NULL;
-		}
-	} else
-		return NULL;
-
-	async_exch_t *exch = async_exchange_begin(sess);
-	rc = async_connect_to_me(exch, 0, 0, 0, input_events, NULL);
-	async_exchange_end(exch);
-
+	if (pointer == NULL) {
+		printf("%s: Cannot create pointer.\n", NAME);
+		async_hangup(sess);
+		return ENOMEM;
+	}
+
+	rc = input_open(sess, &input_ev_ops, pointer, &input);
 	if (rc != EOK) {
 		async_hangup(sess);
-		printf("%s: Unable to create callback connection to service %s (%s)\n",
+		printf("%s: Unable to communicate with service %s (%s)\n",
 		    NAME, svc, str_error(rc));
-		return NULL;
-	}
-
-	return sess;
+		return rc;
+	}
+
+	return EOK;
+}
+
+static void input_disconnect(void)
+{
+    	pointer_t *pointer = input->user;
+	input_close(input);
+	pointer_destroy(pointer);
 }
 
@@ -1733,8 +1748,7 @@
 
 	/* Establish input bidirectional connection. */
-	input_sess = input_connect(input_svc);
-	if (input_sess == NULL) {
-		return -1;
-	}
+	rc = input_connect(input_svc);
+	if (rc != EOK)
+		return rc;
 
 	/* Create viewports and connect them to visualizers. */
@@ -1742,5 +1756,5 @@
 	rc = loc_category_get_id("visualizer", &cat_id, IPC_FLAG_BLOCKING);
 	if (rc != EOK) {
-		async_hangup(input_sess);
+		input_disconnect();
 		return -1;
 	}
@@ -1750,5 +1764,5 @@
 	rc = loc_category_get_svcs(cat_id, &svcs, &svcs_cnt);
 	if (rc != EOK || svcs_cnt == 0) {
-		async_hangup(input_sess);
+		input_disconnect();
 		return -1;
 	}
@@ -1766,5 +1780,5 @@
 	
 	if (list_empty(&viewport_list)) {
-		async_hangup(input_sess);
+		input_disconnect();
 		return -1;
 	}
Index: uspace/srv/hid/compositor/compositor.h
===================================================================
--- uspace/srv/hid/compositor/compositor.h	(revision 131d9a4ae105fe5f519d8dbbfda588ef5358a648)
+++ uspace/srv/hid/compositor/compositor.h	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -36,4 +36,18 @@
 #define COMPOSITOR_COMPOSITOR_H_
 
+typedef native_t desktop_coord_t;
+typedef struct {
+	desktop_coord_t x;
+	desktop_coord_t y;
+} desktop_point_t;
+typedef desktop_point_t desktop_vector_t;
+
+/* TODO remove? */
+typedef struct {
+	double x;
+	double y;
+} double_point_t;
+typedef double_point_t double_vector_t;
+
 #endif
 
Index: uspace/srv/hid/console/console.c
===================================================================
--- uspace/srv/hid/console/console.c	(revision 131d9a4ae105fe5f519d8dbbfda588ef5358a648)
+++ uspace/srv/hid/console/console.c	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -36,6 +36,5 @@
 #include <stdio.h>
 #include <adt/prodcons.h>
-#include <ipc/input.h>
-#include <ipc/console.h>
+#include <io/input.h>
 #include <ipc/vfs.h>
 #include <errno.h>
@@ -43,7 +42,8 @@
 #include <loc.h>
 #include <event.h>
+#include <io/con_srv.h>
+#include <io/kbd_event.h>
 #include <io/keycode.h>
 #include <io/chargrid.h>
-#include <io/console.h>
 #include <io/output.h>
 #include <align.h>
@@ -79,8 +79,9 @@
 	chargrid_t *frontbuf;    /**< Front buffer */
 	frontbuf_handle_t fbid;  /**< Front buffer handle */
+	con_srvs_t srvs;         /**< Console service setup */
 } console_t;
 
-/** Session to the input server */
-static async_sess_t *input_sess;
+/** Input server proxy */
+static input_t *input;
 
 /** Session to the output server */
@@ -101,4 +102,56 @@
 static console_t *kernel_console = &consoles[KERNEL_CONSOLE];
 
+static int input_ev_key(input_t *, kbd_event_type_t, keycode_t, keymod_t, wchar_t);
+static int input_ev_move(input_t *, int, int);
+static int input_ev_abs_move(input_t *, unsigned, unsigned, unsigned, unsigned);
+static int input_ev_button(input_t *, int, int);
+
+static input_ev_ops_t input_ev_ops = {
+	.key = input_ev_key,
+	.move = input_ev_move,
+	.abs_move = input_ev_abs_move,
+	.button = input_ev_button
+};
+
+static int cons_open(con_srvs_t *, con_srv_t *);
+static int cons_close(con_srv_t *);
+static int cons_read(con_srv_t *, void *, size_t);
+static int cons_write(con_srv_t *, void *, size_t);
+static void cons_sync(con_srv_t *);
+static void cons_clear(con_srv_t *);
+static void cons_set_pos(con_srv_t *, sysarg_t col, sysarg_t row);
+static int cons_get_pos(con_srv_t *, sysarg_t *, sysarg_t *);
+static int cons_get_size(con_srv_t *, sysarg_t *, sysarg_t *);
+static int cons_get_color_cap(con_srv_t *, console_caps_t *);
+static void cons_set_style(con_srv_t *, console_style_t);
+static void cons_set_color(con_srv_t *, console_color_t, console_color_t,
+    console_color_attr_t);
+static void cons_set_rgb_color(con_srv_t *, pixel_t, pixel_t);
+static void cons_set_cursor_visibility(con_srv_t *, bool);
+static int cons_get_event(con_srv_t *, kbd_event_t *);
+
+static con_ops_t con_ops = {
+	.open = cons_open,
+	.close = cons_close,
+	.read = cons_read,
+	.write = cons_write,
+	.sync = cons_sync,
+	.clear = cons_clear,
+	.set_pos = cons_set_pos,
+	.get_pos = cons_get_pos,
+	.get_size = cons_get_size,
+	.get_color_cap = cons_get_color_cap,
+	.set_style = cons_set_style,
+	.set_color = cons_set_color,
+	.set_rgb_color = cons_set_rgb_color,
+	.set_cursor_visibility = cons_set_cursor_visibility,
+	.get_event = cons_get_event
+};
+
+static console_t *srv_to_console(con_srv_t *srv)
+{
+	return srv->srvs->sarg;
+}
+
 static void cons_update(console_t *cons)
 {
@@ -125,13 +178,4 @@
 	fibril_mutex_unlock(&cons->mtx);
 	fibril_mutex_unlock(&switch_mtx);
-}
-
-static void cons_clear(console_t *cons)
-{
-	fibril_mutex_lock(&cons->mtx);
-	chargrid_clear(cons->frontbuf);
-	fibril_mutex_unlock(&cons->mtx);
-	
-	cons_update(cons);
 }
 
@@ -195,71 +239,53 @@
 }
 
-static void input_events(ipc_callid_t iid, ipc_call_t *icall, void *arg)
-{
-	/* Ignore parameters, the connection is already opened */
-	while (true) {
-		ipc_call_t call;
-		ipc_callid_t callid = async_get_call(&call);
-		
-		if (!IPC_GET_IMETHOD(call)) {
-			/* TODO: Handle hangup */
-			async_hangup(input_sess);
-			return;
-		}
-		
-		kbd_event_type_t type;
-		keycode_t key;
-		keymod_t mods;
-		wchar_t c;
-		
-		switch (IPC_GET_IMETHOD(call)) {
-		case INPUT_EVENT_KEY:
-			type = IPC_GET_ARG1(call);
-			key = IPC_GET_ARG2(call);
-			mods = IPC_GET_ARG3(call);
-			c = IPC_GET_ARG4(call);
-			
-			if ((key >= KC_F1) && (key < KC_F1 + CONSOLE_COUNT) &&
-			    ((mods & KM_CTRL) == 0))
-				cons_switch(&consoles[key - KC_F1]);
-			else {
-				/* Got key press/release event */
-				kbd_event_t *event =
-				    (kbd_event_t *) malloc(sizeof(kbd_event_t));
-				if (event == NULL) {
-					async_answer_0(callid, ENOMEM);
-					break;
-				}
-				
-				link_initialize(&event->link);
-				event->type = type;
-				event->key = key;
-				event->mods = mods;
-				event->c = c;
-				
-				/*
-				 * Kernel console does not read events
-				 * from us, so we will redirect them
-				 * to the (last) active userspace console
-				 * if necessary.
-				 */
-				console_t *target_console = cons_get_active_uspace();
-				
-				prodcons_produce(&target_console->input_pc,
-				    &event->link);
-			}
-			
-			async_answer_0(callid, EOK);
-			break;
-		case INPUT_EVENT_MOVE:
-			async_answer_0(callid, EOK);
-			break;
-		case INPUT_EVENT_BUTTON:
-			async_answer_0(callid, EOK);
-			break;
-		default:
-			async_answer_0(callid, EINVAL);
-		}
-	}
+static int input_ev_key(input_t *input, kbd_event_type_t type, keycode_t key,
+    keymod_t mods, wchar_t c)
+{
+	if ((key >= KC_F1) && (key < KC_F1 + CONSOLE_COUNT) &&
+	    ((mods & KM_CTRL) == 0)) {
+		cons_switch(&consoles[key - KC_F1]);
+	} else {
+		/* Got key press/release event */
+		kbd_event_t *event =
+		    (kbd_event_t *) malloc(sizeof(kbd_event_t));
+		if (event == NULL) {
+			return ENOMEM;
+		}
+		
+		link_initialize(&event->link);
+		event->type = type;
+		event->key = key;
+		event->mods = mods;
+		event->c = c;
+		
+		/*
+		 * Kernel console does not read events
+		 * from us, so we will redirect them
+		 * to the (last) active userspace console
+		 * if necessary.
+		 */
+		console_t *target_console = cons_get_active_uspace();
+		
+		prodcons_produce(&target_console->input_pc,
+		    &event->link);
+	}
+	
+	return EOK;
+}
+
+static int input_ev_move(input_t *input, int dx, int dy)
+{
+	return EOK;
+}
+
+static int input_ev_abs_move(input_t *input, unsigned x , unsigned y,
+    unsigned max_x, unsigned max_y)
+{
+	return EOK;
+}
+
+static int input_ev_button(input_t *input, int bnum, int bpress)
+{
+	return EOK;
 }
 
@@ -293,8 +319,8 @@
 }
 
-static void cons_set_cursor(console_t *cons, sysarg_t col, sysarg_t row)
-{
-	fibril_mutex_lock(&cons->mtx);
-	chargrid_set_cursor(cons->frontbuf, col, row);
+static void cons_set_cursor_vis(console_t *cons, bool visible)
+{
+	fibril_mutex_lock(&cons->mtx);
+	chargrid_set_cursor_visibility(cons->frontbuf, visible);
 	fibril_mutex_unlock(&cons->mtx);
 	
@@ -302,61 +328,18 @@
 }
 
-static void cons_set_cursor_visibility(console_t *cons, bool visible)
-{
-	fibril_mutex_lock(&cons->mtx);
-	chargrid_set_cursor_visibility(cons->frontbuf, visible);
-	fibril_mutex_unlock(&cons->mtx);
-	
-	cons_update_cursor(cons);
-}
-
-static void cons_get_cursor(console_t *cons, ipc_callid_t iid, ipc_call_t *icall)
-{
-	sysarg_t col;
-	sysarg_t row;
-	
-	fibril_mutex_lock(&cons->mtx);
-	chargrid_get_cursor(cons->frontbuf, &col, &row);
-	fibril_mutex_unlock(&cons->mtx);
-	
-	async_answer_2(iid, EOK, col, row);
-}
-
-static void cons_write(console_t *cons, ipc_callid_t iid, ipc_call_t *icall)
-{
-	void *buf;
-	size_t size;
-	int rc = async_data_write_accept(&buf, false, 0, 0, 0, &size);
-	
-	if (rc != EOK) {
-		async_answer_0(iid, rc);
-		return;
-	}
-	
-	size_t off = 0;
-	while (off < size)
-		cons_write_char(cons, str_decode(buf, &off, size));
-	
-	async_answer_1(iid, EOK, size);
-	free(buf);
-}
-
-static void cons_read(console_t *cons, ipc_callid_t iid, ipc_call_t *icall)
-{
-	ipc_callid_t callid;
-	size_t size;
-	if (!async_data_read_receive(&callid, &size)) {
-		async_answer_0(callid, EINVAL);
-		async_answer_0(iid, EINVAL);
-		return;
-	}
-	
-	char *buf = (char *) malloc(size);
-	if (buf == NULL) {
-		async_answer_0(callid, ENOMEM);
-		async_answer_0(iid, ENOMEM);
-		return;
-	}
-	
+static int cons_open(con_srvs_t *srvs, con_srv_t *srv)
+{
+	return EOK;
+}
+
+static int cons_close(con_srv_t *srv)
+{
+	return EOK;
+}
+
+static int cons_read(con_srv_t *srv, void *buf, size_t size)
+{
+	uint8_t *bbuf = buf;
+	console_t *cons = srv_to_console(srv);
 	size_t pos = 0;
 	
@@ -369,5 +352,5 @@
 		/* Copy to the buffer remaining characters. */
 		while ((pos < size) && (cons->char_remains_len > 0)) {
-			buf[pos] = cons->char_remains[0];
+			bbuf[pos] = cons->char_remains[0];
 			pos++;
 			
@@ -394,12 +377,85 @@
 		}
 	}
-	
-	(void) async_data_read_finalize(callid, buf, size);
-	async_answer_1(iid, EOK, size);
-	free(buf);
-}
-
-static void cons_set_style(console_t *cons, console_style_t style)
-{
+
+	return size;
+}
+
+static int cons_write(con_srv_t *srv, void *data, size_t size)
+{
+	console_t *cons = srv_to_console(srv);
+
+	size_t off = 0;
+	while (off < size)
+		cons_write_char(cons, str_decode(data, &off, size));
+	return size;
+}
+
+static void cons_sync(con_srv_t *srv)
+{
+	console_t *cons = srv_to_console(srv);
+	
+	cons_update(cons);
+}
+
+static void cons_clear(con_srv_t *srv)
+{
+	console_t *cons = srv_to_console(srv);
+	
+	fibril_mutex_lock(&cons->mtx);
+	chargrid_clear(cons->frontbuf);
+	fibril_mutex_unlock(&cons->mtx);
+	
+	cons_update(cons);
+}
+
+static void cons_set_pos(con_srv_t *srv, sysarg_t col, sysarg_t row)
+{
+	console_t *cons = srv_to_console(srv);
+	
+	fibril_mutex_lock(&cons->mtx);
+	chargrid_set_cursor(cons->frontbuf, col, row);
+	fibril_mutex_unlock(&cons->mtx);
+	
+	cons_update_cursor(cons);
+}
+
+static int cons_get_pos(con_srv_t *srv, sysarg_t *col, sysarg_t *row)
+{
+	console_t *cons = srv_to_console(srv);
+	
+	fibril_mutex_lock(&cons->mtx);
+	chargrid_get_cursor(cons->frontbuf, col, row);
+	fibril_mutex_unlock(&cons->mtx);
+	
+	return EOK;
+}
+
+static int cons_get_size(con_srv_t *srv, sysarg_t *cols, sysarg_t *rows)
+{
+	console_t *cons = srv_to_console(srv);
+	
+	fibril_mutex_lock(&cons->mtx);
+	*cols = cons->cols;
+	*rows = cons->rows;
+	fibril_mutex_unlock(&cons->mtx);
+	
+	return EOK;
+}
+
+static int cons_get_color_cap(con_srv_t *srv, console_caps_t *ccaps)
+{
+	console_t *cons = srv_to_console(srv);
+	
+	fibril_mutex_lock(&cons->mtx);
+	*ccaps = cons->ccaps;
+	fibril_mutex_unlock(&cons->mtx);
+	
+	return EOK;
+}
+
+static void cons_set_style(con_srv_t *srv, console_style_t style)
+{
+	console_t *cons = srv_to_console(srv);
+	
 	fibril_mutex_lock(&cons->mtx);
 	chargrid_set_style(cons->frontbuf, style);
@@ -407,7 +463,9 @@
 }
 
-static void cons_set_color(console_t *cons, console_color_t bgcolor,
+static void cons_set_color(con_srv_t *srv, console_color_t bgcolor,
     console_color_t fgcolor, console_color_attr_t attr)
 {
+	console_t *cons = srv_to_console(srv);
+	
 	fibril_mutex_lock(&cons->mtx);
 	chargrid_set_color(cons->frontbuf, bgcolor, fgcolor, attr);
@@ -415,7 +473,9 @@
 }
 
-static void cons_set_rgb_color(console_t *cons, pixel_t bgcolor,
+static void cons_set_rgb_color(con_srv_t *srv, pixel_t bgcolor,
     pixel_t fgcolor)
 {
+	console_t *cons = srv_to_console(srv);
+	
 	fibril_mutex_lock(&cons->mtx);
 	chargrid_set_rgb_color(cons->frontbuf, bgcolor, fgcolor);
@@ -423,11 +483,20 @@
 }
 
-static void cons_get_event(console_t *cons, ipc_callid_t iid, ipc_call_t *icall)
-{
+static void cons_set_cursor_visibility(con_srv_t *srv, bool visible)
+{
+	console_t *cons = srv_to_console(srv);
+	
+	cons_set_cursor_vis(cons, visible);
+}
+
+static int cons_get_event(con_srv_t *srv, kbd_event_t *event)
+{
+	console_t *cons = srv_to_console(srv);
 	link_t *link = prodcons_consume(&cons->input_pc);
-	kbd_event_t *event = list_get_instance(link, kbd_event_t, link);
-	
-	async_answer_4(iid, EOK, event->type, event->key, event->mods, event->c);
-	free(event);
+	kbd_event_t *kevent = list_get_instance(link, kbd_event_t, link);
+	
+	*event = *kevent;
+	free(kevent);
+	return EOK;
 }
 
@@ -452,71 +521,11 @@
 	
 	if (atomic_postinc(&cons->refcnt) == 0)
-		cons_set_cursor_visibility(cons, true);
-	
-	/* Accept the connection */
-	async_answer_0(iid, EOK);
-	
-	while (true) {
-		ipc_call_t call;
-		ipc_callid_t callid = async_get_call(&call);
-		
-		if (!IPC_GET_IMETHOD(call))
-			return;
-		
-		switch (IPC_GET_IMETHOD(call)) {
-		case VFS_OUT_READ:
-			cons_read(cons, callid, &call);
-			break;
-		case VFS_OUT_WRITE:
-			cons_write(cons, callid, &call);
-			break;
-		case VFS_OUT_SYNC:
-			cons_update(cons);
-			async_answer_0(callid, EOK);
-			break;
-		case CONSOLE_CLEAR:
-			cons_clear(cons);
-			async_answer_0(callid, EOK);
-			break;
-		case CONSOLE_GOTO:
-			cons_set_cursor(cons, IPC_GET_ARG1(call), IPC_GET_ARG2(call));
-			async_answer_0(callid, EOK);
-			break;
-		case CONSOLE_GET_POS:
-			cons_get_cursor(cons, callid, &call);
-			break;
-		case CONSOLE_GET_SIZE:
-			async_answer_2(callid, EOK, cons->cols, cons->rows);
-			break;
-		case CONSOLE_GET_COLOR_CAP:
-			async_answer_1(callid, EOK, cons->ccaps);
-			break;
-		case CONSOLE_SET_STYLE:
-			cons_set_style(cons, IPC_GET_ARG1(call));
-			async_answer_0(callid, EOK);
-			break;
-		case CONSOLE_SET_COLOR:
-			cons_set_color(cons, IPC_GET_ARG1(call), IPC_GET_ARG2(call),
-			    IPC_GET_ARG3(call));
-			async_answer_0(callid, EOK);
-			break;
-		case CONSOLE_SET_RGB_COLOR:
-			cons_set_rgb_color(cons, IPC_GET_ARG1(call), IPC_GET_ARG2(call));
-			async_answer_0(callid, EOK);
-			break;
-		case CONSOLE_CURSOR_VISIBILITY:
-			cons_set_cursor_visibility(cons, IPC_GET_ARG1(call));
-			async_answer_0(callid, EOK);
-			break;
-		case CONSOLE_GET_EVENT:
-			cons_get_event(cons, callid, &call);
-			break;
-		default:
-			async_answer_0(callid, EINVAL);
-		}
-	}
-}
-
-static async_sess_t *input_connect(const char *svc)
+		cons_set_cursor_vis(cons, true);
+	
+	con_conn(iid, icall, &cons->srvs);
+}
+
+
+static int input_connect(const char *svc)
 {
 	async_sess_t *sess;
@@ -524,26 +533,25 @@
 	
 	int rc = loc_service_get_id(svc, &dsid, 0);
-	if (rc == EOK) {
-		sess = loc_service_connect(EXCHANGE_ATOMIC, dsid, 0);
-		if (sess == NULL) {
-			printf("%s: Unable to connect to input service %s\n", NAME,
-			    svc);
-			return NULL;
-		}
-	} else
-		return NULL;
-	
-	async_exch_t *exch = async_exchange_begin(sess);
-	rc = async_connect_to_me(exch, 0, 0, 0, input_events, NULL);
-	async_exchange_end(exch);
-	
+	if (rc != EOK) {
+		printf("%s: Input service %s not found\n", NAME, svc);
+		return rc;
+	}
+
+	sess = loc_service_connect(EXCHANGE_ATOMIC, dsid, 0);
+	if (sess == NULL) {
+		printf("%s: Unable to connect to input service %s\n", NAME,
+		    svc);
+		return EIO;
+	}
+	
+	rc = input_open(sess, &input_ev_ops, NULL, &input);
 	if (rc != EOK) {
 		async_hangup(sess);
-		printf("%s: Unable to create callback connection to service %s (%s)\n",
+		printf("%s: Unable to communicate with service %s (%s)\n",
 		    NAME, svc, str_error(rc));
-		return NULL;
-	}
-	
-	return sess;
+		return rc;
+	}
+	
+	return EOK;
 }
 
@@ -574,7 +582,9 @@
 static bool console_srv_init(char *input_svc, char *output_svc)
 {
+	int rc;
+	
 	/* Connect to input service */
-	input_sess = input_connect(input_svc);
-	if (input_sess == NULL)
+	rc = input_connect(input_svc);
+	if (rc != EOK)
 		return false;
 	
@@ -586,5 +596,5 @@
 	/* Register server */
 	async_set_client_connection(client_connection);
-	int rc = loc_server_register(NAME);
+	rc = loc_server_register(NAME);
 	if (rc != EOK) {
 		printf("%s: Unable to register server (%s)\n", NAME,
@@ -628,4 +638,8 @@
 		}
 		
+		con_srvs_init(&consoles[i].srvs);
+		consoles[i].srvs.ops = &con_ops;
+		consoles[i].srvs.sarg = &consoles[i];
+		
 		char vc[LOC_NAME_MAXLEN + 1];
 		snprintf(vc, LOC_NAME_MAXLEN, "%s/vc%zu", NAMESPACE, i);
Index: uspace/srv/hid/remcons/remcons.c
===================================================================
--- uspace/srv/hid/remcons/remcons.c	(revision 131d9a4ae105fe5f519d8dbbfda588ef5358a648)
+++ uspace/srv/hid/remcons/remcons.c	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -34,10 +34,8 @@
 
 #include <async.h>
+#include <errno.h>
+#include <io/con_srv.h>
 #include <stdio.h>
-#include <adt/prodcons.h>
-#include <ipc/input.h>
-#include <ipc/console.h>
-#include <ipc/vfs.h>
-#include <errno.h>
+#include <stdlib.h>
 #include <str_error.h>
 #include <loc.h>
@@ -45,6 +43,4 @@
 #include <io/keycode.h>
 #include <align.h>
-#include <malloc.h>
-#include <as.h>
 #include <fibril_synch.h>
 #include <task.h>
@@ -75,116 +71,131 @@
     sizeof(telnet_force_character_mode_command) / sizeof(telnet_cmd_t);
 
-
-/** Handling client requests (VFS and console interface).
- *
- * @param user Telnet user the requests belong to.
- */
-static void client_connection_message_loop(telnet_user_t *user)
-{
-	while (true) {
-		ipc_call_t call;
-		ipc_callid_t callid = 0;
-
-		/*
-		 * The getterm task might terminate while we are here,
-		 * waiting for a call. Also, the socket might be closed
-		 * meanwhile.
-		 * We want to detect this situation early, so we use a
-		 * timeout variant of async_get_call().
-		 */
-		while (callid == 0) {
-			callid = async_get_call_timeout(&call, 1000);
-
-			if (telnet_user_is_zombie(user)) {
-				if (callid != 0) {
-					async_answer_0(callid, EINTR);
-				}
-				return;
-			}
-		}
-		
-		if (!IPC_GET_IMETHOD(call)) {
-			return;
-		}
-
-		switch (IPC_GET_IMETHOD(call)) {
-		case CONSOLE_GET_SIZE:
-			async_answer_2(callid, EOK, 100, 1);
-			break;
-		case CONSOLE_GET_POS:
-			fibril_mutex_lock(&user->guard);
-			async_answer_2(callid, EOK, user->cursor_x, 0);
-			fibril_mutex_unlock(&user->guard);
-			break;
-		case CONSOLE_GET_EVENT: {
-			kbd_event_t event;
-			int rc = telnet_user_get_next_keyboard_event(user, &event);
-			if (rc != EOK) {
-				/* Silently ignore. */
-				async_answer_0(callid, EOK);
-				break;
-			}
-			async_answer_4(callid, EOK, event.type, event.key, event.mods, event.c);
-			break;
-		}
-		case CONSOLE_GOTO: {
-			int new_x = IPC_GET_ARG1(call);
-			telnet_user_update_cursor_x(user, new_x);
-			async_answer_0(callid, ENOTSUP);
-			break;
-		}
-		case VFS_OUT_READ:
-			async_answer_0(callid, ENOTSUP);
-			break;
-		case VFS_OUT_WRITE: {
-			uint8_t *buf;
-			size_t size;
-			int rc = async_data_write_accept((void **)&buf, false, 0, 0, 0, &size);
-
-			if (rc != EOK) {
-				async_answer_0(callid, rc);
-				break;
-			}
-
-			rc = telnet_user_send_data(user, buf, size);
-			free(buf);
-
-			if (rc != EOK) {
-				async_answer_0(callid, rc);
-				break;
-			}
-
-			async_answer_1(callid, EOK, size);
-			break;
-		}
-		case VFS_OUT_SYNC:
-			async_answer_0(callid, EOK);
-			break;
-		case CONSOLE_CLEAR:
-			async_answer_0(callid, EOK);
-			break;
-
-		case CONSOLE_GET_COLOR_CAP:
-			async_answer_1(callid, EOK, CONSOLE_CAP_NONE);
-			break;
-		case CONSOLE_SET_STYLE:
-			async_answer_0(callid, ENOTSUP);
-			break;
-		case CONSOLE_SET_COLOR:
-			async_answer_0(callid, ENOTSUP);
-			break;
-		case CONSOLE_SET_RGB_COLOR:
-			async_answer_0(callid, ENOTSUP);
-			break;
-
-		case CONSOLE_CURSOR_VISIBILITY:
-			async_answer_0(callid, ENOTSUP);
-			break;
-
-		default:
-			async_answer_0(callid, EINVAL);
-			break;
-		}
-	}
+static int remcons_open(con_srvs_t *, con_srv_t *);
+static int remcons_close(con_srv_t *);
+static int remcons_write(con_srv_t *, void *, size_t);
+static void remcons_sync(con_srv_t *);
+static void remcons_clear(con_srv_t *);
+static void remcons_set_pos(con_srv_t *, sysarg_t col, sysarg_t row);
+static int remcons_get_pos(con_srv_t *, sysarg_t *, sysarg_t *);
+static int remcons_get_size(con_srv_t *, sysarg_t *, sysarg_t *);
+static int remcons_get_color_cap(con_srv_t *, console_caps_t *);
+static int remcons_get_event(con_srv_t *, kbd_event_t *);
+
+static con_ops_t con_ops = {
+	.open = remcons_open,
+	.close = remcons_close,
+	.read = NULL,
+	.write = remcons_write,
+	.sync = remcons_sync,
+	.clear = remcons_clear,
+	.set_pos = remcons_set_pos,
+	.get_pos = remcons_get_pos,
+	.get_size = remcons_get_size,
+	.get_color_cap = remcons_get_color_cap,
+	.set_style = NULL,
+	.set_color = NULL,
+	.set_rgb_color = NULL,
+	.set_cursor_visibility = NULL,
+	.get_event = remcons_get_event
+};
+
+static telnet_user_t *srv_to_user(con_srv_t *srv)
+{
+	return srv->srvs->sarg;
+}
+
+static int remcons_open(con_srvs_t *srvs, con_srv_t *srv)
+{
+	telnet_user_t *user = srv_to_user(srv);
+
+	telnet_user_log(user, "New client connected (%p).", srv);
+
+	/* Force character mode. */
+	send(user->socket, (void *)telnet_force_character_mode_command,
+	    telnet_force_character_mode_command_count, 0);
+
+	return EOK;
+}
+
+static int remcons_close(con_srv_t *srv)
+{
+	telnet_user_t *user = srv_to_user(srv);
+
+	telnet_user_notify_client_disconnected(user);
+	telnet_user_log(user, "Client disconnected (%p).", srv);
+
+	return EOK;
+}
+
+static int remcons_write(con_srv_t *srv, void *data, size_t size)
+{
+	telnet_user_t *user = srv_to_user(srv);
+	int rc;
+
+	rc = telnet_user_send_data(user, data, size);
+	if (rc != EOK)
+		return rc;
+
+	return size;
+}
+
+static void remcons_sync(con_srv_t *srv)
+{
+	(void) srv;
+}
+
+static void remcons_clear(con_srv_t *srv)
+{
+	(void) srv;
+}
+
+static void remcons_set_pos(con_srv_t *srv, sysarg_t col, sysarg_t row)
+{
+	telnet_user_t *user = srv_to_user(srv);
+
+	telnet_user_update_cursor_x(user, col);
+}
+
+static int remcons_get_pos(con_srv_t *srv, sysarg_t *col, sysarg_t *row)
+{
+	telnet_user_t *user = srv_to_user(srv);
+
+	*col = user->cursor_x;
+	*row = 0;
+
+	return EOK;
+}
+
+static int remcons_get_size(con_srv_t *srv, sysarg_t *cols, sysarg_t *rows)
+{
+	(void) srv;
+
+	*cols = 100;
+	*rows = 1;
+
+	return EOK;
+}
+
+static int remcons_get_color_cap(con_srv_t *srv, console_caps_t *ccaps)
+{
+	(void) srv;
+	*ccaps = CONSOLE_CAP_NONE;
+
+	return EOK;
+}
+
+static int remcons_get_event(con_srv_t *srv, kbd_event_t *event)
+{
+	telnet_user_t *user = srv_to_user(srv);
+	int rc;
+
+	rc = telnet_user_get_next_keyboard_event(user, event);
+	if (rc != EOK) {
+		/* XXX What? */
+		memset(event, 0, sizeof(*event));
+		return EOK;
+	}
+
+	return EOK;
 }
 
@@ -198,17 +209,7 @@
 		return;
 	}
-	async_answer_0(iid, EOK);
-
-	telnet_user_log(user, "New client connected (%" PRIxn").", iid);
-
-	/* Force character mode. */
-	send(user->socket, (void *)telnet_force_character_mode_command,
-	    telnet_force_character_mode_command_count, 0);
 
 	/* Handle messages. */
-	client_connection_message_loop(user);
-
-	telnet_user_notify_client_disconnected(user);
-	telnet_user_log(user, "Client disconnected (%" PRIxn").", iid);
+	con_conn(iid, icall, &user->srvs);
 }
 
@@ -232,4 +233,5 @@
 		fibril_mutex_lock(&user->guard);
 		user->task_finished = true;
+		user->srvs.aborted = true;
 		fibril_condvar_signal(&user->refcount_cv);
 		fibril_mutex_unlock(&user->guard);
@@ -251,4 +253,5 @@
 	fibril_mutex_lock(&user->guard);
 	user->task_finished = true;
+	user->srvs.aborted = true;
 	fibril_condvar_signal(&user->refcount_cv);
 	fibril_mutex_unlock(&user->guard);
@@ -295,4 +298,5 @@
 			closesocket(user->socket);
 			user->socket_closed = true;
+			user->srvs.aborted = true;
 			continue;
 		} else if (user->socket_closed) {
@@ -380,4 +384,11 @@
 		assert(user);
 
+		con_srvs_init(&user->srvs);
+		user->srvs.ops = &con_ops;
+		user->srvs.sarg = user;
+		user->srvs.abort_timeout = 1000;
+
+		telnet_user_add(user);
+
 		fid_t fid = fibril_create(network_user_fibril, user);
 		assert(fid);
Index: uspace/srv/hid/remcons/user.c
===================================================================
--- uspace/srv/hid/remcons/user.c	(revision 131d9a4ae105fe5f519d8dbbfda588ef5358a648)
+++ uspace/srv/hid/remcons/user.c	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -35,7 +35,4 @@
 #include <stdio.h>
 #include <adt/prodcons.h>
-#include <ipc/input.h>
-#include <ipc/console.h>
-#include <ipc/vfs.h>
 #include <errno.h>
 #include <str_error.h>
@@ -95,12 +92,14 @@
 	user->locsrv_connection_count = 0;
 
-
+	user->cursor_x = 0;
+
+	return user;
+}
+
+void telnet_user_add(telnet_user_t *user)
+{
 	fibril_mutex_lock(&users_guard);
 	list_append(&user->link, &users);
 	fibril_mutex_unlock(&users_guard);
-
-	user->cursor_x = 0;
-
-	return user;
 }
 
@@ -199,4 +198,5 @@
 		if ((recv_length == 0) || (recv_length == ENOTCONN)) {
 			user->socket_closed = true;
+			user->srvs.aborted = true;
 			return ENOENT;
 		}
Index: uspace/srv/hid/remcons/user.h
===================================================================
--- uspace/srv/hid/remcons/user.h	(revision 131d9a4ae105fe5f519d8dbbfda588ef5358a648)
+++ uspace/srv/hid/remcons/user.h	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -36,6 +36,8 @@
 #define TELNET_USER_H_
 
+#include <adt/prodcons.h>
 #include <fibril_synch.h>
 #include <inttypes.h>
+#include <io/con_srv.h>
 #include "remcons.h"
 
@@ -55,4 +57,6 @@
 	/** Path name of the service. */
 	char *service_name;
+	/** Console service setup */
+	con_srvs_t srvs;
 
 	/** Producer-consumer of kbd_event_t. */
@@ -77,4 +81,5 @@
 
 extern telnet_user_t *telnet_user_create(int);
+extern void telnet_user_add(telnet_user_t *);
 extern void telnet_user_destroy(telnet_user_t *);
 extern telnet_user_t *telnet_user_get_for_client_connection(service_id_t);
Index: uspace/srv/net/ethip/pdu.c
===================================================================
--- uspace/srv/net/ethip/pdu.c	(revision 131d9a4ae105fe5f519d8dbbfda588ef5358a648)
+++ uspace/srv/net/ethip/pdu.c	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -69,6 +69,7 @@
 	    frame->size);
 
-	log_msg(LOG_DEFAULT, LVL_DEBUG, "Encoding Ethernet frame src=%llx dest=%llx etype=%x",
-	    frame->src, frame->dest, frame->etype_len);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "Encoding Ethernet frame "
+	    "src=%" PRIx64 " dest=%" PRIx64 " etype=%x",
+	    frame->src.addr, frame->dest.addr, frame->etype_len);
 	log_msg(LOG_DEFAULT, LVL_DEBUG, "Encoded Ethernet frame (%zu bytes)", size);
 
@@ -104,6 +105,7 @@
 	    frame->size);
 
-	log_msg(LOG_DEFAULT, LVL_DEBUG, "Decoding Ethernet frame src=%llx dest=%llx etype=%x",
-	    frame->src, frame->dest, frame->etype_len);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "Decoding Ethernet frame "
+	    "src=%" PRIx64 " dest=%" PRIx64 " etype=%x",
+	    frame->src.addr, frame->dest.addr, frame->etype_len);
 	log_msg(LOG_DEFAULT, LVL_DEBUG, "Decoded Ethernet frame payload (%zu bytes)", frame->size);
 
Index: uspace/srv/net/tcp/conn.c
===================================================================
--- uspace/srv/net/tcp/conn.c	(revision 131d9a4ae105fe5f519d8dbbfda588ef5358a648)
+++ uspace/srv/net/tcp/conn.c	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -999,6 +999,6 @@
 	} else {
 		log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: Nothing left in segment, dropping "
-		    "(xfer_size=%zu, SEG.LEN=%zu, seg->ctrl=%u)",
-		    conn->name, xfer_size, seg->len, (unsigned)seg->ctrl);
+		    "(xfer_size=%zu, SEG.LEN=%" PRIu32 ", seg->ctrl=%u)",
+		    conn->name, xfer_size, seg->len, (unsigned int) seg->ctrl);
 		/* Nothing left in segment */
 		tcp_segment_delete(seg);
@@ -1146,5 +1146,5 @@
 void tcp_conn_segment_arrived(tcp_conn_t *conn, tcp_segment_t *seg)
 {
-	log_msg(LOG_DEFAULT, LVL_DEBUG, "%c: tcp_conn_segment_arrived(%p)",
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: tcp_conn_segment_arrived(%p)",
 	    conn->name, seg);
 
Index: uspace/srv/net/tcp/segment.c
===================================================================
--- uspace/srv/net/tcp/segment.c	(revision 131d9a4ae105fe5f519d8dbbfda588ef5358a648)
+++ uspace/srv/net/tcp/segment.c	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -250,9 +250,9 @@
 	log_msg(LOG_DEFAULT, LVL_DEBUG2, "Segment dump:");
 	log_msg(LOG_DEFAULT, LVL_DEBUG2, " - ctrl = %u", (unsigned)seg->ctrl);
-	log_msg(LOG_DEFAULT, LVL_DEBUG2, " - seq = % " PRIu32, seg->seq);
-	log_msg(LOG_DEFAULT, LVL_DEBUG2, " - ack = % " PRIu32, seg->ack);
-	log_msg(LOG_DEFAULT, LVL_DEBUG2, " - len = % " PRIu32, seg->len);
-	log_msg(LOG_DEFAULT, LVL_DEBUG2, " - wnd = % " PRIu32, seg->wnd);
-	log_msg(LOG_DEFAULT, LVL_DEBUG2, " - up = % " PRIu32, seg->up);
+	log_msg(LOG_DEFAULT, LVL_DEBUG2, " - seq = %" PRIu32, seg->seq);
+	log_msg(LOG_DEFAULT, LVL_DEBUG2, " - ack = %" PRIu32, seg->ack);
+	log_msg(LOG_DEFAULT, LVL_DEBUG2, " - len = %" PRIu32, seg->len);
+	log_msg(LOG_DEFAULT, LVL_DEBUG2, " - wnd = %" PRIu32, seg->wnd);
+	log_msg(LOG_DEFAULT, LVL_DEBUG2, " - up = %" PRIu32, seg->up);
 }
 
Index: uspace/srv/net/tcp/sock.c
===================================================================
--- uspace/srv/net/tcp/sock.c	(revision 131d9a4ae105fe5f519d8dbbfda588ef5358a648)
+++ uspace/srv/net/tcp/sock.c	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -114,5 +114,5 @@
 	*rsock = NULL;
 
-	sock = calloc(sizeof(tcp_sockdata_t), 1);
+	sock = calloc(1, sizeof(tcp_sockdata_t));
 	if (sock == NULL)
 		return ENOMEM;
@@ -277,5 +277,5 @@
 
 	socket->backlog = backlog;
-	socket->lconn = calloc(sizeof(tcp_conn_t *), backlog);
+	socket->lconn = calloc(backlog, sizeof(tcp_conn_t *));
 	if (socket->lconn == NULL) {
 		fibril_mutex_unlock(&socket->lock);
@@ -293,5 +293,5 @@
 	for (i = 0; i < backlog; i++) {
 
-		lconn = calloc(sizeof(tcp_sock_lconn_t), 1);
+		lconn = calloc(1, sizeof(tcp_sock_lconn_t));
 		if (lconn == NULL) {
 			/* XXX Clean up */
Index: uspace/srv/net/tcp/tqueue.c
===================================================================
--- uspace/srv/net/tcp/tqueue.c	(revision 131d9a4ae105fe5f519d8dbbfda588ef5358a648)
+++ uspace/srv/net/tcp/tqueue.c	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -172,5 +172,5 @@
 
 	xfer_seqlen = min(snd_buf_seqlen, avail_wnd);
-	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: snd_buf_seqlen = %zu, SND.WND = %zu, "
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: snd_buf_seqlen = %zu, SND.WND = %" PRIu32 ", "
 	    "xfer_seqlen = %zu", conn->name, snd_buf_seqlen, conn->snd_wnd,
 	    xfer_seqlen);
Index: uspace/srv/net/udp/sock.c
===================================================================
--- uspace/srv/net/udp/sock.c	(revision 131d9a4ae105fe5f519d8dbbfda588ef5358a648)
+++ uspace/srv/net/udp/sock.c	(revision 702536882b248833b02d3693809a7bb0f21bcbd1)
@@ -104,5 +104,5 @@
 
 	log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_socket()");
-	sock = calloc(sizeof(udp_sockdata_t), 1);
+	sock = calloc(1, sizeof(udp_sockdata_t));
 	if (sock == NULL) {
 		async_answer_0(callid, ENOMEM);
