Index: uspace/srv/fs/ext2fs/ext2fs_ops.c
===================================================================
--- uspace/srv/fs/ext2fs/ext2fs_ops.c	(revision 5e3eea10eab5547b0c0e9d45abbeb98d19f9474d)
+++ uspace/srv/fs/ext2fs/ext2fs_ops.c	(revision fca78d43e53ede5204bbb6a1e7c71c0e0efd4556)
@@ -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);
