Exemple #1
0
static int ext2fs_read_inode
	(struct ext2_data *data, int ino, struct ext2_inode *inode) {
	struct ext2_block_group blkgrp;
	struct ext2_sblock *sblock = &data->sblock;
	int inodes_per_block;
	int status;

	unsigned int blkno;
	unsigned int blkoff;

	/* It is easier to calculate if the first inode is 0.  */
	ino--;
#ifdef DEBUG
	printf ("ext2fs read inode %d\n", ino);
#endif
	status = ext2fs_blockgroup (data,
				    ino /
				    __le32_to_cpu (sblock->inodes_per_group),
				    &blkgrp);
	if (status == 0) {
		return (0);
	}
#ifdef CFG_EXT2_SUPPORT_DYNAMIC_REV
       inodes_per_block = EXT2_BLOCK_SIZE (data) / ext2_inode_size;
#else
        inodes_per_block = EXT2_BLOCK_SIZE (data) / 128;
#endif
	blkno = (ino % __le32_to_cpu (sblock->inodes_per_group)) /
		inodes_per_block;
	blkoff = (ino % __le32_to_cpu (sblock->inodes_per_group)) %
		inodes_per_block;
#ifdef DEBUG
	printf ("ext2fs read inode blkno %d blkoff %d\n", blkno, blkoff);
#endif
	/* Read the inode.  */
#ifdef CFG_EXT2_SUPPORT_DYNAMIC_REV
    status = ext2fs_devread (((__le32_to_cpu (blkgrp.inode_table_id) +
              blkno) << LOG2_EXT2_BLOCK_SIZE (data)),
            ext2_inode_size * blkoff,
            sizeof (struct ext2_inode), (char *) inode);
#else

	status = ext2fs_devread (((__le32_to_cpu (blkgrp.inode_table_id) +
				   blkno) << LOG2_EXT2_BLOCK_SIZE (data)),
				 sizeof (struct ext2_inode) * blkoff,
				 sizeof (struct ext2_inode), (char *) inode);
#endif
	if (status == 0) {
		return (0);
	}
	return (1);
}
Exemple #2
0
int ext4fs_read_inode(struct ext2_data *data, int ino, struct ext2_inode *inode)
{
	struct ext2_block_group blkgrp;
	struct ext2_sblock *sblock = &data->sblock;
	struct ext_filesystem *fs = data->fs;
	int inodes_per_block, ret;
	long int blkno;
	unsigned int blkoff;

	/* It is easier to calculate if the first inode is 0. */
	ino--;
	ret = ext4fs_blockgroup(data, ino / __le32_to_cpu
				   (sblock->inodes_per_group), &blkgrp);
	if (ret)
		return ret;

	inodes_per_block = EXT2_BLOCK_SIZE(data) / fs->inodesz;
	blkno = __le32_to_cpu(blkgrp.inode_table_id) +
	    (ino % __le32_to_cpu(sblock->inodes_per_group)) / inodes_per_block;
	blkoff = (ino % inodes_per_block) * fs->inodesz;
	/* Read the inode. */
	ret = ext4fs_devread(fs, blkno << LOG2_EXT2_BLOCK_SIZE(data), blkoff,
				sizeof(struct ext2_inode), (char *)inode);
	if (ret)
		return ret;

	return 0;
}
Exemple #3
0
/* Read the inode INO for the file described by DATA into INODE.  */
static grub_err_t
grub_ext2_read_inode (struct grub_ext2_data *data,
		      int ino, struct grub_ext2_inode *inode)
{
  struct grub_ext2_block_group blkgrp;
  struct grub_ext2_sblock *sblock = &data->sblock;
  int inodes_per_block;
  unsigned int blkno;
  unsigned int blkoff;

  /* It is easier to calculate if the first inode is 0.  */
  ino--;

  grub_ext2_blockgroup (data,
                        ino / grub_le_to_cpu32 (sblock->inodes_per_group),
			&blkgrp);
  if (grub_errno)
    return grub_errno;

  inodes_per_block = EXT2_BLOCK_SIZE (data) / EXT2_INODE_SIZE (data);
  blkno = (ino % grub_le_to_cpu32 (sblock->inodes_per_group))
    / inodes_per_block;
  blkoff = (ino % grub_le_to_cpu32 (sblock->inodes_per_group))
    % inodes_per_block;

  /* Read the inode.  */
  if (grub_disk_read (data->disk,
		      ((grub_le_to_cpu32 (blkgrp.inode_table_id) + blkno)
		        << LOG2_EXT2_BLOCK_SIZE (data)),
		      EXT2_INODE_SIZE (data) * blkoff,
		      sizeof (struct grub_ext2_inode), inode))
    return grub_errno;

  return 0;
}
Exemple #4
0
int ext2fs_read_file
    (struct ext2fs_node *node, int pos, unsigned int len, char *buf)
{
    int i;
    int blockcnt;
    int log2blocksize = LOG2_EXT2_BLOCK_SIZE (node->data);
    int blocksize = 1 << (log2blocksize + DISK_SECTOR_BITS);
    unsigned int filesize = __le32_to_cpu(node->inode.size);

    /* Adjust len so it we can't read past the end of the file.  */
    if (len > filesize) {
        len = filesize;
    }
    blockcnt = ((len + pos) + blocksize - 1) / blocksize;

    for (i = pos / blocksize; i < blockcnt; i++) {
        int blknr;
        int blockoff = pos % blocksize;
        int blockend = blocksize;

        int skipfirst = 0;

        blknr = ext2fs_read_block (node, i);
        if (blknr < 0) {
            return (-1);
        }
        blknr = blknr << log2blocksize;

        /* Last block.  */
        if (i == blockcnt - 1) {
            blockend = (len + pos) % blocksize;

            /* The last portion is exactly blocksize.  */
            if (!blockend) {
                blockend = blocksize;
            }
        }

        /* First block.  */
        if (i == pos / blocksize) {
            skipfirst = blockoff;
            blockend -= skipfirst;
        }

        /* If the block number is 0 this block is not stored on disk but
           is zero filled instead.  */
        if (blknr) {
            int status;

            status = ext2fs_devread (blknr, skipfirst, blockend, buf);
            if (status == 0) {
                return (-1);
            }
        } else {
            memset (buf, 0, blocksize - skipfirst);
        }
        buf += blocksize - skipfirst;
    }
    return (len);
}
Exemple #5
0
/* Read into BLKGRP the blockgroup descriptor of blockgroup GROUP of
   the mounted filesystem DATA.  */
inline static grub_err_t
grub_ext2_blockgroup (struct grub_ext2_data *data, int group,
		      struct grub_ext2_block_group *blkgrp)
{
  return grub_disk_read (data->disk,
                         ((grub_le_to_cpu32 (data->sblock.first_data_block) + 1)
                          << LOG2_EXT2_BLOCK_SIZE (data)),
			 group * sizeof (struct grub_ext2_block_group),
			 sizeof (struct grub_ext2_block_group), blkgrp);
}
Exemple #6
0
static int ext2fs_blockgroup
	(struct ext2_data *data, int group, struct ext2_block_group *blkgrp) {
#ifdef DEBUG
	printf ("ext2fs read blockgroup\n");
#endif
	return (ext2fs_devread
		(((__le32_to_cpu (data->sblock.first_data_block) +
		   1) << LOG2_EXT2_BLOCK_SIZE (data)),
		 group * sizeof (struct ext2_block_group),
		 sizeof (struct ext2_block_group), (char *) blkgrp));
}
Exemple #7
0
/* Read LEN bytes from the file described by DATA starting with byte
   POS.  Return the amount of read bytes in READ.  */
static grub_ssize_t
grub_ext2_read_file (grub_fshelp_node_t node,
		     void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector,
					unsigned offset, unsigned length),
		     int pos, grub_size_t len, char *buf)
{
  return grub_fshelp_read_file (node->data->disk, node, read_hook,
				pos, len, buf, grub_ext2_read_block,
				node->inode.size,
				LOG2_EXT2_BLOCK_SIZE (node->data));

}
Exemple #8
0
/* Read LEN bytes from the file described by DATA starting with byte
   POS.  Return the amount of read bytes in READ.  */
static grub_ssize_t
grub_ext2_read_file (grub_fshelp_node_t node,
		     void (*read_hook) (grub_disk_addr_t sector,
					unsigned offset, unsigned length,
					void *closure),
		     void *closure, int flags,
		     int pos, grub_size_t len, char *buf)
{
  return grub_fshelp_read_file (node->data->disk, node, read_hook, closure,
				flags, pos, len, buf, grub_ext2_read_block,
				node->inode.size,
				LOG2_EXT2_BLOCK_SIZE (node->data));

}
Exemple #9
0
static quik_err_t
ext2fs_read_inode(struct ext2_data *data,
                  int ino,
                  struct ext2_inode *inode)
{
   struct ext2_block_group blkgrp;
   struct ext2_sblock *sblock = &data->sblock;
   int inodes_per_block;
   quik_err_t err;

   unsigned int blkno;
   unsigned int blkoff;

#ifdef DEBUG
   printk ("ext2fs read inode %d, inode_size %d\n", ino, inode_size);
#endif
   /* It is easier to calculate if the first inode is 0.  */
   ino--;
   err = ext2fs_blockgroup(data, ino / __le32_to_cpu
                           (sblock->inodes_per_group), &blkgrp);
   if (err != ERR_NONE) {
      return err;
   }

   inodes_per_block = EXT2_BLOCK_SIZE(data) / inode_size;

   blkno = __le32_to_cpu(blkgrp.inode_table_id) +
      (ino % __le32_to_cpu(sblock->inodes_per_group))
      / inodes_per_block;
   blkoff = (ino % inodes_per_block) * inode_size;
#ifdef DEBUG
   printk ("ext2fs read inode blkno %d blkoff %d\n", blkno, blkoff);
#endif

   /* Read the inode.  */
   err = part_read(data->part,
                   blkno << LOG2_EXT2_BLOCK_SIZE (data), blkoff,
                   sizeof(struct ext2_inode), (char *) inode);
   if (err != ERR_NONE) {
      return err;
   }

   return ERR_NONE;
}
Exemple #10
0
static int ext2fs_blockgroup
    (struct ext2_data *data, int group, struct ext2_block_group *blkgrp) {
    unsigned int blkno;
    unsigned int blkoff;
    unsigned int desc_per_blk;

    desc_per_blk = EXT2_BLOCK_SIZE(data) / sizeof(struct ext2_block_group);

    blkno = __le32_to_cpu(data->sblock.first_data_block) + 1 +
    group / desc_per_blk;
    blkoff = (group % desc_per_blk) * sizeof(struct ext2_block_group);
#ifdef DEBUG
    printf ("ext2fs read %d group descriptor (blkno %d blkoff %d)\n",
        group, blkno, blkoff);
#endif
    return (ext2fs_devread (blkno << LOG2_EXT2_BLOCK_SIZE(data),
        blkoff, sizeof(struct ext2_block_group), (char *)blkgrp));

}
Exemple #11
0
static int ext4fs_blockgroup
	(struct ext2_data *data, int group, struct ext2_block_group *blkgrp)
{
	long int blkno;
	unsigned int blkoff, desc_per_blk;

	desc_per_blk = EXT2_BLOCK_SIZE(data) / sizeof(struct ext2_block_group);

	blkno = __le32_to_cpu(data->sblock.first_data_block) + 1 +
	    group / desc_per_blk;
	blkoff = (group % desc_per_blk) * sizeof(struct ext2_block_group);

	debug("ext4fs read %d group descriptor (blkno %ld blkoff %u)\n",
	      group, blkno, blkoff);

	return ext4fs_devread(blkno << LOG2_EXT2_BLOCK_SIZE(data),
			      blkoff, sizeof(struct ext2_block_group),
			      (char *)blkgrp);
}
Exemple #12
0
static struct grub_ext4_extent_header *
grub_ext4_find_leaf (struct grub_ext2_data *data, char *buf,
                     struct grub_ext4_extent_header *ext_block,
                     grub_uint32_t fileblock)
{
  struct grub_ext4_extent_idx *index;

  while (1)
    {
      int i;
      grub_disk_addr_t block;

      index = (struct grub_ext4_extent_idx *) (ext_block + 1);

      if (grub_le_to_cpu16(ext_block->magic) != EXT4_EXT_MAGIC)
        return 0;

      if (ext_block->depth == 0)
        return ext_block;

      for (i = 0; i < grub_le_to_cpu16 (ext_block->entries); i++)
        {
          if (fileblock < grub_le_to_cpu32(index[i].block))
            break;
        }

      if (--i < 0)
        return 0;

      block = grub_le_to_cpu16 (index[i].leaf_hi);
      block = (block << 32) + grub_le_to_cpu32 (index[i].leaf);
      if (grub_disk_read (data->disk,
                          block << LOG2_EXT2_BLOCK_SIZE (data),
                          0, EXT2_BLOCK_SIZE(data), buf))
        return 0;

      ext_block = (struct grub_ext4_extent_header *) buf;
    }
}
Exemple #13
0
static int ext2fs_read_inode
    (struct ext2_data *data, int ino, struct ext2_inode *inode) {
    struct ext2_block_group blkgrp;
    struct ext2_sblock *sblock = &data->sblock;
    int inodes_per_block;
    int status;

    unsigned int blkno;
    unsigned int blkoff;

#ifdef DEBUG
    printf ("ext2fs read inode %d, inode_size %d\n", ino, inode_size);
#endif
    /* It is easier to calculate if the first inode is 0.  */
    ino--;
    status = ext2fs_blockgroup (data, ino / __le32_to_cpu
                    (sblock->inodes_per_group), &blkgrp);
    if (status == 0) {
        return (0);
    }

    inodes_per_block = EXT2_BLOCK_SIZE(data) / inode_size;

    blkno = __le32_to_cpu (blkgrp.inode_table_id) +
        (ino % __le32_to_cpu (sblock->inodes_per_group))
        / inodes_per_block;
    blkoff = (ino % inodes_per_block) * inode_size;
#ifdef DEBUG
    printf ("ext2fs read inode blkno %d blkoff %d\n", blkno, blkoff);
#endif
    /* Read the inode.  */
    status = ext2fs_devread (blkno << LOG2_EXT2_BLOCK_SIZE (data), blkoff,
                 sizeof (struct ext2_inode), (char *) inode);
    if (status == 0) {
        return (0);
    }

    return (1);
}
Exemple #14
0
static int ext2fs_read_block(struct ext2fs_node *node, int fileblock)
{
    struct ext2_data *data = node->data;
    struct ext2_inode *inode = &node->inode;
    int blknr;
    int blksz = EXT2_BLOCK_SIZE (data);
    int log2_blksz = LOG2_EXT2_BLOCK_SIZE (data);
    int status;

    /* Direct blocks.  */
    if (fileblock < INDIRECT_BLOCKS) {
        blknr = __le32_to_cpu (inode->b.blocks.dir_blocks[fileblock]);
    }
    /* Indirect.  */
    else if (fileblock < (INDIRECT_BLOCKS + (blksz / 4))) {
        if (indir1_block == NULL) {
            indir1_block = (uint32_t *) malloc (blksz);
            if (indir1_block == NULL) {
                printf ("** ext2fs read block (indir 1) malloc failed. **\n");
                return (-1);
            }
            indir1_size = blksz;
            indir1_blkno = -1;
        }
        if (blksz != indir1_size) {
            free (indir1_block);
            indir1_block = NULL;
            indir1_size = 0;
            indir1_blkno = -1;
            indir1_block = (uint32_t *) malloc (blksz);
            if (indir1_block == NULL) {
                printf ("** ext2fs read block (indir 1) malloc failed. **\n");
                return (-1);
            }
            indir1_size = blksz;
        }
        if ((__le32_to_cpu (inode->b.blocks.indir_block) <<
             log2_blksz) != indir1_blkno) {
            status = ext2fs_devread (__le32_to_cpu(inode->b.blocks.indir_block) << log2_blksz,
                         0, blksz,
                         (char *) indir1_block);
            if (status == 0) {
                printf ("** ext2fs read block (indir 1) failed. **\n");
                return (0);
            }
            indir1_blkno =
                __le32_to_cpu (inode->b.blocks.
                           indir_block) << log2_blksz;
        }
        blknr = __le32_to_cpu (indir1_block
                       [fileblock - INDIRECT_BLOCKS]);
    }
    /* Double indirect.  */
    else if (fileblock <
         (INDIRECT_BLOCKS + (blksz / 4 * (blksz / 4 + 1)))) {
        unsigned int perblock = blksz / 4;
        unsigned int rblock = fileblock - (INDIRECT_BLOCKS
                           + blksz / 4);

        if (indir1_block == NULL) {
            indir1_block = (uint32_t *) malloc (blksz);
            if (indir1_block == NULL) {
                printf ("** ext2fs read block (indir 2 1) malloc failed. **\n");
                return (-1);
            }
            indir1_size = blksz;
            indir1_blkno = -1;
        }
        if (blksz != indir1_size) {
            free (indir1_block);
            indir1_block = NULL;
            indir1_size = 0;
            indir1_blkno = -1;
            indir1_block = (uint32_t *) malloc (blksz);
            if (indir1_block == NULL) {
                printf ("** ext2fs read block (indir 2 1) malloc failed. **\n");
                return (-1);
            }
            indir1_size = blksz;
        }
        if ((__le32_to_cpu (inode->b.blocks.double_indir_block) <<
             log2_blksz) != indir1_blkno) {
            status = ext2fs_devread (__le32_to_cpu(inode->b.blocks.double_indir_block) << log2_blksz,
                        0, blksz,
                        (char *) indir1_block);
            if (status == 0) {
                printf ("** ext2fs read block (indir 2 1) failed. **\n");
                return (-1);
            }
            indir1_blkno =
                __le32_to_cpu (inode->b.blocks.double_indir_block) << log2_blksz;
        }

        if (indir2_block == NULL) {
            indir2_block = (uint32_t *) malloc (blksz);
            if (indir2_block == NULL) {
                printf ("** ext2fs read block (indir 2 2) malloc failed. **\n");
                return (-1);
            }
            indir2_size = blksz;
            indir2_blkno = -1;
        }
        if (blksz != indir2_size) {
            free (indir2_block);
            indir2_block = NULL;
            indir2_size = 0;
            indir2_blkno = -1;
            indir2_block = (uint32_t *) malloc (blksz);
            if (indir2_block == NULL) {
                printf ("** ext2fs read block (indir 2 2) malloc failed. **\n");
                return (-1);
            }
            indir2_size = blksz;
        }
        if ((__le32_to_cpu (indir1_block[rblock / perblock]) <<
             log2_blksz) != indir2_blkno) {
            status = ext2fs_devread (__le32_to_cpu(indir1_block[rblock / perblock]) << log2_blksz,
                         0, blksz,
                         (char *) indir2_block);
            if (status == 0) {
                printf ("** ext2fs read block (indir 2 2) failed. **\n");
                return (-1);
            }
            indir2_blkno =
                __le32_to_cpu (indir1_block[rblock / perblock]) << log2_blksz;
        }
        blknr = __le32_to_cpu (indir2_block[rblock % perblock]);
    }
    /* Tripple indirect.  */
    else {
        printf ("** ext2fs doesn't support tripple indirect blocks. **\n");
        return (-1);
    }
#ifdef DEBUG
    printf ("ext2fs_read_block %08x\n", blknr);
#endif
    return (blknr);
}
Exemple #15
0
quik_err_t
ext2fs_read_file(ext2fs_node_t node,
                 unsigned pos,
                 length_t len,
                 char *buf)
{
   unsigned i;
   unsigned blockcnt;
   quik_err_t err;
   int log2blocksize = LOG2_EXT2_BLOCK_SIZE(node->data);
   int blocksize = 1 << (log2blocksize + DISK_SECTOR_BITS);
   unsigned int filesize = __le32_to_cpu(node->inode.size);

   /* Adjust len so it we can't read past the end of the file.  */
   if (len > filesize) {
      len = filesize;
   }

   blockcnt = ((len + pos) + blocksize - 1) / blocksize;

   for (i = pos / blocksize; i < blockcnt; i++) {
      unsigned blknr;
      unsigned blockoff = pos % blocksize;
      length_t blockend = blocksize;

      spinner(5);

      int skipfirst = 0;

      err = ext2fs_read_block(node, i, &blknr);
      if (err != ERR_NONE) {
         return err;
      }

      blknr = blknr << log2blocksize;

      /* Last block.  */
      if (i == blockcnt - 1) {
         blockend = (len + pos) % blocksize;

         /* The last portion is exactly blocksize.  */
         if (!blockend) {
            blockend = blocksize;
         }
      }

      /* First block.  */
      if (i == pos / blocksize) {
         skipfirst = blockoff;
         blockend -= skipfirst;
      }

      /* If the block number is 0 this block is not stored on disk but
         is zero filled instead.  */
      if (blknr) {
         err = part_read(node->data->part, blknr,
                         skipfirst, blockend, buf);
         if (err != ERR_NONE) {
            return err;
         }
      } else {
         memset(buf, 0, blocksize - skipfirst);
      }

      buf += blocksize - skipfirst;
   }

   return ERR_NONE;
}
Exemple #16
0
static grub_disk_addr_t
grub_ext2_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
{
  struct grub_ext2_data *data = node->data;
  struct grub_ext2_inode *inode = &node->inode;
  int blknr = -1;
  unsigned int blksz = EXT2_BLOCK_SIZE (data);
  int log2_blksz = LOG2_EXT2_BLOCK_SIZE (data);

  if (grub_le_to_cpu32(inode->flags) & EXT4_EXTENTS_FLAG)
    {
      char buf[EXT2_BLOCK_SIZE(data)];
      struct grub_ext4_extent_header *leaf;
      struct grub_ext4_extent *ext;
      int i;

      leaf = grub_ext4_find_leaf (data, buf,
                                  (struct grub_ext4_extent_header *) inode->blocks.dir_blocks,
                                  fileblock);
      if (! leaf)
        {
          grub_error (GRUB_ERR_BAD_FS, "invalid extent");
          return -1;
        }

      ext = (struct grub_ext4_extent *) (leaf + 1);
      for (i = 0; i < grub_le_to_cpu16 (leaf->entries); i++)
        {
          if (fileblock < grub_le_to_cpu32 (ext[i].block))
            break;
        }

      if (--i >= 0)
        {
          fileblock -= grub_le_to_cpu32 (ext[i].block);
          if (fileblock >= grub_le_to_cpu16 (ext[i].len))
            return 0;
          else
            {
              grub_disk_addr_t start;

              start = grub_le_to_cpu16 (ext[i].start_hi);
              start = (start << 32) + grub_le_to_cpu32 (ext[i].start);

              return fileblock + start;
            }
        }
      else
        {
          grub_error (GRUB_ERR_BAD_FS, "something wrong with extent");
          return -1;
        }
    }
  /* Direct blocks.  */
  if (fileblock < INDIRECT_BLOCKS)
    blknr = grub_le_to_cpu32 (inode->blocks.dir_blocks[fileblock]);
  /* Indirect.  */
  else if (fileblock < INDIRECT_BLOCKS + blksz / 4)
    {
      grub_uint32_t indir[blksz / 4];

      if (grub_disk_read (data->disk,
			  ((grub_disk_addr_t)
			   grub_le_to_cpu32 (inode->blocks.indir_block))
			  << log2_blksz,
			  0, blksz, indir))
	return grub_errno;

      blknr = grub_le_to_cpu32 (indir[fileblock - INDIRECT_BLOCKS]);
    }
  /* Double indirect.  */
  else if (fileblock < INDIRECT_BLOCKS + blksz / 4 * (blksz / 4 + 1))
    {
      unsigned int perblock = blksz / 4;
      unsigned int rblock = fileblock - (INDIRECT_BLOCKS
					 + blksz / 4);
      grub_uint32_t indir[blksz / 4];

      if (grub_disk_read (data->disk,
			  ((grub_disk_addr_t)
			   grub_le_to_cpu32 (inode->blocks.double_indir_block))
			  << log2_blksz,
			  0, blksz, indir))
	return grub_errno;

      if (grub_disk_read (data->disk,
			  ((grub_disk_addr_t)
			   grub_le_to_cpu32 (indir[rblock / perblock]))
			  << log2_blksz,
			  0, blksz, indir))
	return grub_errno;


      blknr = grub_le_to_cpu32 (indir[rblock % perblock]);
    }
  /* triple indirect.  */
  else
    {
      grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
		  "ext2fs doesn't support triple indirect blocks");
    }

  return blknr;
}
Exemple #17
0
static int ext2fs_read_block (ext2fs_node_t node, int fileblock, int *stream) {
#else
static int ext2fs_read_block (ext2fs_node_t node, int fileblock) {
#endif
	struct ext2_data *data = node->data;
	struct ext2_inode *inode = &node->inode;
	int blknr;
	int blksz = EXT2_BLOCK_SIZE (data);
	int log2_blksz = LOG2_EXT2_BLOCK_SIZE (data);
	int status;

#ifdef CFG_OPTIMIZE_EXT2_READ
       *stream = 1;/* itself */
#endif

	/* Direct blocks.  */
	if (fileblock < INDIRECT_BLOCKS) {
		blknr = __le32_to_cpu (inode->b.blocks.dir_blocks[fileblock]);
#ifdef CFG_OPTIMIZE_EXT2_READ
               while(((inode->b.blocks.dir_blocks[fileblock + 1] - 
                       inode->b.blocks.dir_blocks[fileblock]) == 1) && 
                        (fileblock < INDIRECT_BLOCKS - 1)) {
                       fileblock++;
                       *stream += 1;
               }
#endif
	}
	/* Indirect.  */
	else if (fileblock < (INDIRECT_BLOCKS + (blksz / 4))) {
		if (indir1_block == NULL) {
			indir1_block = (uint32_t *) malloc (blksz);
			if (indir1_block == NULL) {
				printf ("** ext2fs read block (indir 1) malloc failed. **\n");
				return (-1);
			}
			indir1_size = blksz;
			indir1_blkno = -1;
		}
		if (blksz != indir1_size) {
			free (indir1_block);
			indir1_block = NULL;
			indir1_size = 0;
			indir1_blkno = -1;
			indir1_block = (uint32_t *) malloc (blksz);
			if (indir1_block == NULL) {
				printf ("** ext2fs read block (indir 1) malloc failed. **\n");
				return (-1);
			}
			indir1_size = blksz;
		}
		if ((__le32_to_cpu (inode->b.blocks.indir_block) <<
		     log2_blksz) != indir1_blkno) {
			status = ext2fs_devread (__le32_to_cpu(inode->b.blocks.indir_block) << log2_blksz,
						 0, blksz,
						 (char *) indir1_block);
			if (status == 0) {
				printf ("** ext2fs read block (indir 1) failed. **\n");
				return (0);
			}
			indir1_blkno =
				__le32_to_cpu (inode->b.blocks.
					       indir_block) << log2_blksz;
		}
		blknr = __le32_to_cpu (indir1_block
				       [fileblock - INDIRECT_BLOCKS]);
#ifdef CFG_OPTIMIZE_EXT2_READ
               while(((__le32_to_cpu (indir1_block[fileblock - INDIRECT_BLOCKS + 1]) - \
                       __le32_to_cpu (indir1_block[fileblock - INDIRECT_BLOCKS])) == 1) && (fileblock < (blksz - 1))) {
                       fileblock++;
                       *stream += 1;
               }
#endif
	}
	/* Double indirect.  */
	else if (fileblock <
		 (INDIRECT_BLOCKS + (blksz / 4 * (blksz / 4 + 1)))) {
		unsigned int perblock = blksz / 4;
		unsigned int rblock = fileblock - (INDIRECT_BLOCKS
						   + blksz / 4);
#ifdef CFG_OPTIMIZE_EXT2_READ
        int rbcnt = 0;
#endif

		if (indir1_block == NULL) {
			indir1_block = (uint32_t *) malloc (blksz);
			if (indir1_block == NULL) {
				printf ("** ext2fs read block (indir 2 1) malloc failed. **\n");
				return (-1);
			}
			indir1_size = blksz;
			indir1_blkno = -1;
		}
		if (blksz != indir1_size) {
			free (indir1_block);
			indir1_block = NULL;
			indir1_size = 0;
			indir1_blkno = -1;
			indir1_block = (uint32_t *) malloc (blksz);
			if (indir1_block == NULL) {
				printf ("** ext2fs read block (indir 2 1) malloc failed. **\n");
				return (-1);
			}
			indir1_size = blksz;
		}
		if ((__le32_to_cpu (inode->b.blocks.double_indir_block) <<
		     log2_blksz) != indir1_blkno) {
			status = ext2fs_devread (__le32_to_cpu(inode->b.blocks.double_indir_block) << log2_blksz,
						0, blksz,
						(char *) indir1_block);
			if (status == 0) {
				printf ("** ext2fs read block (indir 2 1) failed. **\n");
				return (-1);
			}
			indir1_blkno =
				__le32_to_cpu (inode->b.blocks.double_indir_block) << log2_blksz;
		}

		if (indir2_block == NULL) {
			indir2_block = (uint32_t *) malloc (blksz);
			if (indir2_block == NULL) {
				printf ("** ext2fs read block (indir 2 2) malloc failed. **\n");
				return (-1);
			}
			indir2_size = blksz;
			indir2_blkno = -1;
		}
		if (blksz != indir2_size) {
			free (indir2_block);
			indir2_block = NULL;
			indir2_size = 0;
			indir2_blkno = -1;
			indir2_block = (uint32_t *) malloc (blksz);
			if (indir2_block == NULL) {
				printf ("** ext2fs read block (indir 2 2) malloc failed. **\n");
				return (-1);
			}
			indir2_size = blksz;
		}
		if ((__le32_to_cpu (indir1_block[rblock / perblock]) <<
		     log2_blksz) != indir1_blkno) {
			status = ext2fs_devread (__le32_to_cpu(indir1_block[rblock / perblock]) << log2_blksz,
						 0, blksz,
						 (char *) indir2_block);
			if (status == 0) {
				printf ("** ext2fs read block (indir 2 2) failed. **\n");
				return (-1);
			}
			indir2_blkno =
				__le32_to_cpu (indir1_block[rblock / perblock]) << log2_blksz;
		}
		blknr = __le32_to_cpu (indir2_block[rblock % perblock]);
#ifdef CFG_OPTIMIZE_EXT2_READ
               rbcnt = rblock % perblock;
               while(((__le32_to_cpu (indir2_block[rbcnt + 1]) - \
                       __le32_to_cpu (indir2_block[rbcnt])) == 1) && (rbcnt < (blksz - 1))) {
                       rbcnt++;
                       *stream += 1;
               }
#endif
	}
	/* Tripple indirect.  */
	else {
		printf ("** ext2fs doesn't support tripple indirect blocks. **\n");
		return (-1);
	}
#ifdef DEBUG
	printf ("ext2fs_read_block %08x\n", blknr);
#endif
	return (blknr);
}

#ifdef CFG_OPTIMIZE_EXT2_READ
int ext2fs_read_file
       (ext2fs_node_t node, int pos, unsigned int len, char *buf) {
       int log2blocksize = LOG2_EXT2_BLOCK_SIZE (node->data);
       int blocksize = 1 << (log2blocksize + DISK_SECTOR_BITS);
       unsigned int filesize = __le32_to_cpu(node->inode.size);
       int blknr;
       int blockend;
       int status;
       int remain = len;
       char *buffer = buf;
       int stream = 0;
       int cur = pos / blocksize;
       int blockoff = pos % blocksize;

       /* Adjust len so it we can't read past the end of the file.  */
       if (len > filesize) {
               len = filesize;
       }

       while (remain > 0) {
               blknr = ext2fs_read_block (node, cur, &stream);
               if (blknr < 0) {
                       return (-1);
               }
               blknr = blknr << log2blocksize; 
       
               if(remain < blocksize * stream) {
                       blockend = remain;
               } else {
                       blockend = blocksize * stream;
               }
               
               status = ext2fs_devread (blknr, blockoff, blockend, buffer);
               if (status == 0) {
                       return (-1);
               }
       
               remain -= blockend;
               buffer += blockend;
               cur += stream;
               blockoff = 0;
       
               if(remain == 0)
                       return (len);
               else if(remain < 0)
                       return (-1);
       }
       return (len);
}
Exemple #18
0
static quik_err_t
ext2fs_read_block(ext2fs_node_t node,
                  int fileblock,
                  unsigned *block_nr)
{
   struct ext2_data *data = node->data;
   struct ext2_inode *inode = &node->inode;
   unsigned blknr;
   int blksz = EXT2_BLOCK_SIZE(data);
   int log2_blksz = LOG2_EXT2_BLOCK_SIZE(data);
   quik_err_t err;

   /* Direct blocks.  */
   if (fileblock < INDIRECT_BLOCKS) {
      blknr = __le32_to_cpu(inode->b.blocks.dir_blocks[fileblock]);
   }

   /* Indirect.  */
   else if(fileblock < (INDIRECT_BLOCKS + (blksz / 4))) {
      if (indir1_block == NULL) {
         indir1_block = (uint32_t *) malloc(blksz);
         if (indir1_block == NULL) {
            return ERR_NO_MEM;
         }

         indir1_size = blksz;
         indir1_blkno = -1;
      }

      if (blksz != indir1_size) {
         free(indir1_block);
         indir1_block = NULL;
         indir1_size = 0;
         indir1_blkno = -1;
         indir1_block = (uint32_t *) malloc(blksz);
         if (indir1_block == NULL) {
            return ERR_NO_MEM;
         }

         indir1_size = blksz;
      }

      if ((__le32_to_cpu(inode->b.blocks.indir_block) <<
           log2_blksz) != indir1_blkno) {
         err = part_read(data->part,
                         __le32_to_cpu(inode->b.blocks.indir_block) << log2_blksz,
                         0, blksz,
                         (char *) indir1_block);
         if (err != ERR_NONE) {
            return err;
         }

         indir1_blkno =
            __le32_to_cpu(inode->b.blocks.
                          indir_block) << log2_blksz;
      }

      blknr = __le32_to_cpu(indir1_block
                            [fileblock - INDIRECT_BLOCKS]);
   }

   /* Double indirect.  */
   else if (fileblock <
            (INDIRECT_BLOCKS + (blksz / 4 * (blksz / 4 + 1)))) {
      unsigned int perblock = blksz / 4;
      unsigned int rblock = fileblock - (INDIRECT_BLOCKS
                                         + blksz / 4);

      if (indir1_block == NULL) {
         indir1_block = (uint32_t *) malloc(blksz);
         if (indir1_block == NULL) {
            return ERR_NO_MEM;
         }
         indir1_size = blksz;
         indir1_blkno = -1;
      }

      if (blksz != indir1_size) {
         free(indir1_block);
         indir1_block = NULL;
         indir1_size = 0;
         indir1_blkno = -1;
         indir1_block = (uint32_t *) malloc(blksz);
         if (indir1_block == NULL) {
            return ERR_NO_MEM;
         }

         indir1_size = blksz;
      }

      if ((__le32_to_cpu(inode->b.blocks.double_indir_block) <<
           log2_blksz) != indir1_blkno) {
         err = part_read(data->part,
                         __le32_to_cpu(inode->b.blocks.double_indir_block) << log2_blksz,
                         0, blksz,
                         (char *) indir1_block);
         if (err != ERR_NONE) {
            return err;
         }

         indir1_blkno =
            __le32_to_cpu(inode->b.blocks.double_indir_block) << log2_blksz;
      }

      if (indir2_block == NULL) {
         indir2_block = (uint32_t *) malloc(blksz);
         if (indir2_block == NULL) {
            return ERR_NO_MEM;
         }
         indir2_size = blksz;
         indir2_blkno = -1;
      }

      if (blksz != indir2_size) {
         free(indir2_block);
         indir2_block = NULL;
         indir2_size = 0;
         indir2_blkno = -1;
         indir2_block = (uint32_t *) malloc(blksz);
         if (indir2_block == NULL) {
            return ERR_NO_MEM;
         }

         indir2_size = blksz;
      }
      if ((__le32_to_cpu(indir1_block[rblock / perblock]) <<
           log2_blksz) != indir2_blkno) {
         err = part_read(data->part,
                         __le32_to_cpu(indir1_block[rblock / perblock]) << log2_blksz,
                         0, blksz,
                         (char *) indir2_block);
         if (err != ERR_NONE) {
            return err;
         }

         indir2_blkno =
            __le32_to_cpu(indir1_block[rblock / perblock]) << log2_blksz;
      }

      blknr = __le32_to_cpu(indir2_block[rblock % perblock]);
   }

   /* Triple indirect.  */
   else {
      return ERR_FS_CORRUPT;
   }
#ifdef DEBUG
   printk("ext2fs_read_block %x\n", blknr);
#endif

   *block_nr = blknr;
   return ERR_NONE;
}
Exemple #19
0
long int read_allocated_block(struct ext2_inode *inode, int fileblock)
{
	long int blknr;
	int blksz;
	int log2_blksz;
	int status;
	long int rblock;
	long int perblock_parent;
	long int perblock_child;
	unsigned long long start;
	/* get the blocksize of the filesystem */
	blksz = EXT2_BLOCK_SIZE(ext4fs_root);
	log2_blksz = LOG2_EXT2_BLOCK_SIZE(ext4fs_root);
	if (le32_to_cpu(inode->flags) & EXT4_EXTENTS_FL) {
		char *buf = zalloc(blksz);
		if (!buf)
			return -ENOMEM;
		struct ext4_extent_header *ext_block;
		struct ext4_extent *extent;
		int i = -1;
		ext_block = ext4fs_get_extent_block(ext4fs_root, buf,
						    (struct ext4_extent_header
						     *)inode->b.
						    blocks.dir_blocks,
						    fileblock, log2_blksz);
		if (!ext_block) {
			printf("invalid extent block\n");
			free(buf);
			return -EINVAL;
		}

		extent = (struct ext4_extent *)(ext_block + 1);

		do {
			i++;
			if (i >= le32_to_cpu(ext_block->eh_entries))
				break;
		} while (fileblock >= le32_to_cpu(extent[i].ee_block));
		if (--i >= 0) {
			fileblock -= le32_to_cpu(extent[i].ee_block);
			if (fileblock >= le32_to_cpu(extent[i].ee_len)) {
				free(buf);
				return 0;
			}

			start = le32_to_cpu(extent[i].ee_start_hi);
			start = (start << 32) +
			    le32_to_cpu(extent[i].ee_start_lo);
			free(buf);
			return fileblock + start;
		}

		printf("Extent Error\n");
		free(buf);
		return -1;
	}

	/* Direct blocks. */
	if (fileblock < INDIRECT_BLOCKS)
		blknr = __le32_to_cpu(inode->b.blocks.dir_blocks[fileblock]);

	/* Indirect. */
	else if (fileblock < (INDIRECT_BLOCKS + (blksz / 4))) {
		if (ext4fs_indir1_block == NULL) {
			ext4fs_indir1_block = zalloc(blksz);
			if (ext4fs_indir1_block == NULL) {
				printf("** SI ext2fs read block (indir 1)"
				       "malloc failed. **\n");
				return -1;
			}
			ext4fs_indir1_size = blksz;
			ext4fs_indir1_blkno = -1;
		}
		if (blksz != ext4fs_indir1_size) {
			free(ext4fs_indir1_block);
			ext4fs_indir1_block = NULL;
			ext4fs_indir1_size = 0;
			ext4fs_indir1_blkno = -1;
			ext4fs_indir1_block = zalloc(blksz);
			if (ext4fs_indir1_block == NULL) {
				printf("** SI ext2fs read block (indir 1):"
				       "malloc failed. **\n");
				return -1;
			}
			ext4fs_indir1_size = blksz;
		}
		if ((__le32_to_cpu(inode->b.blocks.indir_block) <<
		     log2_blksz) != ext4fs_indir1_blkno) {
			status =
			    ext4fs_devread(__le32_to_cpu
					   (inode->b.blocks.
					    indir_block) << log2_blksz, 0,
					   blksz, (char *)ext4fs_indir1_block);
			if (status == 0) {
				printf("** SI ext2fs read block (indir 1)"
				       "failed. **\n");
				return 0;
			}
			ext4fs_indir1_blkno =
			    __le32_to_cpu(inode->b.blocks.
					  indir_block) << log2_blksz;
		}
		blknr = __le32_to_cpu(ext4fs_indir1_block
				      [fileblock - INDIRECT_BLOCKS]);
	}
	/* Double indirect. */
	else if (fileblock < (INDIRECT_BLOCKS + (blksz / 4 *
					(blksz / 4 + 1)))) {

		long int perblock = blksz / 4;
		long int rblock = fileblock - (INDIRECT_BLOCKS + blksz / 4);

		if (ext4fs_indir1_block == NULL) {
			ext4fs_indir1_block = zalloc(blksz);
			if (ext4fs_indir1_block == NULL) {
				printf("** DI ext2fs read block (indir 2 1)"
				       "malloc failed. **\n");
				return -1;
			}
			ext4fs_indir1_size = blksz;
			ext4fs_indir1_blkno = -1;
		}
		if (blksz != ext4fs_indir1_size) {
			free(ext4fs_indir1_block);
			ext4fs_indir1_block = NULL;
			ext4fs_indir1_size = 0;
			ext4fs_indir1_blkno = -1;
			ext4fs_indir1_block = zalloc(blksz);
			if (ext4fs_indir1_block == NULL) {
				printf("** DI ext2fs read block (indir 2 1)"
				       "malloc failed. **\n");
				return -1;
			}
			ext4fs_indir1_size = blksz;
		}
		if ((__le32_to_cpu(inode->b.blocks.double_indir_block) <<
		     log2_blksz) != ext4fs_indir1_blkno) {
			status =
			    ext4fs_devread(__le32_to_cpu
					   (inode->b.blocks.
					    double_indir_block) << log2_blksz,
					   0, blksz,
					   (char *)ext4fs_indir1_block);
			if (status == 0) {
				printf("** DI ext2fs read block (indir 2 1)"
				       "failed. **\n");
				return -1;
			}
			ext4fs_indir1_blkno =
			    __le32_to_cpu(inode->b.blocks.double_indir_block) <<
			    log2_blksz;
		}

		if (ext4fs_indir2_block == NULL) {
			ext4fs_indir2_block = zalloc(blksz);
			if (ext4fs_indir2_block == NULL) {
				printf("** DI ext2fs read block (indir 2 2)"
				       "malloc failed. **\n");
				return -1;
			}
			ext4fs_indir2_size = blksz;
			ext4fs_indir2_blkno = -1;
		}
		if (blksz != ext4fs_indir2_size) {
			free(ext4fs_indir2_block);
			ext4fs_indir2_block = NULL;
			ext4fs_indir2_size = 0;
			ext4fs_indir2_blkno = -1;
			ext4fs_indir2_block = zalloc(blksz);
			if (ext4fs_indir2_block == NULL) {
				printf("** DI ext2fs read block (indir 2 2)"
				       "malloc failed. **\n");
				return -1;
			}
			ext4fs_indir2_size = blksz;
		}
		if ((__le32_to_cpu(ext4fs_indir1_block[rblock / perblock]) <<
		     log2_blksz) != ext4fs_indir2_blkno) {
			status = ext4fs_devread(__le32_to_cpu
						(ext4fs_indir1_block
						 [rblock /
						  perblock]) << log2_blksz, 0,
						blksz,
						(char *)ext4fs_indir2_block);
			if (status == 0) {
				printf("** DI ext2fs read block (indir 2 2)"
				       "failed. **\n");
				return -1;
			}
			ext4fs_indir2_blkno =
			    __le32_to_cpu(ext4fs_indir1_block[rblock
							      /
							      perblock]) <<
			    log2_blksz;
		}
		blknr = __le32_to_cpu(ext4fs_indir2_block[rblock % perblock]);
	}
	/* Tripple indirect. */
	else {
		rblock = fileblock - (INDIRECT_BLOCKS + blksz / 4 +
				      (blksz / 4 * blksz / 4));
		perblock_child = blksz / 4;
		perblock_parent = ((blksz / 4) * (blksz / 4));

		if (ext4fs_indir1_block == NULL) {
			ext4fs_indir1_block = zalloc(blksz);
			if (ext4fs_indir1_block == NULL) {
				printf("** TI ext2fs read block (indir 2 1)"
				       "malloc failed. **\n");
				return -1;
			}
			ext4fs_indir1_size = blksz;
			ext4fs_indir1_blkno = -1;
		}
		if (blksz != ext4fs_indir1_size) {
			free(ext4fs_indir1_block);
			ext4fs_indir1_block = NULL;
			ext4fs_indir1_size = 0;
			ext4fs_indir1_blkno = -1;
			ext4fs_indir1_block = zalloc(blksz);
			if (ext4fs_indir1_block == NULL) {
				printf("** TI ext2fs read block (indir 2 1)"
				       "malloc failed. **\n");
				return -1;
			}
			ext4fs_indir1_size = blksz;
		}
		if ((__le32_to_cpu(inode->b.blocks.triple_indir_block) <<
		     log2_blksz) != ext4fs_indir1_blkno) {
			status = ext4fs_devread
			    (__le32_to_cpu(inode->b.blocks.triple_indir_block)
			     << log2_blksz, 0, blksz,
			     (char *)ext4fs_indir1_block);
			if (status == 0) {
				printf("** TI ext2fs read block (indir 2 1)"
				       "failed. **\n");
				return -1;
			}
			ext4fs_indir1_blkno =
			    __le32_to_cpu(inode->b.blocks.triple_indir_block) <<
			    log2_blksz;
		}

		if (ext4fs_indir2_block == NULL) {
			ext4fs_indir2_block = zalloc(blksz);
			if (ext4fs_indir2_block == NULL) {
				printf("** TI ext2fs read block (indir 2 2)"
				       "malloc failed. **\n");
				return -1;
			}
			ext4fs_indir2_size = blksz;
			ext4fs_indir2_blkno = -1;
		}
		if (blksz != ext4fs_indir2_size) {
			free(ext4fs_indir2_block);
			ext4fs_indir2_block = NULL;
			ext4fs_indir2_size = 0;
			ext4fs_indir2_blkno = -1;
			ext4fs_indir2_block = zalloc(blksz);
			if (ext4fs_indir2_block == NULL) {
				printf("** TI ext2fs read block (indir 2 2)"
				       "malloc failed. **\n");
				return -1;
			}
			ext4fs_indir2_size = blksz;
		}
		if ((__le32_to_cpu(ext4fs_indir1_block[rblock /
						       perblock_parent]) <<
		     log2_blksz)
		    != ext4fs_indir2_blkno) {
			status = ext4fs_devread(__le32_to_cpu
						(ext4fs_indir1_block
						 [rblock /
						  perblock_parent]) <<
						log2_blksz, 0, blksz,
						(char *)ext4fs_indir2_block);
			if (status == 0) {
				printf("** TI ext2fs read block (indir 2 2)"
				       "failed. **\n");
				return -1;
			}
			ext4fs_indir2_blkno =
			    __le32_to_cpu(ext4fs_indir1_block[rblock /
							      perblock_parent])
			    << log2_blksz;
		}

		if (ext4fs_indir3_block == NULL) {
			ext4fs_indir3_block = zalloc(blksz);
			if (ext4fs_indir3_block == NULL) {
				printf("** TI ext2fs read block (indir 2 2)"
				       "malloc failed. **\n");
				return -1;
			}
			ext4fs_indir3_size = blksz;
			ext4fs_indir3_blkno = -1;
		}
		if (blksz != ext4fs_indir3_size) {
			free(ext4fs_indir3_block);
			ext4fs_indir3_block = NULL;
			ext4fs_indir3_size = 0;
			ext4fs_indir3_blkno = -1;
			ext4fs_indir3_block = zalloc(blksz);
			if (ext4fs_indir3_block == NULL) {
				printf("** TI ext2fs read block (indir 2 2)"
				       "malloc failed. **\n");
				return -1;
			}
			ext4fs_indir3_size = blksz;
		}
		if ((__le32_to_cpu(ext4fs_indir2_block[rblock
						       /
						       perblock_child]) <<
		     log2_blksz) != ext4fs_indir3_blkno) {
			status =
			    ext4fs_devread(__le32_to_cpu
					   (ext4fs_indir2_block
					    [(rblock / perblock_child)
					     % (blksz / 4)]) << log2_blksz, 0,
					   blksz, (char *)ext4fs_indir3_block);
			if (status == 0) {
				printf("** TI ext2fs read block (indir 2 2)"
				       "failed. **\n");
				return -1;
			}
			ext4fs_indir3_blkno =
			    __le32_to_cpu(ext4fs_indir2_block[(rblock /
							       perblock_child) %
							      (blksz /
							       4)]) <<
			    log2_blksz;
		}

		blknr = __le32_to_cpu(ext4fs_indir3_block
				      [rblock % perblock_child]);
	}
	debug("ext4fs_read_block %ld\n", blknr);

	return blknr;
}
Exemple #20
0
long int read_allocated_block(struct ext2fs_node *node, int fileblock)
{
	long int blknr;
	int blksz;
	int log2_blksz;
	long int rblock;
	long int perblock_parent;
	long int perblock_child;
	unsigned long long start;
	struct ext2_inode *inode = &node->inode;
	struct ext2_data *data = node->data;
	int ret;

	/* get the blocksize of the filesystem */
	blksz = EXT2_BLOCK_SIZE(node->data);
	log2_blksz = LOG2_EXT2_BLOCK_SIZE(node->data);

	if (le32_to_cpu(inode->flags) & EXT4_EXTENTS_FL) {
		char *buf = zalloc(blksz);
		struct ext4_extent_header *ext_block;
		struct ext4_extent *extent;
		int i = -1;

		if (!buf)
			return -ENOMEM;

		ext_block = ext4fs_get_extent_block(node->data, buf,
				(struct ext4_extent_header *)inode->b.blocks.dir_blocks,
				fileblock, log2_blksz);
		if (!ext_block) {
			pr_err("invalid extent block\n");
			free(buf);
			return -EINVAL;
		}

		extent = (struct ext4_extent *)(ext_block + 1);

		do {
			i++;
			if (i >= le32_to_cpu(ext_block->eh_entries))
				break;
		} while (fileblock >= le32_to_cpu(extent[i].ee_block));

		if (--i >= 0) {
			fileblock -= le32_to_cpu(extent[i].ee_block);
			if (fileblock >= le32_to_cpu(extent[i].ee_len)) {
				free(buf);
				return 0;
			}

			start = le32_to_cpu(extent[i].ee_start_hi);
			start = (start << 32) +
					le32_to_cpu(extent[i].ee_start_lo);
			free(buf);
			return fileblock + start;
		}

		free(buf);
		return -EIO;
	}

	if (fileblock < INDIRECT_BLOCKS) {
		/* Direct blocks. */
		blknr = __le32_to_cpu(inode->b.blocks.dir_blocks[fileblock]);
	} else if (fileblock < (INDIRECT_BLOCKS + (blksz / 4))) {
		/* Indirect. */
		ret = ext4fs_get_indir_block(node, &data->indir1,
				__le32_to_cpu(inode->b.blocks.indir_block) << log2_blksz);
		if (ret)
			return ret;
		blknr = __le32_to_cpu(data->indir1.data[fileblock - INDIRECT_BLOCKS]);
	} else if (fileblock < (INDIRECT_BLOCKS + (blksz / 4 *
					(blksz / 4 + 1)))) {
		/* Double indirect. */
		long int perblock = blksz / 4;
		long int rblock = fileblock - (INDIRECT_BLOCKS + blksz / 4);

		ret = ext4fs_get_indir_block(node, &data->indir1,
				__le32_to_cpu(inode->b.blocks.double_indir_block) << log2_blksz);
		if (ret)
			return ret;

		ret = ext4fs_get_indir_block(node, &data->indir2,
				__le32_to_cpu(data->indir1.data[rblock / perblock]) << log2_blksz);
		if (ret)
			return ret;

		blknr = __le32_to_cpu(data->indir2.data[rblock % perblock]);
	} else {
		/* Triple indirect. */
		rblock = fileblock - (INDIRECT_BLOCKS + blksz / 4 +
				      (blksz / 4 * blksz / 4));
		perblock_child = blksz / 4;
		perblock_parent = ((blksz / 4) * (blksz / 4));

		ret = ext4fs_get_indir_block(node, &data->indir1,
				__le32_to_cpu(inode->b.blocks.triple_indir_block) << log2_blksz);
		if (ret)
			return ret;

		ret = ext4fs_get_indir_block(node, &data->indir2,
				__le32_to_cpu(data->indir1.data[rblock / perblock_parent]) << log2_blksz);
		if (ret)
			return ret;

		ret = ext4fs_get_indir_block(node, &data->indir3,
				__le32_to_cpu(data->indir2.data[rblock / perblock_child]) << log2_blksz);
		if (ret)
			return ret;

		blknr = __le32_to_cpu(data->indir3.data[rblock % perblock_child]);
	}

	return blknr;
}