errcode_t ext2fs_icount_store(ext2_icount_t icount, ext2_ino_t ino, __u16 count) { if (!ino || (ino > icount->num_inodes)) return EXT2_ET_INVALID_ARGUMENT; EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT); if (count == 1) { ext2fs_mark_inode_bitmap(icount->single, ino); if (icount->multiple) ext2fs_unmark_inode_bitmap(icount->multiple, ino); return 0; } if (count == 0) { ext2fs_unmark_inode_bitmap(icount->single, ino); if (icount->multiple) { /* * If the icount->multiple bitmap is enabled, * we can just clear both bitmaps and we're done */ ext2fs_unmark_inode_bitmap(icount->multiple, ino); } else set_inode_count(icount, ino, 0); return 0; } if (set_inode_count(icount, ino, count)) return EXT2_ET_NO_MEMORY; ext2fs_unmark_inode_bitmap(icount->single, ino); if (icount->multiple) ext2fs_mark_inode_bitmap(icount->multiple, ino); return 0; }
/* * This routine is called when an inode is not connected to the * directory tree. * * This subroutine returns 1 then the caller shouldn't bother with the * rest of the pass 4 tests. */ static int disconnect_inode(e2fsck_t ctx, ext2_ino_t i) { ext2_filsys fs = ctx->fs; struct ext2_inode inode; struct problem_context pctx; e2fsck_read_inode(ctx, i, &inode, "pass4: disconnect_inode"); clear_problem_context(&pctx); pctx.ino = i; pctx.inode = &inode; /* * Offer to delete any zero-length files that does not have * blocks. If there is an EA block, it might have useful * information, so we won't prompt to delete it, but let it be * reconnected to lost+found. */ if (!inode.i_blocks && (LINUX_S_ISREG(inode.i_mode) || LINUX_S_ISDIR(inode.i_mode))) { if (fix_problem(ctx, PR_4_ZERO_LEN_INODE, &pctx)) { ext2fs_icount_store(ctx->inode_link_info, i, 0); inode.i_links_count = 0; inode.i_dtime = ctx->now; e2fsck_write_inode(ctx, i, &inode, "disconnect_inode"); /* * Fix up the bitmaps... */ e2fsck_read_bitmaps(ctx); ext2fs_unmark_inode_bitmap(ctx->inode_used_map, i); ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, i); ext2fs_inode_alloc_stats2(fs, i, -1, LINUX_S_ISDIR(inode.i_mode)); return 0; } } /* * Prompt to reconnect. */ if (fix_problem(ctx, PR_4_UNATTACHED_INODE, &pctx)) { if (e2fsck_reconnect_file(ctx, i)) ext2fs_unmark_valid(fs); } else { /* * If we don't attach the inode, then skip the * i_links_test since there's no point in trying to * force i_links_count to zero. */ ext2fs_unmark_valid(fs); return 1; } return 0; }
/* * This fuction deallocates an inode */ static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf) { ext2_filsys fs = ctx->fs; struct ext2_inode inode; struct problem_context pctx; ext2fs_icount_store(ctx->inode_link_info, ino, 0); e2fsck_read_inode(ctx, ino, &inode, "deallocate_inode"); inode.i_links_count = 0; inode.i_dtime = time(0); e2fsck_write_inode(ctx, ino, &inode, "deallocate_inode"); clear_problem_context(&pctx); pctx.ino = ino; /* * Fix up the bitmaps... */ e2fsck_read_bitmaps(ctx); ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino); ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino); if (ctx->inode_bad_map) ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, ino); ext2fs_unmark_inode_bitmap(fs->inode_map, ino); ext2fs_mark_ib_dirty(fs); if (!ext2fs_inode_has_valid_blocks(&inode)) return; if (!LINUX_S_ISDIR(inode.i_mode) && (inode.i_size_high || inode.i_size & 0x80000000UL)) ctx->large_files--; if (inode.i_file_acl) { ext2fs_unmark_block_bitmap(ctx->block_found_map, inode.i_file_acl); ext2fs_unmark_block_bitmap(fs->block_map, inode.i_file_acl); } ext2fs_mark_bb_dirty(fs); pctx.errcode = ext2fs_block_iterate2(fs, ino, 0, block_buf, deallocate_inode_block, ctx); if (pctx.errcode) { fix_problem(ctx, PR_2_DEALLOC_INODE, &pctx); ctx->flags |= E2F_FLAG_ABORT; return; } }
errcode_t ext2fs_icount_store(ext2_icount_t icount, ext2_ino_t ino, __u16 count) { struct ext2_icount_el *el; if (!ino || (ino > icount->num_inodes)) return EXT2_ET_INVALID_ARGUMENT; EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT); if (count == 1) { ext2fs_mark_inode_bitmap(icount->single, ino); if (icount->multiple) ext2fs_unmark_inode_bitmap(icount->multiple, ino); return 0; } if (count == 0) { ext2fs_unmark_inode_bitmap(icount->single, ino); if (icount->multiple) { /* * If the icount->multiple bitmap is enabled, * we can just clear both bitmaps and we're done */ ext2fs_unmark_inode_bitmap(icount->multiple, ino); } else { el = get_icount_el(icount, ino, 0); if (el) el->count = 0; } return 0; } /* * Get the icount element */ el = get_icount_el(icount, ino, 1); if (!el) return EXT2_ET_NO_MEMORY; el->count = count; ext2fs_unmark_inode_bitmap(icount->single, ino); if (icount->multiple) ext2fs_mark_inode_bitmap(icount->multiple, ino); return 0; }
errcode_t ext2fs_icount_increment(ext2_icount_t icount, ext2_ino_t ino, __u16 *ret) { __u32 curr_value; EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT); if (!ino || (ino > icount->num_inodes)) return EXT2_ET_INVALID_ARGUMENT; if (ext2fs_test_inode_bitmap(icount->single, ino)) { /* * If the existing count is 1, then we know there is * no entry in the list. */ if (set_inode_count(icount, ino, 2)) return EXT2_ET_NO_MEMORY; curr_value = 2; ext2fs_unmark_inode_bitmap(icount->single, ino); } else if (icount->multiple) { /* * The count is either zero or greater than 1; if the * inode is set in icount->multiple, then there should * be an entry in the list, so we need to fix it. */ if (ext2fs_test_inode_bitmap(icount->multiple, ino)) { get_inode_count(icount, ino, &curr_value); curr_value++; if (set_inode_count(icount, ino, curr_value)) return EXT2_ET_NO_MEMORY; } else { /* * The count was zero; mark the single bitmap * and return. */ ext2fs_mark_inode_bitmap(icount->single, ino); if (ret) *ret = 1; return 0; } } else { /* * The count is either zero or greater than 1; try to * find an entry in the list to determine which. */ get_inode_count(icount, ino, &curr_value); curr_value++; if (set_inode_count(icount, ino, curr_value)) return EXT2_ET_NO_MEMORY; } if (icount->multiple) ext2fs_mark_inode_bitmap(icount->multiple, ino); if (ret) *ret = icount_16_xlate(curr_value); return 0; }
errcode_t ext2fs_icount_decrement(ext2_icount_t icount, ext2_ino_t ino, __u16 *ret) { __u32 curr_value; if (!ino || (ino > icount->num_inodes)) return EXT2_ET_INVALID_ARGUMENT; EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT); if (ext2fs_test_inode_bitmap(icount->single, ino)) { ext2fs_unmark_inode_bitmap(icount->single, ino); if (icount->multiple) ext2fs_unmark_inode_bitmap(icount->multiple, ino); else { set_inode_count(icount, ino, 0); } if (ret) *ret = 0; return 0; } if (icount->multiple && !ext2fs_test_inode_bitmap(icount->multiple, ino)) return EXT2_ET_INVALID_ARGUMENT; get_inode_count(icount, ino, &curr_value); if (!curr_value) return EXT2_ET_INVALID_ARGUMENT; curr_value--; if (set_inode_count(icount, ino, curr_value)) return EXT2_ET_NO_MEMORY; if (curr_value == 1) ext2fs_mark_inode_bitmap(icount->single, ino); if ((curr_value == 0) && icount->multiple) ext2fs_unmark_inode_bitmap(icount->multiple, ino); if (ret) *ret = icount_16_xlate(curr_value); return 0; }
errcode_t ext2fs_icount_decrement(ext2_icount_t icount, ext2_ino_t ino, __u16 *ret) { struct ext2_icount_el *el; if (!ino || (ino > icount->num_inodes)) return EXT2_ET_INVALID_ARGUMENT; EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT); if (ext2fs_test_inode_bitmap(icount->single, ino)) { ext2fs_unmark_inode_bitmap(icount->single, ino); if (icount->multiple) ext2fs_unmark_inode_bitmap(icount->multiple, ino); else { el = get_icount_el(icount, ino, 0); if (el) el->count = 0; } if (ret) *ret = 0; return 0; } if (icount->multiple && !ext2fs_test_inode_bitmap(icount->multiple, ino)) return EXT2_ET_INVALID_ARGUMENT; el = get_icount_el(icount, ino, 0); if (!el || el->count == 0) return EXT2_ET_INVALID_ARGUMENT; el->count--; if (el->count == 1) ext2fs_mark_inode_bitmap(icount->single, ino); if ((el->count == 0) && icount->multiple) ext2fs_unmark_inode_bitmap(icount->multiple, ino); if (ret) *ret = el->count; return 0; }
void ext2fs_inode_alloc_stats2(ext2_filsys fs, ext2_ino_t ino, int inuse, int isdir) { int group = ext2fs_group_of_ino(fs, ino); if (inuse > 0) ext2fs_mark_inode_bitmap(fs->inode_map, ino); else ext2fs_unmark_inode_bitmap(fs->inode_map, ino); fs->group_desc[group].bg_free_inodes_count -= inuse; if (isdir) fs->group_desc[group].bg_used_dirs_count += inuse; fs->super->s_free_inodes_count -= inuse; ext2fs_mark_super_dirty(fs); ext2fs_mark_ib_dirty(fs); }
void ext2fs_inode_alloc_stats2(ext2_filsys fs, ext2_ino_t ino, int inuse, int isdir) { int group = ext2fs_group_of_ino(fs, ino); #ifndef OMIT_COM_ERR if (ino > fs->super->s_inodes_count) { com_err("ext2fs_inode_alloc_stats2", 0, "Illegal inode number: %lu", (unsigned long) ino); return; } #endif if (inuse > 0) ext2fs_mark_inode_bitmap(fs->inode_map, ino); else ext2fs_unmark_inode_bitmap(fs->inode_map, ino); fs->group_desc[group].bg_free_inodes_count -= inuse; if (isdir) fs->group_desc[group].bg_used_dirs_count += inuse; /* We don't strictly need to be clearing the uninit flag if inuse < 0 * (i.e. freeing inodes) but it also means something is bad. */ fs->group_desc[group].bg_flags &= ~EXT2_BG_INODE_UNINIT; if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super, EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) { ext2_ino_t first_unused_inode = fs->super->s_inodes_per_group - fs->group_desc[group].bg_itable_unused + group * fs->super->s_inodes_per_group + 1; if (ino >= first_unused_inode) fs->group_desc[group].bg_itable_unused = group * fs->super->s_inodes_per_group + fs->super->s_inodes_per_group - ino; ext2fs_group_desc_csum_set(fs, group); } fs->super->s_free_inodes_count -= inuse; ext2fs_mark_super_dirty(fs); ext2fs_mark_ib_dirty(fs); }
void e2fsck_move_ext3_journal(e2fsck_t ctx) { struct ext2_super_block *sb = ctx->fs->super; struct problem_context pctx; struct ext2_inode inode; ext2_filsys fs = ctx->fs; ext2_ino_t ino; errcode_t retval; const char * const * cpp; int group, mount_flags; clear_problem_context(&pctx); /* * If the filesystem is opened read-only, or there is no * journal, then do nothing. */ if ((ctx->options & E2F_OPT_READONLY) || (sb->s_journal_inum == 0) || !(sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL)) return; /* * Read in the journal inode */ if (ext2fs_read_inode(fs, sb->s_journal_inum, &inode) != 0) return; /* * If it's necessary to backup the journal inode, do so. */ if ((sb->s_jnl_backup_type == 0) || ((sb->s_jnl_backup_type == EXT3_JNL_BACKUP_BLOCKS) && memcmp(inode.i_block, sb->s_jnl_blocks, EXT2_N_BLOCKS*4))) { if (fix_problem(ctx, PR_0_BACKUP_JNL, &pctx)) { memcpy(sb->s_jnl_blocks, inode.i_block, EXT2_N_BLOCKS*4); sb->s_jnl_blocks[16] = inode.i_size; sb->s_jnl_backup_type = EXT3_JNL_BACKUP_BLOCKS; ext2fs_mark_super_dirty(fs); fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY; } } /* * If the journal is already the hidden inode, then do nothing */ if (sb->s_journal_inum == EXT2_JOURNAL_INO) return; /* * The journal inode had better have only one link and not be readable. */ if (inode.i_links_count != 1) return; /* * If the filesystem is mounted, or we can't tell whether * or not it's mounted, do nothing. */ retval = ext2fs_check_if_mounted(ctx->filesystem_name, &mount_flags); if (retval || (mount_flags & EXT2_MF_MOUNTED)) return; /* * If we can't find the name of the journal inode, then do * nothing. */ for (cpp = journal_names; *cpp; cpp++) { retval = ext2fs_lookup(fs, EXT2_ROOT_INO, *cpp, strlen(*cpp), 0, &ino); if ((retval == 0) && (ino == sb->s_journal_inum)) break; } if (*cpp == 0) return; /* We need the inode bitmap to be loaded */ retval = ext2fs_read_bitmaps(fs); if (retval) return; pctx.str = *cpp; if (!fix_problem(ctx, PR_0_MOVE_JOURNAL, &pctx)) return; /* * OK, we've done all the checks, let's actually move the * journal inode. Errors at this point mean we need to force * an ext2 filesystem check. */ if ((retval = ext2fs_unlink(fs, EXT2_ROOT_INO, *cpp, ino, 0)) != 0) goto err_out; if ((retval = ext2fs_write_inode(fs, EXT2_JOURNAL_INO, &inode)) != 0) goto err_out; sb->s_journal_inum = EXT2_JOURNAL_INO; ext2fs_mark_super_dirty(fs); fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY; inode.i_links_count = 0; inode.i_dtime = ctx->now; if ((retval = ext2fs_write_inode(fs, ino, &inode)) != 0) goto err_out; group = ext2fs_group_of_ino(fs, ino); ext2fs_unmark_inode_bitmap(fs->inode_map, ino); ext2fs_mark_ib_dirty(fs); fs->group_desc[group].bg_free_inodes_count++; fs->super->s_free_inodes_count++; return; err_out: pctx.errcode = retval; fix_problem(ctx, PR_0_ERR_MOVE_JOURNAL, &pctx); fs->super->s_state &= ~EXT2_VALID_FS; ext2fs_mark_super_dirty(fs); return; }
extern int e2fsck_process_bad_inode(e2fsck_t ctx, ext2_ino_t dir, ext2_ino_t ino, char *buf) { ext2_filsys fs = ctx->fs; struct ext2_inode inode; int inode_modified = 0; int not_fixed = 0; unsigned char *frag, *fsize; struct problem_context pctx; int problem = 0; e2fsck_read_inode(ctx, ino, &inode, "process_bad_inode"); clear_problem_context(&pctx); pctx.ino = ino; pctx.dir = dir; pctx.inode = &inode; if (inode.i_file_acl && !(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR)) { if (fix_problem(ctx, PR_2_FILE_ACL_ZERO, &pctx)) { inode.i_file_acl = 0; inode_modified++; } else not_fixed++; } if (!LINUX_S_ISDIR(inode.i_mode) && !LINUX_S_ISREG(inode.i_mode) && !LINUX_S_ISCHR(inode.i_mode) && !LINUX_S_ISBLK(inode.i_mode) && !LINUX_S_ISLNK(inode.i_mode) && !LINUX_S_ISFIFO(inode.i_mode) && !(LINUX_S_ISSOCK(inode.i_mode))) problem = PR_2_BAD_MODE; else if (LINUX_S_ISCHR(inode.i_mode) && !e2fsck_pass1_check_device_inode(fs, &inode)) problem = PR_2_BAD_CHAR_DEV; else if (LINUX_S_ISBLK(inode.i_mode) && !e2fsck_pass1_check_device_inode(fs, &inode)) problem = PR_2_BAD_BLOCK_DEV; else if (LINUX_S_ISFIFO(inode.i_mode) && !e2fsck_pass1_check_device_inode(fs, &inode)) problem = PR_2_BAD_FIFO; else if (LINUX_S_ISSOCK(inode.i_mode) && !e2fsck_pass1_check_device_inode(fs, &inode)) problem = PR_2_BAD_SOCKET; else if (LINUX_S_ISLNK(inode.i_mode) && !e2fsck_pass1_check_symlink(fs, ino, &inode, buf)) { problem = PR_2_INVALID_SYMLINK; } if (problem) { if (fix_problem(ctx, problem, &pctx)) { deallocate_inode(ctx, ino, 0); if (ctx->flags & E2F_FLAG_SIGNAL_MASK) return 0; return 1; } else not_fixed++; problem = 0; } if (inode.i_faddr) { if (fix_problem(ctx, PR_2_FADDR_ZERO, &pctx)) { inode.i_faddr = 0; inode_modified++; } else not_fixed++; } switch (fs->super->s_creator_os) { case EXT2_OS_HURD: frag = &inode.osd2.hurd2.h_i_frag; fsize = &inode.osd2.hurd2.h_i_fsize; break; default: frag = fsize = 0; } if (frag && *frag) { pctx.num = *frag; if (fix_problem(ctx, PR_2_FRAG_ZERO, &pctx)) { *frag = 0; inode_modified++; } else not_fixed++; pctx.num = 0; } if (fsize && *fsize) { pctx.num = *fsize; if (fix_problem(ctx, PR_2_FSIZE_ZERO, &pctx)) { *fsize = 0; inode_modified++; } else not_fixed++; pctx.num = 0; } if ((fs->super->s_creator_os == EXT2_OS_LINUX) && !(fs->super->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_HUGE_FILE) && (inode.osd2.linux2.l_i_blocks_hi != 0)) { pctx.num = inode.osd2.linux2.l_i_blocks_hi; if (fix_problem(ctx, PR_2_BLOCKS_HI_ZERO, &pctx)) { inode.osd2.linux2.l_i_blocks_hi = 0; inode_modified++; } } if (!(fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT) && inode.osd2.linux2.l_i_file_acl_high != 0) { pctx.num = inode.osd2.linux2.l_i_file_acl_high; if (fix_problem(ctx, PR_2_I_FILE_ACL_HI_ZERO, &pctx)) { inode.osd2.linux2.l_i_file_acl_high = 0; inode_modified++; } else not_fixed++; } if (inode.i_file_acl && ((inode.i_file_acl < fs->super->s_first_data_block) || (inode.i_file_acl >= fs->super->s_blocks_count))) { if (fix_problem(ctx, PR_2_FILE_ACL_BAD, &pctx)) { inode.i_file_acl = 0; inode_modified++; } else not_fixed++; } if (inode.i_dir_acl && LINUX_S_ISDIR(inode.i_mode)) { if (fix_problem(ctx, PR_2_DIR_ACL_ZERO, &pctx)) { inode.i_dir_acl = 0; inode_modified++; } else not_fixed++; } if (inode_modified) e2fsck_write_inode(ctx, ino, &inode, "process_bad_inode"); if (!not_fixed && ctx->inode_bad_map) ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, ino); return 0; }
errcode_t ext2fs_icount_increment(ext2_icount_t icount, ext2_ino_t ino, __u16 *ret) { struct ext2_icount_el *el; EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT); if (!ino || (ino > icount->num_inodes)) return EXT2_ET_INVALID_ARGUMENT; if (ext2fs_test_inode_bitmap(icount->single, ino)) { /* * If the existing count is 1, then we know there is * no entry in the list. */ el = get_icount_el(icount, ino, 1); if (!el) return EXT2_ET_NO_MEMORY; ext2fs_unmark_inode_bitmap(icount->single, ino); el->count = 2; } else if (icount->multiple) { /* * The count is either zero or greater than 1; if the * inode is set in icount->multiple, then there should * be an entry in the list, so find it using * get_icount_el(). */ if (ext2fs_test_inode_bitmap(icount->multiple, ino)) { el = get_icount_el(icount, ino, 1); if (!el) return EXT2_ET_NO_MEMORY; el->count++; } else { /* * The count was zero; mark the single bitmap * and return. */ zero_count: ext2fs_mark_inode_bitmap(icount->single, ino); if (ret) *ret = 1; return 0; } } else { /* * The count is either zero or greater than 1; try to * find an entry in the list to determine which. */ el = get_icount_el(icount, ino, 0); if (!el) { /* No entry means the count was zero */ goto zero_count; } el = get_icount_el(icount, ino, 1); if (!el) return EXT2_ET_NO_MEMORY; el->count++; } if (icount->multiple) ext2fs_mark_inode_bitmap(icount->multiple, ino); if (ret) *ret = el->count; return 0; }