Index: boot/Makefile.common
===================================================================
--- boot/Makefile.common	(revision 40d4c1d4873553b574cf552692c01791d56f1689)
+++ boot/Makefile.common	(revision 234e39e658dc0c08fdabeeb8bbb0f20fee1eb942)
@@ -60,4 +60,5 @@
 	$(USPACEDIR)/app/getterm/getterm \
 	$(USPACEDIR)/app/klog/klog \
+	$(USPACEDIR)/app/mkfat/mkfat \
 	$(USPACEDIR)/app/redir/redir \
 	$(USPACEDIR)/app/tester/tester \
Index: tools/mkfat.py
===================================================================
--- tools/mkfat.py	(revision 40d4c1d4873553b574cf552692c01791d56f1689)
+++ tools/mkfat.py	(revision 234e39e658dc0c08fdabeeb8bbb0f20fee1eb942)
@@ -354,5 +354,5 @@
 		return
 	
-	fat16_clusters = 4096
+	fat16_clusters = 8192
 	
 	sector_size = 512
Index: uspace/Makefile
===================================================================
--- uspace/Makefile	(revision 40d4c1d4873553b574cf552692c01791d56f1689)
+++ uspace/Makefile	(revision 234e39e658dc0c08fdabeeb8bbb0f20fee1eb942)
@@ -38,4 +38,5 @@
 	app/init \
 	app/klog \
+	app/mkfat \
 	app/redir \
 	app/tester \
Index: uspace/app/bdsh/Makefile.build
===================================================================
--- uspace/app/bdsh/Makefile.build	(revision 40d4c1d4873553b574cf552692c01791d56f1689)
+++ uspace/app/bdsh/Makefile.build	(revision 234e39e658dc0c08fdabeeb8bbb0f20fee1eb942)
@@ -42,4 +42,5 @@
 	cmds/modules/help/help.c \
 	cmds/modules/mkdir/mkdir.c \
+	cmds/modules/mkfile/mkfile.c \
 	cmds/modules/rm/rm.c \
 	cmds/modules/bdd/bdd.c \
Index: uspace/app/bdsh/cmds/modules/mkfile/entry.h
===================================================================
--- uspace/app/bdsh/cmds/modules/mkfile/entry.h	(revision 234e39e658dc0c08fdabeeb8bbb0f20fee1eb942)
+++ uspace/app/bdsh/cmds/modules/mkfile/entry.h	(revision 234e39e658dc0c08fdabeeb8bbb0f20fee1eb942)
@@ -0,0 +1,9 @@
+#ifndef MKFILE_ENTRY_H
+#define MKFILE_ENTRY_H
+
+/* Entry points for the mkfile command */
+extern int cmd_mkfile(char **);
+extern void help_cmd_mkfile(unsigned int);
+
+#endif /* MKFILE_ENTRY_H */
+
Index: uspace/app/bdsh/cmds/modules/mkfile/mkfile.c
===================================================================
--- uspace/app/bdsh/cmds/modules/mkfile/mkfile.c	(revision 234e39e658dc0c08fdabeeb8bbb0f20fee1eb942)
+++ uspace/app/bdsh/cmds/modules/mkfile/mkfile.c	(revision 234e39e658dc0c08fdabeeb8bbb0f20fee1eb942)
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2009 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.
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <macros.h>
+#include <getopt.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "config.h"
+#include "errors.h"
+#include "util.h"
+#include "entry.h"
+#include "mkfile.h"
+#include "cmds.h"
+
+/** Number of bytes to write at a time */
+#define BUFFER_SIZE 16384
+
+static char *cmdname = "mkfile";
+
+static struct option const long_options[] = {
+	{"size", required_argument, 0, 's'},
+	{"help", no_argument, 0, 'h'},
+	{0, 0, 0, 0}
+};
+
+void help_cmd_mkfile(unsigned int level)
+{
+	if (level == HELP_SHORT) {
+		printf("`%s' creates a new zero-filled file\n", cmdname);
+	} else {
+		help_cmd_mkfile(HELP_SHORT);
+		printf(
+		"Usage:  %s [options] <path>\n"
+		"Options:\n"
+		"  -h, --help       A short option summary\n"
+		"  -s, --size sz    Size of the file\n"
+		"\n"
+		"Size is a number followed by 'k', 'm' or 'g' for kB, MB, GB.\n"
+		"E.g. 100k, 2m, 1g.\n",
+		cmdname);
+	}
+
+	return;
+}
+
+/** Parse size specification.
+ *
+ * Size specification is in the form <decimal_number><unit> where
+ * <unit> is 'k', 'm' or 'g' for kB, MB, GB.
+ *
+ * @param str	String containing the size specification.
+ * @return	Non-negative size in bytes on success, -1 on failure.
+ */
+static ssize_t read_size(const char *str)
+{
+	ssize_t number, unit;
+	char *ep;
+
+	number = strtol(str, &ep, 10);
+	if (ep[0] == '\0')
+		return number;
+
+	if (ep[1] != '\0')
+		    return -1;
+
+	switch (tolower(ep[0])) {
+	case 'k': unit = 1024; break;
+	case 'm': unit = 1024*1024; break;
+	case 'g': unit = 1024*1024*1024; break;
+	default: return -1;
+	}
+
+	return number * unit;
+}
+
+int cmd_mkfile(char **argv)
+{
+	unsigned int argc;
+	int c, opt_ind;
+	int fd;
+	ssize_t file_size;
+	ssize_t total_written;
+	ssize_t to_write, rc;
+	char *file_name;
+	void *buffer;
+
+	file_size = 0;
+
+	argc = cli_count_args(argv);
+
+	for (c = 0, optind = 0, opt_ind = 0; c != -1;) {
+		c = getopt_long(argc, argv, "pvhVfm:", long_options, &opt_ind);
+		switch (c) {
+		case 'h':
+			help_cmd_mkfile(HELP_LONG);
+			return CMD_SUCCESS;
+		case 's':
+			file_size = read_size(optarg);
+			if (file_size < 0) {
+				printf("%s: Invalid file size specification.\n",
+				    cmdname);
+				return CMD_FAILURE;
+			}
+			break;
+		}
+	}
+
+	argc -= optind;
+
+	if (argc != 1) {
+		printf("%s: incorrect number of arguments. Try `%s --help'\n",
+			cmdname, cmdname);
+		return CMD_FAILURE;
+	}
+
+	file_name = argv[optind];
+
+	fd = open(file_name, O_CREAT | O_EXCL | O_WRONLY, 0666);
+	if (fd < 0) {
+		printf("%s: failed to create file %s.\n", cmdname, file_name);
+		return CMD_FAILURE;
+	}
+
+	buffer = calloc(BUFFER_SIZE, 1);
+	if (buffer == NULL) {
+		printf("%s: Error, out of memory.\n", cmdname);
+		return CMD_FAILURE;
+	}
+
+	total_written = 0;
+	while (total_written < file_size) {
+		to_write = min(file_size - total_written, BUFFER_SIZE);
+		rc = write(fd, buffer, to_write);
+		if (rc <= 0) {
+			printf("%s: Error writing file (%d).\n", cmdname, rc);
+			close(fd);
+			return CMD_FAILURE;
+		}
+		total_written += rc;
+	}
+
+	rc = close(fd);
+	if (rc != 0) {
+		printf("%s: Error writing file (%d).\n", cmdname, rc);
+		return CMD_FAILURE;
+	}
+
+	free(buffer);
+
+	return CMD_SUCCESS;
+}
Index: uspace/app/bdsh/cmds/modules/mkfile/mkfile.h
===================================================================
--- uspace/app/bdsh/cmds/modules/mkfile/mkfile.h	(revision 234e39e658dc0c08fdabeeb8bbb0f20fee1eb942)
+++ uspace/app/bdsh/cmds/modules/mkfile/mkfile.h	(revision 234e39e658dc0c08fdabeeb8bbb0f20fee1eb942)
@@ -0,0 +1,8 @@
+#ifndef MKFILE_H
+#define MKFILE_H
+
+/* Prototypes for the mkfile command, excluding entry points */
+
+
+#endif /* MKFILE_H */
+
Index: uspace/app/bdsh/cmds/modules/mkfile/mkfile_def.h
===================================================================
--- uspace/app/bdsh/cmds/modules/mkfile/mkfile_def.h	(revision 234e39e658dc0c08fdabeeb8bbb0f20fee1eb942)
+++ uspace/app/bdsh/cmds/modules/mkfile/mkfile_def.h	(revision 234e39e658dc0c08fdabeeb8bbb0f20fee1eb942)
@@ -0,0 +1,8 @@
+{
+	"mkfile",
+	"Create new file",
+	&cmd_mkfile,
+	&help_cmd_mkfile,
+},
+
+
Index: uspace/app/bdsh/cmds/modules/modules.h
===================================================================
--- uspace/app/bdsh/cmds/modules/modules.h	(revision 40d4c1d4873553b574cf552692c01791d56f1689)
+++ uspace/app/bdsh/cmds/modules/modules.h	(revision 234e39e658dc0c08fdabeeb8bbb0f20fee1eb942)
@@ -20,4 +20,5 @@
 #include "help/entry.h"
 #include "mkdir/entry.h"
+#include "mkfile/entry.h"
 #include "rm/entry.h"
 #include "bdd/entry.h"
@@ -39,4 +40,5 @@
 #include "help/help_def.h"
 #include "mkdir/mkdir_def.h"
+#include "mkfile/mkfile_def.h"
 #include "rm/rm_def.h"
 #include "bdd/bdd_def.h"
Index: uspace/app/mkfat/Makefile
===================================================================
--- uspace/app/mkfat/Makefile	(revision 234e39e658dc0c08fdabeeb8bbb0f20fee1eb942)
+++ uspace/app/mkfat/Makefile	(revision 234e39e658dc0c08fdabeeb8bbb0f20fee1eb942)
@@ -0,0 +1,40 @@
+#
+# Copyright (c) 2005 Martin Decky
+# Copyright (c) 2007 Jakub Jermar
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+include Makefile.common
+
+.PHONY: all clean
+
+all: $(LIBC_PREFIX)/../../../Makefile.config $(LIBC_PREFIX)/../../../config.h $(LIBC_PREFIX)/../../../config.defs $(LIBS)
+	-[ -f $(DEPEND) ] && mv -f $(DEPEND) $(DEPEND_PREV)
+	$(MAKE) -f Makefile.build PRECHECK=$(PRECHECK)
+
+clean:
+	rm -f $(DEPEND) $(DEPEND_PREV) $(JOB) $(OUTPUT) $(OUTPUT).map $(OUTPUT).disasm
+	find . -name '*.o' -follow -exec rm \{\} \;
Index: uspace/app/mkfat/Makefile.build
===================================================================
--- uspace/app/mkfat/Makefile.build	(revision 234e39e658dc0c08fdabeeb8bbb0f20fee1eb942)
+++ uspace/app/mkfat/Makefile.build	(revision 234e39e658dc0c08fdabeeb8bbb0f20fee1eb942)
@@ -0,0 +1,66 @@
+#
+# Copyright (c) 2005 Martin Decky
+# Copyright (c) 2007 Jakub Jermar
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+## Setup toolchain
+#
+
+include Makefile.common
+include $(LIBC_PREFIX)/Makefile.toolchain
+
+CFLAGS += -I$(LIBBLOCK_PREFIX)
+
+## Sources
+#
+
+SOURCES = \
+	mkfat.c
+
+OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
+
+.PHONY: all
+
+all: $(OUTPUT) $(OUTPUT).disasm
+
+-include $(DEPEND)
+
+$(OUTPUT).disasm: $(OUTPUT)
+	$(OBJDUMP) -d $< > $@
+
+$(OUTPUT): $(OBJECTS) $(LIBS)
+	$(LD) -T $(LIBC_PREFIX)/arch/$(UARCH)/_link.ld $(OBJECTS) $(LIBS) $(LFLAGS) -o $@ -Map $(OUTPUT).map
+
+%.o: %.c $(DEPEND)
+	$(CC) $(DEFS) $(CFLAGS) -c $< -o $@
+ifeq ($(PRECHECK),y)
+	$(JOBFILE) $(JOB) $< $@ cc core $(DEFS) $(CFLAGS)
+endif
+
+$(DEPEND):
+	makedepend -f - -- $(DEPEND_DEFS) $(CFLAGS) -- $(SOURCES) > $@ 2> /dev/null
+	-[ -f $(DEPEND_PREV) ] && diff -q $(DEPEND_PREV) $@ && mv -f $(DEPEND_PREV) $@
Index: uspace/app/mkfat/Makefile.common
===================================================================
--- uspace/app/mkfat/Makefile.common	(revision 234e39e658dc0c08fdabeeb8bbb0f20fee1eb942)
+++ uspace/app/mkfat/Makefile.common	(revision 234e39e658dc0c08fdabeeb8bbb0f20fee1eb942)
@@ -0,0 +1,40 @@
+#
+# Copyright (c) 2005 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.
+#
+
+
+## Common names
+#
+
+LIBC_PREFIX = ../../lib/libc
+SOFTINT_PREFIX = ../../lib/softint
+LIBBLOCK_PREFIX = ../../lib/libblock
+LIBS = $(LIBBLOCK_PREFIX)/libblock.a $(LIBC_PREFIX)/libc.a
+
+DEPEND = Makefile.depend
+DEPEND_PREV = $(DEPEND).prev
+OUTPUT = mkfat
Index: uspace/app/mkfat/fat.h
===================================================================
--- uspace/app/mkfat/fat.h	(revision 234e39e658dc0c08fdabeeb8bbb0f20fee1eb942)
+++ uspace/app/mkfat/fat.h	(revision 234e39e658dc0c08fdabeeb8bbb0f20fee1eb942)
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2008 Jakub Jermar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup fs
+ * @{
+ */
+
+#ifndef FAT_FAT_H_
+#define FAT_FAT_H_
+
+#include <sys/types.h>
+
+#define BS_BLOCK		0
+#define BS_SIZE			512
+
+#define DIRENT_SIZE		32
+
+typedef struct fat_bs {
+	uint8_t		ji[3];		/**< Jump instruction. */
+	uint8_t		oem_name[8];
+	/* BIOS Parameter Block */
+	uint16_t	bps;		/**< Bytes per sector. */
+	uint8_t		spc;		/**< Sectors per cluster. */
+	uint16_t	rscnt;		/**< Reserved sector count. */
+	uint8_t		fatcnt;		/**< Number of FATs. */
+	uint16_t	root_ent_max;	/**< Maximum number of root directory
+					     entries. */
+	uint16_t	totsec16;	/**< Total sectors. 16-bit version. */
+	uint8_t		mdesc;		/**< Media descriptor. */
+	uint16_t	sec_per_fat;	/**< Sectors per FAT12/FAT16. */
+	uint16_t	sec_per_track;	/**< Sectors per track. */
+	uint16_t	headcnt;	/**< Number of heads. */
+	uint32_t	hidden_sec;	/**< Hidden sectors. */
+	uint32_t	totsec32;	/**< Total sectors. 32-bit version. */
+
+	union {
+		struct {
+			/* FAT12/FAT16 only: Extended BIOS Parameter Block */
+			/** Physical drive number. */
+			uint8_t		pdn;
+			uint8_t		reserved;
+			/** Extended boot signature. */
+			uint8_t		ebs;
+			/** Serial number. */
+			uint32_t	id;
+			/** Volume label. */
+			uint8_t		label[11];
+			/** FAT type. */
+			uint8_t		type[8];
+			/** Boot code. */
+			uint8_t		boot_code[448];
+			/** Boot sector signature. */
+			uint16_t	signature;
+		} __attribute__ ((packed));
+		struct fat32 {
+			/* FAT32 only */
+			/** Sectors per FAT. */
+			uint32_t	sectors_per_fat;
+			/** FAT flags. */
+			uint16_t	flags;
+			/** Version. */
+			uint16_t	version;
+			/** Cluster number of root directory. */
+			uint32_t	root_cluster;
+			/** Sector number of file system information sector. */
+			uint16_t	fsinfo_sec;
+			/** Sector number of boot sector copy. */
+			uint16_t	bscopy_sec;
+			uint8_t		reserved1[12];
+			/** Physical drive number. */
+			uint8_t		pdn;
+			uint8_t		reserved2;
+			/** Extended boot signature. */
+			uint8_t		ebs;
+			/** Serial number. */
+			uint32_t	id;
+			/** Volume label. */
+			uint8_t		label[11];
+			/** FAT type. */
+			uint8_t		type[8];
+			/** Boot code. */
+			uint8_t		boot_code[420];
+			/** Signature. */
+			uint16_t	signature;
+		} __attribute__ ((packed));
+	};
+} __attribute__ ((packed)) fat_bs_t;
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/app/mkfat/mkfat.c
===================================================================
--- uspace/app/mkfat/mkfat.c	(revision 234e39e658dc0c08fdabeeb8bbb0f20fee1eb942)
+++ uspace/app/mkfat/mkfat.c	(revision 234e39e658dc0c08fdabeeb8bbb0f20fee1eb942)
@@ -0,0 +1,347 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup fs
+ * @{
+ */
+
+/**
+ * @file	mkfat.c
+ * @brief	Tool for creating new FAT file systems.
+ *
+ * Currently we can only create 16-bit FAT.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <libblock.h>
+#include <mem.h>
+#include <devmap.h>
+#include <byteorder.h>
+#include <errno.h>
+#include "fat.h"
+
+#define NAME	"mkfat"
+
+/** Divide and round up. */
+#define div_round_up(a, b) (((a) + (b) - 1) / (b))
+
+/** Predefined file-system parameters */
+enum {
+	sector_size		= 512,
+	sectors_per_cluster	= 8,
+	fat_count		= 2,
+	reserved_clusters	= 2,
+	media_descriptor	= 0xF8 /**< fixed disk */
+};
+
+/** Configurable file-system parameters */
+typedef struct fat_cfg {
+	uint32_t total_sectors;
+	uint16_t root_ent_max;
+	uint16_t addt_res_sectors;
+} fat_cfg_t;
+
+/** Derived file-system parameters */
+typedef struct fat_params {
+	struct fat_cfg cfg;
+	uint16_t reserved_sectors;
+	uint16_t rootdir_sectors;
+	uint32_t fat_sectors;
+	uint16_t total_clusters;
+} fat_params_t;
+
+static void syntax_print(void);
+
+static int fat_params_compute(struct fat_cfg const *cfg,
+    struct fat_params *par);
+static int fat_blocks_write(struct fat_params const *par,
+    dev_handle_t handle);
+static void fat_bootsec_create(struct fat_params const *par, struct fat_bs *bs);
+
+int main(int argc, char **argv)
+{
+	struct fat_params par;
+	struct fat_cfg cfg;
+
+	int rc;
+	char *dev_path;
+	dev_handle_t handle;
+	size_t block_size;
+	char *endptr;
+	bn_t dev_nblocks;
+
+	cfg.total_sectors = 0;
+	cfg.addt_res_sectors = 0;
+	cfg.root_ent_max = 128;
+
+	if (argc < 2) {
+		printf(NAME ": Error, argument missing.\n");
+		syntax_print();
+		return 1;
+	}
+
+	--argc; ++argv;
+
+	if (str_cmp(*argv, "--size") == 0) {
+		--argc; ++argv;
+		if (*argv == NULL) {
+			printf(NAME ": Error, argument missing.\n");
+			syntax_print();
+			return 1;
+		}
+
+		cfg.total_sectors = strtol(*argv, &endptr, 10);
+		if (*endptr != '\0') {
+			printf(NAME ": Error, invalid argument.\n");
+			syntax_print();
+			return 1;
+		}
+
+		--argc; ++argv;
+	}
+
+	if (argc != 1) {
+		printf(NAME ": Error, unexpected argument.\n");
+		syntax_print();
+		return 1;
+	}
+
+	dev_path = *argv;
+
+	rc = devmap_device_get_handle(dev_path, &handle, 0);
+	if (rc != EOK) {
+		printf(NAME ": Error resolving device `%s'.\n", dev_path);
+		return 2;
+	}
+
+	rc = block_init(handle, 2048);
+	if (rc != EOK)  {
+		printf(NAME ": Error initializing libblock.\n");
+		return 2;
+	}
+
+	rc = block_get_bsize(handle, &block_size);
+	if (rc != EOK) {
+		printf(NAME ": Error determining device block size.\n");
+		return 2;
+	}
+
+	rc = block_get_nblocks(handle, &dev_nblocks);
+	if (rc != EOK) {
+		printf(NAME ": Warning, failed to obtain block device size.\n");
+	} else {
+		printf(NAME ": Block device has %llu blocks.\n", dev_nblocks);
+		cfg.total_sectors = dev_nblocks;
+	}
+
+	if (block_size != 512) {
+		printf(NAME ": Error. Device block size is not 512 bytes.\n");
+		return 2;
+	}
+
+	if (cfg.total_sectors == 0) {
+		printf(NAME ": Error. You must specify filesystem size.\n");
+		return 1;
+	}
+
+	printf(NAME ": Creating FAT filesystem on device %s.\n", dev_path);
+
+	rc = fat_params_compute(&cfg, &par);
+	if (rc != EOK) {
+		printf(NAME ": Invalid file-system parameters.\n");
+		return 2;
+	}
+
+	rc = fat_blocks_write(&par, handle);
+	if (rc != EOK) {
+		printf(NAME ": Error writing device.\n");
+		return 2;
+	}
+
+	block_fini(handle);
+	printf("Success.\n");
+
+	return 0;
+}
+
+static void syntax_print(void)
+{
+	printf("syntax: mkfat [--size <num_blocks>] <device_name>\n");
+}
+
+/** Derive sizes of different filesystem structures.
+ *
+ * This function concentrates all the different computations of FAT
+ * file system params.
+ */
+static int fat_params_compute(struct fat_cfg const *cfg, struct fat_params *par)
+{
+	uint32_t fat_bytes;
+	uint32_t non_data_sectors_lb;
+
+	/*
+         * Make a conservative guess on the FAT size needed for the file
+         * system. The optimum could be potentially smaller since we
+         * do not subtract size of the FAT itself when computing the
+         * size of the data region.
+         */
+
+	par->reserved_sectors = 1 + cfg->addt_res_sectors;
+	par->rootdir_sectors = div_round_up(cfg->root_ent_max * DIRENT_SIZE,
+	    sector_size);
+	non_data_sectors_lb = par->reserved_sectors + par->rootdir_sectors;
+
+	par->total_clusters = div_round_up(cfg->total_sectors - non_data_sectors_lb,
+	    sectors_per_cluster);
+
+	fat_bytes = (par->total_clusters + 2) * 2;
+	par->fat_sectors = div_round_up(fat_bytes, sector_size);
+
+	par->cfg = *cfg;
+
+	return EOK;
+}
+
+/** Create file system with the given parameters. */
+static int fat_blocks_write(struct fat_params const *par, dev_handle_t handle)
+{
+	bn_t addr;
+	uint8_t *buffer;
+	int i;
+	uint32_t j;
+	int rc;
+	struct fat_bs bs;
+
+	fat_bootsec_create(par, &bs);
+
+	rc = block_write_direct(handle, BS_BLOCK, 1, &bs);
+	if (rc != EOK)
+		return EIO;
+
+	addr = BS_BLOCK + 1;
+
+	buffer = calloc(sector_size, 1);
+	if (buffer == NULL)
+		return ENOMEM;
+
+	/* Reserved sectors */
+	for (i = 0; i < par->reserved_sectors - 1; ++i) {
+		rc = block_write_direct(handle, addr, 1, buffer);
+		if (rc != EOK)
+			return EIO;
+
+		++addr;
+	}
+
+	/* File allocation tables */
+	for (i = 0; i < fat_count; ++i) {
+		printf("Writing allocation table %d.\n", i + 1);
+
+		for (j = 0; j < par->fat_sectors; ++j) {
+			memset(buffer, 0, sector_size);
+			if (j == 0) {
+				buffer[0] = media_descriptor;
+				buffer[1] = 0xFF;
+				buffer[2] = 0xFF;
+				buffer[3] = 0xFF;
+			}
+
+			rc = block_write_direct(handle, addr, 1, buffer);
+			if (rc != EOK)
+				return EIO;
+
+			++addr;
+		}
+	}
+
+	printf("Writing root directory.\n");
+
+	memset(buffer, 0, sector_size);
+
+	/* Root directory */
+	for (i = 0; i < par->rootdir_sectors; ++i) {
+		rc = block_write_direct(handle, addr, 1, buffer);
+		if (rc != EOK)
+			return EIO;
+
+		++addr;
+	}
+
+	free(buffer);
+
+	return EOK;
+}
+
+/** Construct boot sector with the given parameters. */
+static void fat_bootsec_create(struct fat_params const *par, struct fat_bs *bs)
+{
+	memset(bs, 0, sizeof(*bs));
+
+	bs->ji[0] = 0xEB;
+	bs->ji[1] = 0x3C;
+	bs->ji[2] = 0x90;
+
+	memcpy(bs->oem_name, "HELENOS ", 8);
+
+	/* BIOS Parameter Block */
+	bs->bps = host2uint16_t_le(sector_size);
+	bs->spc = sectors_per_cluster;
+	bs->rscnt = host2uint16_t_le(par->reserved_sectors);
+	bs->fatcnt = fat_count;
+	bs->root_ent_max = host2uint16_t_le(par->cfg.root_ent_max);
+
+	if (par->cfg.total_sectors < 0x10000)
+		bs->totsec16 = host2uint16_t_le(par->cfg.total_sectors);
+	else
+		bs->totsec16 = host2uint16_t_le(0);
+
+	bs->mdesc = media_descriptor;
+	bs->sec_per_fat = host2uint16_t_le(par->fat_sectors);
+	bs->sec_per_track = host2uint16_t_le(63);
+	bs->headcnt = host2uint16_t_le(6);
+	bs->hidden_sec = host2uint32_t_le(0);
+
+	if (par->cfg.total_sectors >= 0x10000)
+		bs->totsec32 = host2uint32_t_le(par->cfg.total_sectors);
+	else
+		bs->totsec32 = host2uint32_t_le(0);
+
+	/* Extended BPB */
+	bs->pdn = 0x80;
+	bs->ebs = 0x29;
+	bs->id = host2uint32_t_be(0x12345678);
+
+	memcpy(bs->label, "HELENOS_NEW", 11);
+	memcpy(bs->type, "FAT16   ", 8);
+	bs->signature = host2uint16_t_be(0x55AA);
+}
+
+/**
+ * @}
+ */
Index: uspace/lib/libblock/libblock.c
===================================================================
--- uspace/lib/libblock/libblock.c	(revision 40d4c1d4873553b574cf552692c01791d56f1689)
+++ uspace/lib/libblock/libblock.c	(revision 234e39e658dc0c08fdabeeb8bbb0f20fee1eb942)
@@ -87,4 +87,5 @@
 static int write_blocks(devcon_t *devcon, bn_t ba, size_t cnt);
 static int get_block_size(int dev_phone, size_t *bsize);
+static int get_num_blocks(int dev_phone, bn_t *nblocks);
 
 static devcon_t *devcon_search(dev_handle_t dev_handle)
@@ -714,5 +715,5 @@
 
 	memcpy(devcon->comm_area, data, devcon->pblock_size * cnt);
-	rc = read_blocks(devcon, ba, cnt);
+	rc = write_blocks(devcon, ba, cnt);
 
 	fibril_mutex_unlock(&devcon->comm_area_lock);
@@ -736,4 +737,21 @@
 	
 	return get_block_size(devcon->dev_phone, bsize);
+}
+
+/** Get number of blocks on device.
+ *
+ * @param dev_handle	Device handle of the block device.
+ * @param nblocks	Output number of blocks.
+ *
+ * @return		EOK on success or negative error code on failure.
+ */
+int block_get_nblocks(dev_handle_t dev_handle, bn_t *nblocks)
+{
+	devcon_t *devcon;
+
+	devcon = devcon_search(dev_handle);
+	assert(devcon);
+	
+	return get_num_blocks(devcon->dev_phone, nblocks);
 }
 
@@ -789,4 +807,18 @@
 }
 
+/** Get total number of blocks on block device. */
+static int get_num_blocks(int dev_phone, bn_t *nblocks)
+{
+	ipcarg_t nb_l, nb_h;
+	int rc;
+
+	rc = async_req_0_2(dev_phone, BD_GET_NUM_BLOCKS, &nb_l, &nb_h);
+	if (rc == EOK) {
+		*nblocks = (bn_t) MERGE_LOUP32(nb_l, nb_h);
+	}
+
+	return rc;
+}
+
 /** @}
  */
Index: uspace/lib/libblock/libblock.h
===================================================================
--- uspace/lib/libblock/libblock.h	(revision 40d4c1d4873553b574cf552692c01791d56f1689)
+++ uspace/lib/libblock/libblock.h	(revision 234e39e658dc0c08fdabeeb8bbb0f20fee1eb942)
@@ -60,6 +60,4 @@
 #define BLOCK_FLAGS_NOREAD	1
 
-typedef uint64_t bn_t;	/**< Block number type. */
-
 typedef struct block {
 	/** Mutex protecting the reference count. */
@@ -110,4 +108,5 @@
 
 extern int block_get_bsize(dev_handle_t, size_t *);
+extern int block_get_nblocks(dev_handle_t, bn_t *);
 extern int block_read_direct(dev_handle_t, bn_t, size_t, void *);
 extern int block_write_direct(dev_handle_t, bn_t, size_t, const void *);
Index: uspace/lib/libc/generic/io/io.c
===================================================================
--- uspace/lib/libc/generic/io/io.c	(revision 40d4c1d4873553b574cf552692c01791d56f1689)
+++ uspace/lib/libc/generic/io/io.c	(revision 234e39e658dc0c08fdabeeb8bbb0f20fee1eb942)
@@ -554,4 +554,15 @@
 }
 
+int ftell(FILE *stream)
+{
+	off_t rc = lseek(stream->fd, 0, SEEK_CUR);
+	if (rc == (off_t) (-1)) {
+		/* errno has been set by lseek. */
+		return -1;
+	}
+
+	return rc;
+}
+
 void rewind(FILE *stream)
 {
Index: uspace/lib/libc/include/ipc/bd.h
===================================================================
--- uspace/lib/libc/include/ipc/bd.h	(revision 40d4c1d4873553b574cf552692c01791d56f1689)
+++ uspace/lib/libc/include/ipc/bd.h	(revision 234e39e658dc0c08fdabeeb8bbb0f20fee1eb942)
@@ -40,4 +40,5 @@
 typedef enum {
 	BD_GET_BLOCK_SIZE = IPC_FIRST_USER_METHOD,
+	BD_GET_NUM_BLOCKS,
 	BD_READ_BLOCKS,
 	BD_WRITE_BLOCKS
Index: uspace/lib/libc/include/sys/types.h
===================================================================
--- uspace/lib/libc/include/sys/types.h	(revision 40d4c1d4873553b574cf552692c01791d56f1689)
+++ uspace/lib/libc/include/sys/types.h	(revision 234e39e658dc0c08fdabeeb8bbb0f20fee1eb942)
@@ -40,4 +40,5 @@
 typedef long off_t;
 typedef int mode_t;
+typedef uint64_t bn_t;	/**< Block number type. */
 
 typedef int32_t wchar_t;
Index: uspace/srv/bd/ata_bd/ata_bd.c
===================================================================
--- uspace/srv/bd/ata_bd/ata_bd.c	(revision 40d4c1d4873553b574cf552692c01791d56f1689)
+++ uspace/srv/bd/ata_bd/ata_bd.c	(revision 234e39e658dc0c08fdabeeb8bbb0f20fee1eb942)
@@ -296,4 +296,8 @@
 			ipc_answer_1(callid, EOK, block_size);
 			continue;
+		case BD_GET_NUM_BLOCKS:
+			ipc_answer_2(callid, EOK, LOWER32(disk[disk_id].blocks),
+			    UPPER32(disk[disk_id].blocks));
+			continue;
 		default:
 			retval = EINVAL;
Index: uspace/srv/bd/file_bd/file_bd.c
===================================================================
--- uspace/srv/bd/file_bd/file_bd.c	(revision 40d4c1d4873553b574cf552692c01791d56f1689)
+++ uspace/srv/bd/file_bd/file_bd.c	(revision 234e39e658dc0c08fdabeeb8bbb0f20fee1eb942)
@@ -56,4 +56,5 @@
 
 static const size_t block_size = 512;
+static bn_t num_blocks;
 static FILE *img;
 
@@ -99,4 +100,5 @@
 {
 	int rc;
+	long img_size;
 
 	rc = devmap_driver_register(NAME, file_bd_connection);
@@ -109,4 +111,17 @@
 	if (img == NULL)
 		return EINVAL;
+
+	if (fseek(img, 0, SEEK_END) != 0) {
+		fclose(img);
+		return EIO;
+	}
+
+	img_size = ftell(img);
+	if (img_size < 0) {
+		fclose(img);
+		return EIO;
+	}
+
+	num_blocks = img_size / block_size;
 
 	fibril_mutex_initialize(&dev_lock);
@@ -174,4 +189,8 @@
 			ipc_answer_1(callid, EOK, block_size);
 			continue;
+		case BD_GET_NUM_BLOCKS:
+			ipc_answer_2(callid, EOK, LOWER32(num_blocks),
+			    UPPER32(num_blocks));
+			continue;
 		default:
 			retval = EINVAL;
@@ -213,5 +232,5 @@
 
 	fseek(img, ba * block_size, SEEK_SET);
-	n_wr = fread(buf, block_size, cnt, img);
+	n_wr = fwrite(buf, block_size, cnt, img);
 
 	if (ferror(img) || n_wr < cnt) {
Index: uspace/srv/bd/gxe_bd/gxe_bd.c
===================================================================
--- uspace/srv/bd/gxe_bd/gxe_bd.c	(revision 40d4c1d4873553b574cf552692c01791d56f1689)
+++ uspace/srv/bd/gxe_bd/gxe_bd.c	(revision 234e39e658dc0c08fdabeeb8bbb0f20fee1eb942)
@@ -234,4 +234,7 @@
 			ipc_answer_1(callid, EOK, block_size);
 			continue;
+		case BD_GET_NUM_BLOCKS:
+			retval = ENOTSUP;
+			break;
 		default:
 			retval = EINVAL;
Index: uspace/srv/bd/part/mbr_part/mbr_part.c
===================================================================
--- uspace/srv/bd/part/mbr_part/mbr_part.c	(revision 40d4c1d4873553b574cf552692c01791d56f1689)
+++ uspace/srv/bd/part/mbr_part/mbr_part.c	(revision 234e39e658dc0c08fdabeeb8bbb0f20fee1eb942)
@@ -463,5 +463,8 @@
 			ipc_answer_1(callid, EOK, block_size);
 			continue;
-
+		case BD_GET_NUM_BLOCKS:
+			ipc_answer_2(callid, EOK, LOWER32(part->length),
+			    UPPER32(part->length));
+			continue;
 		default:
 			retval = EINVAL;
Index: uspace/srv/bd/rd/rd.c
===================================================================
--- uspace/srv/bd/rd/rd.c	(revision 40d4c1d4873553b574cf552692c01791d56f1689)
+++ uspace/srv/bd/rd/rd.c	(revision 234e39e658dc0c08fdabeeb8bbb0f20fee1eb942)
@@ -153,4 +153,8 @@
 			ipc_answer_1(callid, EOK, block_size);
 			continue;
+		case BD_GET_NUM_BLOCKS:
+			ipc_answer_2(callid, EOK, LOWER32(rd_size / block_size),
+			    UPPER32(rd_size / block_size));
+			continue;
 		default:
 			/*
Index: uspace/srv/vfs/vfs_ops.c
===================================================================
--- uspace/srv/vfs/vfs_ops.c	(revision 40d4c1d4873553b574cf552692c01791d56f1689)
+++ uspace/srv/vfs/vfs_ops.c	(revision 234e39e658dc0c08fdabeeb8bbb0f20fee1eb942)
@@ -900,4 +900,5 @@
 		}
 		newpos = size + off;
+		file->pos = newpos;
 		fibril_mutex_unlock(&file->lock);
 		ipc_answer_1(rid, EOK, newpos);
