/* * This function parses the journal blocks and replays the * suceessful transactions. A transaction is successfull * if commit block is found for a descriptor block * The tags in descriptor block contain the disk block * numbers of the metadata to be replayed */ void recover_transaction(int prev_desc_logical_no) { struct ext2_inode inode_journal; struct ext_filesystem *fs = get_fs(); struct journal_header_t *jdb; long int blknr; char *p_jdb; int ofs, flags; int i; struct ext3_journal_block_tag *tag; char *temp_buff = zalloc(fs->blksz); char *metadata_buff = zalloc(fs->blksz); if (!temp_buff || !metadata_buff) goto fail; i = prev_desc_logical_no; ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, (struct ext2_inode *)&inode_journal); blknr = read_allocated_block((struct ext2_inode *) &inode_journal, i, NULL); ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz, temp_buff); p_jdb = (char *)temp_buff; jdb = (struct journal_header_t *) temp_buff; ofs = sizeof(struct journal_header_t); do { tag = (struct ext3_journal_block_tag *)(p_jdb + ofs); ofs += sizeof(struct ext3_journal_block_tag); if (ofs > fs->blksz) break; flags = be32_to_cpu(tag->flags); if (!(flags & EXT3_JOURNAL_FLAG_SAME_UUID)) ofs += 16; i++; debug("\t\ttag %u\n", be32_to_cpu(tag->block)); if (revk_blk_list != NULL) { if (check_blknr_for_revoke(be32_to_cpu(tag->block), be32_to_cpu(jdb->h_sequence)) == 0) continue; } blknr = read_allocated_block(&inode_journal, i, NULL); ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz, metadata_buff); put_ext4((uint64_t)((uint64_t)be32_to_cpu(tag->block) * (uint64_t)fs->blksz), metadata_buff, (uint32_t) fs->blksz); } while (!(flags & EXT3_JOURNAL_FLAG_LAST_TAG)); fail: free(temp_buff); free(metadata_buff); }
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; }
static void update_commit_block(long int blknr) { struct journal_header_t jdb; struct ext_filesystem *fs = get_fs(); char *buf = NULL; struct ext2_inode inode_journal; struct journal_superblock_t *jsb; long int jsb_blknr; char *temp_buff = zalloc(fs->blksz); if (!temp_buff) return; ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal); jsb_blknr = read_allocated_block(&inode_journal, EXT2_JOURNAL_SUPERBLOCK, NULL); ext4fs_devread((lbaint_t)jsb_blknr * fs->sect_perblk, 0, fs->blksz, temp_buff); jsb = (struct journal_superblock_t *) temp_buff; jdb.h_blocktype = cpu_to_be32(EXT3_JOURNAL_COMMIT_BLOCK); jdb.h_magic = cpu_to_be32(EXT3_JOURNAL_MAGIC_NUMBER); jdb.h_sequence = jsb->s_sequence; buf = zalloc(fs->blksz); if (!buf) { free(temp_buff); return; } memcpy(buf, &jdb, sizeof(struct journal_header_t)); put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)fs->blksz), buf, (uint32_t) fs->blksz); free(temp_buff); free(buf); }
int ext4fs_mount(struct ext_filesystem *fs) { struct ext2_data *data; int ret, blksz; data = zalloc(sizeof(struct ext2_data)); if (!data) return -ENOMEM; /* Read the superblock. */ ret = ext4fs_devread(fs, 1 * 2, 0, sizeof(struct ext2_sblock), (char *)&data->sblock); if (ret) goto fail; /* Make sure this is an ext2 filesystem. */ if (__le16_to_cpu(data->sblock.magic) != EXT2_MAGIC) { ret = -EINVAL; goto fail; } if (__le32_to_cpu(data->sblock.revision_level == 0)) fs->inodesz = 128; else fs->inodesz = __le16_to_cpu(data->sblock.inode_size); dev_info(fs->dev, "EXT2 rev %d, inode_size %d\n", __le32_to_cpu(data->sblock.revision_level), fs->inodesz); data->diropen.data = data; data->diropen.ino = 2; data->diropen.inode_read = 1; data->inode = &data->diropen.inode; data->fs = fs; fs->data = data; blksz = EXT2_BLOCK_SIZE(data); fs->data->indir1.data = malloc(blksz); fs->data->indir2.data = malloc(blksz); fs->data->indir3.data = malloc(blksz); if (!fs->data->indir1.data || !fs->data->indir2.data || !fs->data->indir3.data) { ret = -ENOMEM; goto fail; } ret = ext4fs_read_inode(data, 2, data->inode); if (ret) goto fail; return 0; fail: free(data); return ret; }
int ext4fs_init_journal(void) { int i; char *temp = NULL; struct ext_filesystem *fs = get_fs(); /* init globals */ revk_blk_list = NULL; prev_node = NULL; gindex = 0; gd_index = 0; jrnl_blk_idx = 1; for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) { journal_ptr[i] = zalloc(sizeof(struct journal_log)); if (!journal_ptr[i]) goto fail; dirty_block_ptr[i] = zalloc(sizeof(struct dirty_blocks)); if (!dirty_block_ptr[i]) goto fail; journal_ptr[i]->buf = NULL; journal_ptr[i]->blknr = -1; dirty_block_ptr[i]->buf = NULL; dirty_block_ptr[i]->blknr = -1; } if (fs->blksz == 4096) { temp = zalloc(fs->blksz); if (!temp) goto fail; journal_ptr[gindex]->buf = zalloc(fs->blksz); if (!journal_ptr[gindex]->buf) goto fail; ext4fs_devread(0, 0, fs->blksz, temp); memcpy(temp + SUPERBLOCK_SIZE, fs->sb, SUPERBLOCK_SIZE); memcpy(journal_ptr[gindex]->buf, temp, fs->blksz); journal_ptr[gindex++]->blknr = 0; free(temp); } else { journal_ptr[gindex]->buf = zalloc(fs->blksz); if (!journal_ptr[gindex]->buf) goto fail; memcpy(journal_ptr[gindex]->buf, fs->sb, SUPERBLOCK_SIZE); journal_ptr[gindex++]->blknr = 1; } /* Check the file system state using journal super block */ if (ext4fs_check_journal_state(SCAN)) goto fail; /* Check the file system state using journal super block */ if (ext4fs_check_journal_state(RECOVER)) goto fail; return 0; fail: return -1; }
int ext4_read_superblock(char *buffer) { struct ext_filesystem *fs = get_fs(); int sector = SUPERBLOCK_START >> fs->dev_desc->log2blksz; int offset = 0; ext4fs_devread(sector, offset, SUPERBLOCK_SIZE, buffer); return 0; }
static void update_descriptor_block(long int blknr) { int i; long int jsb_blknr; struct journal_header_t jdb; struct ext3_journal_block_tag tag; struct ext2_inode inode_journal; struct journal_superblock_t *jsb = NULL; char *buf = NULL; char *temp = NULL; struct ext_filesystem *fs = get_fs(); char *temp_buff = zalloc(fs->blksz); if (!temp_buff) return; ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal); jsb_blknr = read_allocated_block(&inode_journal, EXT2_JOURNAL_SUPERBLOCK, NULL); ext4fs_devread((lbaint_t)jsb_blknr * fs->sect_perblk, 0, fs->blksz, temp_buff); jsb = (struct journal_superblock_t *) temp_buff; jdb.h_blocktype = cpu_to_be32(EXT3_JOURNAL_DESCRIPTOR_BLOCK); jdb.h_magic = cpu_to_be32(EXT3_JOURNAL_MAGIC_NUMBER); jdb.h_sequence = jsb->s_sequence; buf = zalloc(fs->blksz); if (!buf) { free(temp_buff); return; } temp = buf; memcpy(buf, &jdb, sizeof(struct journal_header_t)); temp += sizeof(struct journal_header_t); for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) { if (journal_ptr[i]->blknr == -1) break; tag.block = cpu_to_be32(journal_ptr[i]->blknr); tag.flags = cpu_to_be32(EXT3_JOURNAL_FLAG_SAME_UUID); memcpy(temp, &tag, sizeof(struct ext3_journal_block_tag)); temp = temp + sizeof(struct ext3_journal_block_tag); } tag.block = cpu_to_be32(journal_ptr[--i]->blknr); tag.flags = cpu_to_be32(EXT3_JOURNAL_FLAG_LAST_TAG); memcpy(temp - sizeof(struct ext3_journal_block_tag), &tag, sizeof(struct ext3_journal_block_tag)); put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)fs->blksz), buf, (uint32_t) fs->blksz); free(temp_buff); free(buf); }
int ext4fs_mount(unsigned part_length) { struct ext2_data *data; int status; struct ext_filesystem *fs = get_fs(); data = zalloc(sizeof(struct ext2_data)); if (!data) return 0; /* Read the superblock. */ status = ext4fs_devread(1 * 2, 0, sizeof(struct ext2_sblock), (char *)&data->sblock); if (status == 0) goto fail; /* Make sure this is an ext2 filesystem. */ if (__le16_to_cpu(data->sblock.magic) != EXT2_MAGIC) goto fail; if (__le32_to_cpu(data->sblock.revision_level == 0)) fs->inodesz = 128; else fs->inodesz = __le16_to_cpu(data->sblock.inode_size); debug("EXT2 rev %d, inode_size %d\n", __le32_to_cpu(data->sblock.revision_level), fs->inodesz); data->diropen.data = data; data->diropen.ino = 2; data->diropen.inode_read = 1; data->inode = &data->diropen.inode; status = ext4fs_read_inode(data, 2, data->inode); if (status == 0) goto fail; ext4fs_root = data; return 1; fail: printf("Failed to mount ext2 filesystem...\n"); free(data); ext4fs_root = NULL; return 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); }
int ext4fs_get_indir_block(struct ext2fs_node *node, struct ext4fs_indir_block *indir, int blkno) { struct ext_filesystem *fs = node->data->fs; int blksz; int ret; blksz = EXT2_BLOCK_SIZE(node->data); if (indir->blkno == blkno) return 0; ret = ext4fs_devread(fs, blkno, 0, blksz, (void *)indir->data); if (ret) { dev_err(fs->dev, "** SI ext2fs read block (indir 1)" "failed. **\n"); return ret; } return 0; }
static struct ext4_extent_header *ext4fs_get_extent_block(struct ext2_data *data, char *buf, struct ext4_extent_header *ext_block, uint32_t fileblock, int log2_blksz) { struct ext4_extent_idx *index; unsigned long long block; struct ext_filesystem *fs = data->fs; int blksz = EXT2_BLOCK_SIZE(data); int i, ret; while (1) { index = (struct ext4_extent_idx *)(ext_block + 1); if (le16_to_cpu(ext_block->eh_magic) != EXT4_EXT_MAGIC) return 0; if (ext_block->eh_depth == 0) return ext_block; i = -1; do { i++; if (i >= le16_to_cpu(ext_block->eh_entries)) break; } while (fileblock >= le32_to_cpu(index[i].ei_block)); if (--i < 0) return 0; block = le16_to_cpu(index[i].ei_leaf_hi); block = (block << 32) + le32_to_cpu(index[i].ei_leaf_lo); ret = ext4fs_devread(fs, block << log2_blksz, 0, blksz, buf); if (ret) return NULL; else ext_block = (struct ext4_extent_header *)buf; } }
static struct ext4_extent_header *ext4fs_get_extent_block (struct ext2_data *data, char *buf, struct ext4_extent_header *ext_block, uint32_t fileblock, int log2_blksz) { struct ext4_extent_idx *index; unsigned long long block; struct ext_filesystem *fs = get_fs(); int i; while (1) { index = (struct ext4_extent_idx *)(ext_block + 1); if (le32_to_cpu(ext_block->eh_magic) != EXT4_EXT_MAGIC) return 0; if (ext_block->eh_depth == 0) return ext_block; i = -1; do { i++; if (i >= le32_to_cpu(ext_block->eh_entries)) break; } while (fileblock > le32_to_cpu(index[i].ei_block)); if (--i < 0) return 0; block = le32_to_cpu(index[i].ei_leaf_hi); block = (block << 32) + le32_to_cpu(index[i].ei_leaf_lo); if (ext4fs_devread(block << log2_blksz, 0, fs->blksz, buf)) ext_block = (struct ext4_extent_header *)buf; else return 0; } }
int ext4fs_check_journal_state(int recovery_flag) { int i; int DB_FOUND = NO; long int blknr; int transaction_state = TRANSACTION_COMPLETE; int prev_desc_logical_no = 0; int curr_desc_logical_no = 0; int ofs, flags; struct ext2_inode inode_journal; struct journal_superblock_t *jsb = NULL; struct journal_header_t *jdb = NULL; char *p_jdb = NULL; struct ext3_journal_block_tag *tag = NULL; char *temp_buff = NULL; char *temp_buff1 = NULL; struct ext_filesystem *fs = get_fs(); temp_buff = zalloc(fs->blksz); if (!temp_buff) return -ENOMEM; temp_buff1 = zalloc(fs->blksz); if (!temp_buff1) { free(temp_buff); return -ENOMEM; } ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal); blknr = read_allocated_block(&inode_journal, EXT2_JOURNAL_SUPERBLOCK, NULL); ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz, temp_buff); jsb = (struct journal_superblock_t *) temp_buff; if (le32_to_cpu(fs->sb->feature_incompat) & EXT3_FEATURE_INCOMPAT_RECOVER) { if (recovery_flag == RECOVER) printf("Recovery required\n"); } else { if (recovery_flag == RECOVER) printf("File System is consistent\n"); goto end; } if (be32_to_cpu(jsb->s_start) == 0) goto end; if (!(jsb->s_feature_compat & cpu_to_be32(JBD2_FEATURE_COMPAT_CHECKSUM))) jsb->s_feature_compat |= cpu_to_be32(JBD2_FEATURE_COMPAT_CHECKSUM); i = be32_to_cpu(jsb->s_first); while (1) { blknr = read_allocated_block(&inode_journal, i, NULL); memset(temp_buff1, '\0', fs->blksz); ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz, temp_buff1); jdb = (struct journal_header_t *) temp_buff1; if (be32_to_cpu(jdb->h_blocktype) == EXT3_JOURNAL_DESCRIPTOR_BLOCK) { if (be32_to_cpu(jdb->h_sequence) != be32_to_cpu(jsb->s_sequence)) { print_jrnl_status(recovery_flag); break; } curr_desc_logical_no = i; if (transaction_state == TRANSACTION_COMPLETE) transaction_state = TRANSACTION_RUNNING; else return -1; p_jdb = (char *)temp_buff1; ofs = sizeof(struct journal_header_t); do { tag = (struct ext3_journal_block_tag *) (p_jdb + ofs); ofs += sizeof(struct ext3_journal_block_tag); if (ofs > fs->blksz) break; flags = be32_to_cpu(tag->flags); if (!(flags & EXT3_JOURNAL_FLAG_SAME_UUID)) ofs += 16; i++; debug("\t\ttag %u\n", be32_to_cpu(tag->block)); } while (!(flags & EXT3_JOURNAL_FLAG_LAST_TAG)); i++; DB_FOUND = YES; } else if (be32_to_cpu(jdb->h_blocktype) == EXT3_JOURNAL_COMMIT_BLOCK) { if (be32_to_cpu(jdb->h_sequence) != be32_to_cpu(jsb->s_sequence)) { print_jrnl_status(recovery_flag); break; } if (transaction_state == TRANSACTION_RUNNING || (DB_FOUND == NO)) { transaction_state = TRANSACTION_COMPLETE; i++; jsb->s_sequence = cpu_to_be32(be32_to_cpu( jsb->s_sequence) + 1); } prev_desc_logical_no = curr_desc_logical_no; if ((recovery_flag == RECOVER) && (DB_FOUND == YES)) recover_transaction(prev_desc_logical_no); DB_FOUND = NO; } else if (be32_to_cpu(jdb->h_blocktype) == EXT3_JOURNAL_REVOKE_BLOCK) { if (be32_to_cpu(jdb->h_sequence) != be32_to_cpu(jsb->s_sequence)) { print_jrnl_status(recovery_flag); break; } if (recovery_flag == SCAN) ext4fs_push_revoke_blk((char *)jdb); i++; } else { debug("Else Case\n"); if (be32_to_cpu(jdb->h_sequence) != be32_to_cpu(jsb->s_sequence)) { print_jrnl_status(recovery_flag); break; } } } end: if (recovery_flag == RECOVER) { uint32_t new_feature_incompat; jsb->s_start = cpu_to_be32(1); jsb->s_sequence = cpu_to_be32(be32_to_cpu(jsb->s_sequence) + 1); /* get the superblock */ ext4_read_superblock((char *)fs->sb); new_feature_incompat = le32_to_cpu(fs->sb->feature_incompat); new_feature_incompat |= EXT3_FEATURE_INCOMPAT_RECOVER; fs->sb->feature_incompat = cpu_to_le32(new_feature_incompat); /* Update the super block */ put_ext4((uint64_t) (SUPERBLOCK_SIZE), (struct ext2_sblock *)fs->sb, (uint32_t) SUPERBLOCK_SIZE); ext4_read_superblock((char *)fs->sb); blknr = read_allocated_block(&inode_journal, EXT2_JOURNAL_SUPERBLOCK, NULL); put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)fs->blksz), (struct journal_superblock_t *)temp_buff, (uint32_t) fs->blksz); ext4fs_free_revoke_blks(); } free(temp_buff); free(temp_buff1); return 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; }