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); }
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; }
/* 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; }
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); }
/* 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); }
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)); }
/* 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)); }
/* 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)); }
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; }
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)); }
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); }
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; } }
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); }
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); }
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; }
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; }
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); }
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; }
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; }
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; }