static int extent_head_looks_insane(struct ext2_inode_large *inode) { if (!(inode->i_flags & EXT4_EXTENTS_FL) || ext2fs_extent_header_verify(inode->i_block, sizeof(inode->i_block)) == 0) return 0; return 1; }
/* * This function is responsible for (optionally) moving through the * extent tree and then returning the current extent */ errcode_t ext2fs_extent_get(ext2_extent_handle_t handle, int flags, struct ext2fs_extent *extent) { struct extent_path *path, *newpath; struct ext3_extent_header *eh; struct ext3_extent_idx *ix = 0; struct ext3_extent *ex; errcode_t retval; blk_t blk; blk64_t end_blk; int orig_op, op; EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE); if (!handle->path) return EXT2_ET_NO_CURRENT_NODE; orig_op = op = flags & EXT2_EXTENT_MOVE_MASK; retry: path = handle->path + handle->level; if ((orig_op == EXT2_EXTENT_NEXT) || (orig_op == EXT2_EXTENT_NEXT_LEAF)) { if (handle->level < handle->max_depth) { /* interior node */ if (path->visit_num == 0) { path->visit_num++; op = EXT2_EXTENT_DOWN; } else if (path->left > 0) op = EXT2_EXTENT_NEXT_SIB; else if (handle->level > 0) op = EXT2_EXTENT_UP; else return EXT2_ET_EXTENT_NO_NEXT; } else { /* leaf node */ if (path->left > 0) op = EXT2_EXTENT_NEXT_SIB; else if (handle->level > 0) op = EXT2_EXTENT_UP; else return EXT2_ET_EXTENT_NO_NEXT; } if (op != EXT2_EXTENT_NEXT_SIB) { #ifdef DEBUG printf("<<<< OP = %s\n", (op == EXT2_EXTENT_DOWN) ? "down" : ((op == EXT2_EXTENT_UP) ? "up" : "unknown")); #endif } } if ((orig_op == EXT2_EXTENT_PREV) || (orig_op == EXT2_EXTENT_PREV_LEAF)) { if (handle->level < handle->max_depth) { /* interior node */ if (path->visit_num > 0 ) { /* path->visit_num = 0; */ op = EXT2_EXTENT_DOWN_AND_LAST; } else if (path->left < path->entries-1) op = EXT2_EXTENT_PREV_SIB; else if (handle->level > 0) op = EXT2_EXTENT_UP; else return EXT2_ET_EXTENT_NO_PREV; } else { /* leaf node */ if (path->left < path->entries-1) op = EXT2_EXTENT_PREV_SIB; else if (handle->level > 0) op = EXT2_EXTENT_UP; else return EXT2_ET_EXTENT_NO_PREV; } if (op != EXT2_EXTENT_PREV_SIB) { #ifdef DEBUG printf("<<<< OP = %s\n", (op == EXT2_EXTENT_DOWN_AND_LAST) ? "down/last" : ((op == EXT2_EXTENT_UP) ? "up" : "unknown")); #endif } } if (orig_op == EXT2_EXTENT_LAST_LEAF) { if ((handle->level < handle->max_depth) && (path->left == 0)) op = EXT2_EXTENT_DOWN; else op = EXT2_EXTENT_LAST_SIB; #ifdef DEBUG printf("<<<< OP = %s\n", (op == EXT2_EXTENT_DOWN) ? "down" : "last_sib"); #endif } switch (op) { case EXT2_EXTENT_CURRENT: ix = path->curr; break; case EXT2_EXTENT_ROOT: handle->level = 0; path = handle->path + handle->level; case EXT2_EXTENT_FIRST_SIB: path->left = path->entries; path->curr = 0; case EXT2_EXTENT_NEXT_SIB: if (path->left <= 0) return EXT2_ET_EXTENT_NO_NEXT; if (path->curr) { ix = path->curr; ix++; } else { eh = (struct ext3_extent_header *) path->buf; ix = EXT_FIRST_INDEX(eh); } path->left--; path->curr = ix; path->visit_num = 0; break; case EXT2_EXTENT_PREV_SIB: if (!path->curr || path->left+1 >= path->entries) return EXT2_ET_EXTENT_NO_PREV; ix = path->curr; ix--; path->curr = ix; path->left++; if (handle->level < handle->max_depth) path->visit_num = 1; break; case EXT2_EXTENT_LAST_SIB: eh = (struct ext3_extent_header *) path->buf; path->curr = EXT_LAST_EXTENT(eh); ix = path->curr; path->left = 0; path->visit_num = 0; break; case EXT2_EXTENT_UP: if (handle->level <= 0) return EXT2_ET_EXTENT_NO_UP; handle->level--; path--; ix = path->curr; if ((orig_op == EXT2_EXTENT_PREV) || (orig_op == EXT2_EXTENT_PREV_LEAF)) path->visit_num = 0; break; case EXT2_EXTENT_DOWN: case EXT2_EXTENT_DOWN_AND_LAST: if (!path->curr ||(handle->level >= handle->max_depth)) return EXT2_ET_EXTENT_NO_DOWN; ix = path->curr; newpath = path + 1; if (!newpath->buf) { retval = ext2fs_get_mem(handle->fs->blocksize, &newpath->buf); if (retval) return retval; } blk = ext2fs_le32_to_cpu(ix->ei_leaf) + ((__u64) ext2fs_le16_to_cpu(ix->ei_leaf_hi) << 32); if ((handle->fs->flags & EXT2_FLAG_IMAGE_FILE) && (handle->fs->io != handle->fs->image_io)) memset(newpath->buf, 0, handle->fs->blocksize); else { retval = io_channel_read_blk(handle->fs->io, blk, 1, newpath->buf); if (retval) return retval; } handle->level++; eh = (struct ext3_extent_header *) newpath->buf; retval = ext2fs_extent_header_verify(eh, handle->fs->blocksize); if (retval) { handle->level--; return retval; } newpath->left = newpath->entries = ext2fs_le16_to_cpu(eh->eh_entries); newpath->max_entries = ext2fs_le16_to_cpu(eh->eh_max); if (path->left > 0) { ix++; newpath->end_blk = ext2fs_le32_to_cpu(ix->ei_block); } else newpath->end_blk = path->end_blk; path = newpath; if (op == EXT2_EXTENT_DOWN) { ix = EXT_FIRST_INDEX((struct ext3_extent_header *) eh); path->curr = ix; path->left = path->entries - 1; path->visit_num = 0; } else { ix = EXT_LAST_INDEX((struct ext3_extent_header *) eh); path->curr = ix; path->left = 0; if (handle->level < handle->max_depth) path->visit_num = 1; } #ifdef DEBUG printf("Down to level %d/%d, end_blk=%llu\n", handle->level, handle->max_depth, path->end_blk); #endif break; default: return EXT2_ET_OP_NOT_SUPPORTED; } if (!ix) return EXT2_ET_NO_CURRENT_NODE; extent->e_flags = 0; #ifdef DEBUG printf("(Left %d)\n", path->left); #endif if (handle->level == handle->max_depth) { ex = (struct ext3_extent *) ix; extent->e_pblk = ext2fs_le32_to_cpu(ex->ee_start) + ((__u64) ext2fs_le16_to_cpu(ex->ee_start_hi) << 32); extent->e_lblk = ext2fs_le32_to_cpu(ex->ee_block); extent->e_len = ext2fs_le16_to_cpu(ex->ee_len); extent->e_flags |= EXT2_EXTENT_FLAGS_LEAF; if (extent->e_len > EXT_INIT_MAX_LEN) { extent->e_len -= EXT_INIT_MAX_LEN; extent->e_flags |= EXT2_EXTENT_FLAGS_UNINIT; } } else { extent->e_pblk = ext2fs_le32_to_cpu(ix->ei_leaf) + ((__u64) ext2fs_le16_to_cpu(ix->ei_leaf_hi) << 32); extent->e_lblk = ext2fs_le32_to_cpu(ix->ei_block); if (path->left > 0) { ix++; end_blk = ext2fs_le32_to_cpu(ix->ei_block); } else end_blk = path->end_blk; extent->e_len = end_blk - extent->e_lblk; } if (path->visit_num) extent->e_flags |= EXT2_EXTENT_FLAGS_SECOND_VISIT; if (((orig_op == EXT2_EXTENT_NEXT_LEAF) || (orig_op == EXT2_EXTENT_PREV_LEAF)) && (handle->level != handle->max_depth)) goto retry; if ((orig_op == EXT2_EXTENT_LAST_LEAF) && ((handle->level != handle->max_depth) || (path->left != 0))) goto retry; return 0; }
void ext2fs_swap_super(struct ext2_super_block * sb) { int i; sb->s_inodes_count = ext2fs_swab32(sb->s_inodes_count); sb->s_blocks_count = ext2fs_swab32(sb->s_blocks_count); sb->s_r_blocks_count = ext2fs_swab32(sb->s_r_blocks_count); sb->s_free_blocks_count = ext2fs_swab32(sb->s_free_blocks_count); sb->s_free_inodes_count = ext2fs_swab32(sb->s_free_inodes_count); sb->s_first_data_block = ext2fs_swab32(sb->s_first_data_block); sb->s_log_block_size = ext2fs_swab32(sb->s_log_block_size); sb->s_log_frag_size = ext2fs_swab32(sb->s_log_frag_size); sb->s_blocks_per_group = ext2fs_swab32(sb->s_blocks_per_group); sb->s_frags_per_group = ext2fs_swab32(sb->s_frags_per_group); sb->s_inodes_per_group = ext2fs_swab32(sb->s_inodes_per_group); sb->s_mtime = ext2fs_swab32(sb->s_mtime); sb->s_wtime = ext2fs_swab32(sb->s_wtime); sb->s_mnt_count = ext2fs_swab16(sb->s_mnt_count); sb->s_max_mnt_count = ext2fs_swab16(sb->s_max_mnt_count); sb->s_magic = ext2fs_swab16(sb->s_magic); sb->s_state = ext2fs_swab16(sb->s_state); sb->s_errors = ext2fs_swab16(sb->s_errors); sb->s_minor_rev_level = ext2fs_swab16(sb->s_minor_rev_level); sb->s_lastcheck = ext2fs_swab32(sb->s_lastcheck); sb->s_checkinterval = ext2fs_swab32(sb->s_checkinterval); sb->s_creator_os = ext2fs_swab32(sb->s_creator_os); sb->s_rev_level = ext2fs_swab32(sb->s_rev_level); sb->s_def_resuid = ext2fs_swab16(sb->s_def_resuid); sb->s_def_resgid = ext2fs_swab16(sb->s_def_resgid); sb->s_first_ino = ext2fs_swab32(sb->s_first_ino); sb->s_inode_size = ext2fs_swab16(sb->s_inode_size); sb->s_block_group_nr = ext2fs_swab16(sb->s_block_group_nr); sb->s_feature_compat = ext2fs_swab32(sb->s_feature_compat); sb->s_feature_incompat = ext2fs_swab32(sb->s_feature_incompat); sb->s_feature_ro_compat = ext2fs_swab32(sb->s_feature_ro_compat); sb->s_algorithm_usage_bitmap = ext2fs_swab32(sb->s_algorithm_usage_bitmap); sb->s_reserved_gdt_blocks = ext2fs_swab16(sb->s_reserved_gdt_blocks); sb->s_journal_inum = ext2fs_swab32(sb->s_journal_inum); sb->s_journal_dev = ext2fs_swab32(sb->s_journal_dev); sb->s_last_orphan = ext2fs_swab32(sb->s_last_orphan); sb->s_desc_size = ext2fs_swab16(sb->s_desc_size); sb->s_default_mount_opts = ext2fs_swab32(sb->s_default_mount_opts); sb->s_first_meta_bg = ext2fs_swab32(sb->s_first_meta_bg); sb->s_mkfs_time = ext2fs_swab32(sb->s_mkfs_time); sb->s_blocks_count_hi = ext2fs_swab32(sb->s_blocks_count_hi); sb->s_r_blocks_count_hi = ext2fs_swab32(sb->s_r_blocks_count_hi); sb->s_free_blocks_hi = ext2fs_swab32(sb->s_free_blocks_hi); sb->s_min_extra_isize = ext2fs_swab16(sb->s_min_extra_isize); sb->s_want_extra_isize = ext2fs_swab16(sb->s_want_extra_isize); sb->s_flags = ext2fs_swab32(sb->s_flags); sb->s_kbytes_written = ext2fs_swab64(sb->s_kbytes_written); sb->s_snapshot_inum = ext2fs_swab32(sb->s_snapshot_inum); sb->s_snapshot_id = ext2fs_swab32(sb->s_snapshot_id); sb->s_snapshot_r_blocks_count = ext2fs_swab64(sb->s_snapshot_r_blocks_count); sb->s_snapshot_list = ext2fs_swab32(sb->s_snapshot_list); for (i=0; i < 4; i++) sb->s_hash_seed[i] = ext2fs_swab32(sb->s_hash_seed[i]); if (!ext2fs_extent_header_verify(sb->s_jnl_blocks, sizeof(sb->s_jnl_blocks))) { sb->s_jnl_blocks[16] = ext2fs_swab32(sb->s_jnl_blocks[16]); return; } for (i=0; i < 17; i++) sb->s_jnl_blocks[i] = ext2fs_swab32(sb->s_jnl_blocks[i]); }
extern errcode_t ext2fs_extent_open(ext2_filsys fs, ext2_ino_t ino, ext2_extent_handle_t *ret_handle) { struct ext2_extent_handle *handle; errcode_t retval; int isize = EXT2_INODE_SIZE(fs->super); int i; struct ext3_extent_header *eh; EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); if ((ino == 0) || (ino > fs->super->s_inodes_count)) return EXT2_ET_BAD_INODE_NUM; retval = ext2fs_get_mem(sizeof(struct ext2_extent_handle), &handle); if (retval) return retval; memset(handle, 0, sizeof(struct ext2_extent_handle)); retval = ext2fs_get_mem(isize, &handle->inode); if (retval) goto errout; handle->ino = ino; handle->fs = fs; retval = ext2fs_read_inode_full(fs, ino, handle->inode, isize); if (retval) goto errout; eh = (struct ext3_extent_header *) &handle->inode->i_block[0]; for (i=0; i < EXT2_N_BLOCKS; i++) if (handle->inode->i_block[i]) break; if (i >= EXT2_N_BLOCKS) { eh->eh_magic = ext2fs_cpu_to_le16(EXT3_EXT_MAGIC); eh->eh_depth = 0; eh->eh_entries = 0; i = (sizeof(handle->inode->i_block) - sizeof(*eh)) / sizeof(struct ext3_extent); eh->eh_max = ext2fs_cpu_to_le16(i); handle->inode->i_flags |= EXT4_EXTENTS_FL; } if (!(handle->inode->i_flags & EXT4_EXTENTS_FL)) { retval = EXT2_ET_INODE_NOT_EXTENT; goto errout; } retval = ext2fs_extent_header_verify(eh, sizeof(handle->inode->i_block)); if (retval) goto errout; handle->max_depth = ext2fs_le16_to_cpu(eh->eh_depth); handle->type = ext2fs_le16_to_cpu(eh->eh_magic); retval = ext2fs_get_mem(((handle->max_depth+1) * sizeof(struct extent_path)), &handle->path); memset(handle->path, 0, (handle->max_depth+1) * sizeof(struct extent_path)); handle->path[0].buf = (char *) handle->inode->i_block; handle->path[0].left = handle->path[0].entries = ext2fs_le16_to_cpu(eh->eh_entries); handle->path[0].max_entries = ext2fs_le16_to_cpu(eh->eh_max); handle->path[0].curr = 0; handle->path[0].end_blk = ((((__u64) handle->inode->i_size_high << 32) + handle->inode->i_size + (fs->blocksize - 1)) >> EXT2_BLOCK_SIZE_BITS(fs->super)); handle->path[0].visit_num = 1; handle->level = 0; handle->magic = EXT2_ET_MAGIC_EXTENT_HANDLE; *ret_handle = handle; return 0; errout: ext2fs_extent_free(handle); return retval; }
void ext2fs_swap_super(struct ext2_super_block * sb) { int i; sb->s_inodes_count = ext2fs_swab32(sb->s_inodes_count); sb->s_blocks_count = ext2fs_swab32(sb->s_blocks_count); sb->s_r_blocks_count = ext2fs_swab32(sb->s_r_blocks_count); sb->s_free_blocks_count = ext2fs_swab32(sb->s_free_blocks_count); sb->s_free_inodes_count = ext2fs_swab32(sb->s_free_inodes_count); sb->s_first_data_block = ext2fs_swab32(sb->s_first_data_block); sb->s_log_block_size = ext2fs_swab32(sb->s_log_block_size); sb->s_log_frag_size = ext2fs_swab32(sb->s_log_frag_size); sb->s_blocks_per_group = ext2fs_swab32(sb->s_blocks_per_group); sb->s_frags_per_group = ext2fs_swab32(sb->s_frags_per_group); sb->s_inodes_per_group = ext2fs_swab32(sb->s_inodes_per_group); sb->s_mtime = ext2fs_swab32(sb->s_mtime); sb->s_wtime = ext2fs_swab32(sb->s_wtime); sb->s_mnt_count = ext2fs_swab16(sb->s_mnt_count); sb->s_max_mnt_count = ext2fs_swab16(sb->s_max_mnt_count); sb->s_magic = ext2fs_swab16(sb->s_magic); sb->s_state = ext2fs_swab16(sb->s_state); sb->s_errors = ext2fs_swab16(sb->s_errors); sb->s_minor_rev_level = ext2fs_swab16(sb->s_minor_rev_level); sb->s_lastcheck = ext2fs_swab32(sb->s_lastcheck); sb->s_checkinterval = ext2fs_swab32(sb->s_checkinterval); sb->s_creator_os = ext2fs_swab32(sb->s_creator_os); sb->s_rev_level = ext2fs_swab32(sb->s_rev_level); sb->s_def_resuid = ext2fs_swab16(sb->s_def_resuid); sb->s_def_resgid = ext2fs_swab16(sb->s_def_resgid); sb->s_first_ino = ext2fs_swab32(sb->s_first_ino); sb->s_inode_size = ext2fs_swab16(sb->s_inode_size); sb->s_block_group_nr = ext2fs_swab16(sb->s_block_group_nr); sb->s_feature_compat = ext2fs_swab32(sb->s_feature_compat); sb->s_feature_incompat = ext2fs_swab32(sb->s_feature_incompat); sb->s_feature_ro_compat = ext2fs_swab32(sb->s_feature_ro_compat); sb->s_algorithm_usage_bitmap = ext2fs_swab32(sb->s_algorithm_usage_bitmap); sb->s_reserved_gdt_blocks = ext2fs_swab16(sb->s_reserved_gdt_blocks); sb->s_journal_inum = ext2fs_swab32(sb->s_journal_inum); sb->s_journal_dev = ext2fs_swab32(sb->s_journal_dev); sb->s_last_orphan = ext2fs_swab32(sb->s_last_orphan); sb->s_desc_size = ext2fs_swab16(sb->s_desc_size); sb->s_default_mount_opts = ext2fs_swab32(sb->s_default_mount_opts); sb->s_first_meta_bg = ext2fs_swab32(sb->s_first_meta_bg); sb->s_mkfs_time = ext2fs_swab32(sb->s_mkfs_time); sb->s_blocks_count_hi = ext2fs_swab32(sb->s_blocks_count_hi); sb->s_r_blocks_count_hi = ext2fs_swab32(sb->s_r_blocks_count_hi); sb->s_free_blocks_hi = ext2fs_swab32(sb->s_free_blocks_hi); sb->s_min_extra_isize = ext2fs_swab16(sb->s_min_extra_isize); sb->s_want_extra_isize = ext2fs_swab16(sb->s_want_extra_isize); sb->s_flags = ext2fs_swab32(sb->s_flags); sb->s_kbytes_written = ext2fs_swab64(sb->s_kbytes_written); for (i=0; i < 4; i++) sb->s_hash_seed[i] = ext2fs_swab32(sb->s_hash_seed[i]); /* if journal backup is for a valid extent-based journal... */ if (!ext2fs_extent_header_verify(sb->s_jnl_blocks, sizeof(sb->s_jnl_blocks))) { /* ... swap only the journal i_size */ sb->s_jnl_blocks[16] = ext2fs_swab32(sb->s_jnl_blocks[16]); /* and the extent data is not swapped on read */ return; } /* direct/indirect journal: swap it all */ for (i=0; i < 17; i++) sb->s_jnl_blocks[i] = ext2fs_swab32(sb->s_jnl_blocks[i]); }