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; }
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; }