Index: uspace/lib/ext2/libext2_filesystem.c
===================================================================
--- uspace/lib/ext2/libext2_filesystem.c	(revision a54af668b195587f801880c219d838ca1c5537fe)
+++ uspace/lib/ext2/libext2_filesystem.c	(revision ad34feb47f3ea02025abdcc9a3565f7e7df1ec6a)
@@ -41,4 +41,5 @@
 #include <libblock.h>
 #include <malloc.h>
+#include <assert.h>
 
 /**
@@ -255,4 +256,94 @@
 
 /**
+ * Find a filesystem block number where iblock-th data block
+ * of the given inode is located.
+ * 
+ * @return 		EOK on success or negative error code on failure
+ */
+int ext2_filesystem_get_inode_data_block_index(ext2_filesystem_t *fs, ext2_inode_t* inode,
+    aoff64_t iblock, uint32_t* fblock)
+{
+	int rc;
+	aoff64_t limits[4];
+	uint32_t block_ids_per_block;
+	aoff64_t blocks_per_level[4];
+	uint32_t offset_in_block;
+	uint32_t current_block;
+	aoff64_t block_offset_in_level;
+	int i;
+	int level;
+	block_t *block;
+	
+	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;
+	}
+	
+	// Compute limits for indirect block levels
+	// TODO: compute this once when loading filesystem and store in ext2_filesystem_t
+	block_ids_per_block = ext2_superblock_get_block_size(fs->superblock) / sizeof(uint32_t);
+	limits[0] = EXT2_INODE_DIRECT_BLOCKS;
+	blocks_per_level[0] = 1;
+	for (i = 1; i < 4; i++) {
+		blocks_per_level[i]  = blocks_per_level[i-1] *
+		    block_ids_per_block;
+		limits[i] = limits[i-1] + blocks_per_level[i];
+	}
+	
+	// Determine the indirection level needed to get the desired block
+	level = -1;
+	for (i = 1; i < 4; i++) {
+		if (iblock < limits[i]) {
+			level = i;
+			break;
+		}
+	}
+	
+	if (level == -1) {
+		return EIO;
+	}
+	
+	block_offset_in_level = iblock - limits[level-1];
+	current_block = ext2_inode_get_indirect_block(inode, level-1);
+	offset_in_block = block_offset_in_level / blocks_per_level[level-1];
+	
+	while (level > 0) {
+		rc = block_get(&block, fs->device, current_block, 0);
+		if (rc != EOK) {
+			return rc;
+		}
+		
+		assert(offset_in_block < block_ids_per_block);
+		current_block = ((uint32_t*)block->data)[offset_in_block];
+		
+		rc = block_put(block);
+		if (rc != EOK) {
+			return rc;
+		}
+		
+		if (current_block == 0) {
+			return EIO;
+		}
+		
+		level -= 1;
+		
+		if (level == 0) {
+			break;
+		}
+		
+		offset_in_block = block_offset_in_level / blocks_per_level[level-1];
+		block_offset_in_level %= blocks_per_level[level-1];
+	}
+	
+	*fblock = current_block;
+	
+	return EOK;
+}
+
+/**
  * Finalize an instance of filesystem
  * 
Index: uspace/lib/ext2/libext2_filesystem.h
===================================================================
--- uspace/lib/ext2/libext2_filesystem.h	(revision a54af668b195587f801880c219d838ca1c5537fe)
+++ uspace/lib/ext2/libext2_filesystem.h	(revision ad34feb47f3ea02025abdcc9a3565f7e7df1ec6a)
@@ -60,4 +60,6 @@
     ext2_inode_ref_t **);
 extern int ext2_filesystem_put_inode_ref(ext2_inode_ref_t *);
+extern int ext2_filesystem_get_inode_data_block_index(ext2_filesystem_t *, ext2_inode_t*,
+    aoff64_t, uint32_t*);
 extern void ext2_filesystem_fini(ext2_filesystem_t *);
 
Index: uspace/lib/ext2/libext2_inode.c
===================================================================
--- uspace/lib/ext2/libext2_inode.c	(revision a54af668b195587f801880c219d838ca1c5537fe)
+++ uspace/lib/ext2/libext2_inode.c	(revision ad34feb47f3ea02025abdcc9a3565f7e7df1ec6a)
@@ -38,4 +38,5 @@
 #include "libext2_superblock.h"
 #include <byteorder.h>
+#include <assert.h>
 
 /**
@@ -142,4 +143,17 @@
 
 /**
+ * Get number of blocks allocated for contents of the file
+ * represented by this inode.
+ * 
+ * @param inode pointer to inode
+ */
+inline uint32_t ext2_inode_get_reserved_blocks(ext2_superblock_t *sb,
+    ext2_inode_t *inode)
+{
+	return ext2_inode_get_reserved_512_blocks(inode) /
+	    (ext2_superblock_get_block_size(sb) / 512);
+}
+
+/**
  * Get inode flags
  * 
@@ -158,4 +172,5 @@
 inline uint32_t ext2_inode_get_direct_block(ext2_inode_t *inode, uint8_t idx)
 {
+	assert(idx < EXT2_INODE_DIRECT_BLOCKS);
 	return uint32_t_le2host(inode->direct_blocks[idx]);
 }
@@ -165,31 +180,12 @@
  * 
  * @param inode pointer to inode
+ * @param idx Indirection level. Valid values are 0 <= idx < 3, where 0 is
+ *            singly-indirect block and 2 is triply-indirect-block
  */
-inline uint32_t ext2_inode_get_single_indirect_block(ext2_inode_t *inode)
+inline uint32_t ext2_inode_get_indirect_block(ext2_inode_t *inode, uint8_t idx)
 {
-	return uint32_t_le2host(inode->single_indirect_block);
+	assert(idx < 3);
+	return uint32_t_le2host(inode->indirect_blocks[idx]);
 }
-
-/**
- * Get double indirect block ID
- * 
- * @param inode pointer to inode
- */
-inline uint32_t ext2_inode_get_double_indirect_block(ext2_inode_t *inode)
-{
-	return uint32_t_le2host(inode->double_indirect_block);
-}
-
-/**
- * Get triple indirect block ID
- * 
- * @param inode pointer to inode
- */
-inline uint32_t ext2_inode_get_triple_indirect_block(ext2_inode_t *inode)
-{
-	return uint32_t_le2host(inode->triple_indirect_block);
-}
-
-
 
 /** @}
Index: uspace/lib/ext2/libext2_inode.h
===================================================================
--- uspace/lib/ext2/libext2_inode.h	(revision a54af668b195587f801880c219d838ca1c5537fe)
+++ uspace/lib/ext2/libext2_inode.h	(revision ad34feb47f3ea02025abdcc9a3565f7e7df1ec6a)
@@ -51,7 +51,5 @@
 	uint8_t unused2[4];
 	uint32_t direct_blocks[12]; // Direct block ids stored in this inode
-	uint32_t single_indirect_block;
-	uint32_t double_indirect_block;
-	uint32_t triple_indirect_block;
+	uint32_t indirect_blocks[3];
 	uint32_t version;
 	uint32_t file_acl;
@@ -75,4 +73,5 @@
 #define EXT2_INODE_MODE_ACCESS_MASK	0x0FFF
 #define EXT2_INODE_MODE_TYPE_MASK	0xF000
+#define EXT2_INODE_DIRECT_BLOCKS	12
 
 typedef struct ext2_inode_ref {
@@ -88,9 +87,9 @@
 inline uint16_t ext2_inode_get_usage_count(ext2_inode_t *);
 inline uint32_t ext2_inode_get_reserved_512_blocks(ext2_inode_t *);
+inline uint32_t ext2_inode_get_reserved_blocks(ext2_superblock_t *, 
+    ext2_inode_t *);
 inline uint32_t ext2_inode_get_flags(ext2_inode_t *);
 inline uint32_t ext2_inode_get_direct_block(ext2_inode_t *, uint8_t);
-inline uint32_t ext2_inode_get_single_indirect_block(ext2_inode_t *);
-inline uint32_t ext2_inode_get_double_indirect_block(ext2_inode_t *);
-inline uint32_t ext2_inode_get_triple_indirect_block(ext2_inode_t *);
+inline uint32_t ext2_inode_get_indirect_block(ext2_inode_t *, uint8_t level);
 
 
