Index: uspace/app/mkfat/mkfat.c
===================================================================
--- uspace/app/mkfat/mkfat.c	(revision dccf72146c31b468c546d35ed8f671e5e26cda76)
+++ uspace/app/mkfat/mkfat.c	(revision 08232eec7477aa13695d471714768b19b5d6d270)
@@ -93,4 +93,5 @@
 	size_t block_size;
 	char *endptr;
+	bn_t dev_nblocks;
 
 	cfg.total_sectors = 0;
@@ -144,4 +145,12 @@
 		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;
 	}
 
@@ -240,5 +249,4 @@
 	}
 
-	printf("fat_sectors=%d\n", par->fat_sectors);
 	/* File allocation tables */
 	for (i = 0; i < fat_count; ++i) {
Index: uspace/lib/libblock/libblock.c
===================================================================
--- uspace/lib/libblock/libblock.c	(revision dccf72146c31b468c546d35ed8f671e5e26cda76)
+++ uspace/lib/libblock/libblock.c	(revision 08232eec7477aa13695d471714768b19b5d6d270)
@@ -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)
@@ -738,4 +739,21 @@
 }
 
+/** 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);
+}
+
 /** Read blocks from block device.
  *
@@ -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 dccf72146c31b468c546d35ed8f671e5e26cda76)
+++ uspace/lib/libblock/libblock.h	(revision 08232eec7477aa13695d471714768b19b5d6d270)
@@ -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 dccf72146c31b468c546d35ed8f671e5e26cda76)
+++ uspace/lib/libc/generic/io/io.c	(revision 08232eec7477aa13695d471714768b19b5d6d270)
@@ -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 dccf72146c31b468c546d35ed8f671e5e26cda76)
+++ uspace/lib/libc/include/ipc/bd.h	(revision 08232eec7477aa13695d471714768b19b5d6d270)
@@ -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 dccf72146c31b468c546d35ed8f671e5e26cda76)
+++ uspace/lib/libc/include/sys/types.h	(revision 08232eec7477aa13695d471714768b19b5d6d270)
@@ -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 dccf72146c31b468c546d35ed8f671e5e26cda76)
+++ uspace/srv/bd/ata_bd/ata_bd.c	(revision 08232eec7477aa13695d471714768b19b5d6d270)
@@ -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 dccf72146c31b468c546d35ed8f671e5e26cda76)
+++ uspace/srv/bd/file_bd/file_bd.c	(revision 08232eec7477aa13695d471714768b19b5d6d270)
@@ -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;
Index: uspace/srv/bd/gxe_bd/gxe_bd.c
===================================================================
--- uspace/srv/bd/gxe_bd/gxe_bd.c	(revision dccf72146c31b468c546d35ed8f671e5e26cda76)
+++ uspace/srv/bd/gxe_bd/gxe_bd.c	(revision 08232eec7477aa13695d471714768b19b5d6d270)
@@ -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 dccf72146c31b468c546d35ed8f671e5e26cda76)
+++ uspace/srv/bd/part/mbr_part/mbr_part.c	(revision 08232eec7477aa13695d471714768b19b5d6d270)
@@ -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 dccf72146c31b468c546d35ed8f671e5e26cda76)
+++ uspace/srv/bd/rd/rd.c	(revision 08232eec7477aa13695d471714768b19b5d6d270)
@@ -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 dccf72146c31b468c546d35ed8f671e5e26cda76)
+++ uspace/srv/vfs/vfs_ops.c	(revision 08232eec7477aa13695d471714768b19b5d6d270)
@@ -900,4 +900,5 @@
 		}
 		newpos = size + off;
+		file->pos = newpos;
 		fibril_mutex_unlock(&file->lock);
 		ipc_answer_1(rid, EOK, newpos);
