Index: uspace/lib/ext2/libext2_filesystem.c
===================================================================
--- uspace/lib/ext2/libext2_filesystem.c	(revision f2d665b48f974d9723721aacf0bdbd99afedcbd7)
+++ uspace/lib/ext2/libext2_filesystem.c	(revision 7ea69a670d131f8f5725fcb281e21c4c2280c81e)
@@ -297,4 +297,6 @@
  * of the given inode is located.
  * 
+ * @param fblock the number of filesystem block, or 0 if no such block is allocated yet
+ * 
  * @return 		EOK on success or negative error code on failure
  */
@@ -315,7 +317,4 @@
 	if (iblock < EXT2_INODE_DIRECT_BLOCKS) {
 		current_block = ext2_inode_get_direct_block(inode, (uint32_t)iblock);
-		if (current_block == 0) {
-			return EIO;
-		}
 		*fblock = current_block;
 		return EOK;
@@ -365,5 +364,6 @@
 		
 		if (current_block == 0) {
-			return EIO;
+			*fblock = 0;
+			return EOK;
 		}
 		
Index: uspace/srv/fs/ext2fs/ext2fs_ops.c
===================================================================
--- uspace/srv/fs/ext2fs/ext2fs_ops.c	(revision f2d665b48f974d9723721aacf0bdbd99afedcbd7)
+++ uspace/srv/fs/ext2fs/ext2fs_ops.c	(revision 7ea69a670d131f8f5725fcb281e21c4c2280c81e)
@@ -56,4 +56,5 @@
 #include <align.h>
 #include <adt/hash_table.h>
+#include <sys/typefmt.h>
 
 #define EXT2FS_NODE(node)	((node) ? (ext2fs_node_t *) (node)->data : NULL)
@@ -760,4 +761,5 @@
 	size_t bytes;
 	block_t *block;
+	uint8_t *buffer;
 	
 	file_size = ext2_inode_get_size(inst->filesystem->superblock,
@@ -777,4 +779,9 @@
 	bytes = min(block_size - offset_in_block, size);
 	
+	// Handle end of file
+	if (pos + bytes > file_size) {
+		bytes = file_size - pos;
+	}
+	
 	rc = ext2_filesystem_get_inode_data_block_index(inst->filesystem,
 		inode_ref->inode, file_block, &fs_block);
@@ -785,4 +792,27 @@
 	}
 	
+	// Check for sparse file
+	// If ext2_filesystem_get_inode_data_block_index returned
+	// fs_block == 0, it means that the given block is not allocated for the 
+	// file and we need to return a buffer of zeros
+	if (fs_block == 0) {
+		buffer = malloc(bytes);
+		if (buffer == NULL) {
+			async_answer_0(callid, ENOMEM);
+			async_answer_0(rid, ENOMEM);
+			return;
+		}
+		
+		memset(buffer, 0, bytes);
+		
+		async_data_read_finalize(callid, buffer, bytes);
+		async_answer_1(rid, EOK, bytes);
+		
+		free(buffer);
+		
+		return;
+	}
+	
+	// Usual case - we need to read a block from device
 	rc = block_get(&block, inst->devmap_handle, fs_block, BLOCK_FLAGS_NONE);
 	if (rc != EOK) {
@@ -792,5 +822,6 @@
 	}
 	
-	async_data_read_finalize(callid, block->data, bytes);
+	assert(offset_in_block + bytes <= block_size);
+	async_data_read_finalize(callid, block->data + offset_in_block, bytes);
 	
 	rc = block_put(block);
