void e2fsck_pass5(e2fsck_t ctx) { #ifdef RESOURCE_TRACK struct resource_track rtrack; #endif struct problem_context pctx; #ifdef MTRACE mtrace_print("Pass 5"); #endif #ifdef RESOURCE_TRACK init_resource_track(&rtrack); #endif clear_problem_context(&pctx); if (!(ctx->options & E2F_OPT_PREEN)) fix_problem(ctx, PR_5_PASS_HEADER, &pctx); if (ctx->progress) if ((ctx->progress)(ctx, 5, 0, ctx->fs->group_desc_count*2)) return; e2fsck_read_bitmaps(ctx); check_block_bitmaps(ctx); if (ctx->flags & E2F_FLAG_SIGNAL_MASK) return; check_inode_bitmaps(ctx); if (ctx->flags & E2F_FLAG_SIGNAL_MASK) return; check_inode_end(ctx); if (ctx->flags & E2F_FLAG_SIGNAL_MASK) return; check_block_end(ctx); if (ctx->flags & E2F_FLAG_SIGNAL_MASK) return; ext2fs_free_inode_bitmap(ctx->inode_used_map); ctx->inode_used_map = 0; ext2fs_free_inode_bitmap(ctx->inode_dir_map); ctx->inode_dir_map = 0; ext2fs_free_block_bitmap(ctx->block_found_map); ctx->block_found_map = 0; #ifdef RESOURCE_TRACK if (ctx->options & E2F_OPT_TIME2) { e2fsck_clear_progbar(ctx); print_resource_track(_("Pass 5"), &rtrack); } #endif }
void ext2fs_free_icount(ext2_icount_t icount) { if (!icount) return; icount->magic = 0; if (icount->list) ext2fs_free_mem(&icount->list); if (icount->single) ext2fs_free_inode_bitmap(icount->single); if (icount->multiple) ext2fs_free_inode_bitmap(icount->multiple); ext2fs_free_mem(&icount); }
void ext2fs_free(ext2_filsys fs) { if (!fs || (fs->magic != EXT2_ET_MAGIC_EXT2FS_FILSYS)) return; if (fs->image_io != fs->io) { if (fs->image_io) io_channel_close(fs->image_io); } if (fs->io) { io_channel_close(fs->io); } ext2fs_free_mem(&fs->device_name); ext2fs_free_mem(&fs->super); ext2fs_free_mem(&fs->orig_super); ext2fs_free_mem(&fs->group_desc); ext2fs_free_block_bitmap(fs->block_map); ext2fs_free_inode_bitmap(fs->inode_map); ext2fs_badblocks_list_free(fs->badblocks); fs->badblocks = 0; ext2fs_free_dblist(fs->dblist); if (fs->icache) ext2fs_free_inode_cache(fs->icache); fs->magic = 0; ext2fs_free_mem(&fs); }
void ext2fs_free_icount(ext2_icount_t icount) { if (!icount) return; icount->magic = 0; if (icount->list) ext2fs_free_mem(&icount->list); if (icount->single) ext2fs_free_inode_bitmap(icount->single); if (icount->multiple) ext2fs_free_inode_bitmap(icount->multiple); if (icount->tdb) tdb_close(icount->tdb); if (icount->tdb_fn) { unlink(icount->tdb_fn); free(icount->tdb_fn); } ext2fs_free_mem(&icount); }
void free_empty_dirblock(empty_dir_info edi) { if (!edi) return; if (edi->empty_dblist) ext2fs_free_dblist(edi->empty_dblist); if (edi->empty_dir_blocks) ext2fs_free_block_bitmap(edi->empty_dir_blocks); if (edi->dir_map) ext2fs_free_inode_bitmap(edi->dir_map); memset(edi, 0, sizeof(struct empty_dir_info_struct)); free(edi); }
static void setup_filesystem(const char *name, unsigned int blocks, unsigned int inodes, unsigned int type, int flags) { struct ext2_super_block param; errcode_t retval; memset(¶m, 0, sizeof(param)); ext2fs_blocks_count_set(¶m, blocks); param.s_inodes_count = inodes; retval = ext2fs_initialize("test fs", flags, ¶m, test_io_manager, &test_fs); if (retval) { com_err(name, retval, "while initializing filesystem"); return; } test_fs->default_bitmap_type = type; ext2fs_free_block_bitmap(test_fs->block_map); test_fs->block_map = 0; ext2fs_free_inode_bitmap(test_fs->inode_map); test_fs->inode_map = 0; retval = ext2fs_allocate_block_bitmap(test_fs, "block bitmap", &test_fs->block_map); if (retval) { com_err(name, retval, "while allocating block bitmap"); goto errout; } retval = ext2fs_allocate_inode_bitmap(test_fs, "inode bitmap", &test_fs->inode_map); if (retval) { com_err(name, retval, "while allocating inode bitmap"); goto errout; } return; errout: ext2fs_close_free(&test_fs); }
static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block) { dgrp_t i; char *block_bitmap = 0, *inode_bitmap = 0; char *buf; errcode_t retval; int block_nbytes = (int) EXT2_BLOCKS_PER_GROUP(fs->super) / 8; int inode_nbytes = (int) EXT2_INODES_PER_GROUP(fs->super) / 8; int lazy_flag = 0; blk_t blk; EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); fs->write_bitmaps = ext2fs_write_bitmaps; if (EXT2_HAS_COMPAT_FEATURE(fs->super, EXT2_FEATURE_COMPAT_LAZY_BG)) lazy_flag = 1; retval = ext2fs_get_mem(strlen(fs->device_name) + 80, &buf); if (retval) return retval; if (do_block) { if (fs->block_map) ext2fs_free_block_bitmap(fs->block_map); sprintf(buf, "block bitmap for %s", fs->device_name); retval = ext2fs_allocate_block_bitmap(fs, buf, &fs->block_map); if (retval) goto cleanup; block_bitmap = fs->block_map->bitmap; } if (do_inode) { if (fs->inode_map) ext2fs_free_inode_bitmap(fs->inode_map); sprintf(buf, "inode bitmap for %s", fs->device_name); retval = ext2fs_allocate_inode_bitmap(fs, buf, &fs->inode_map); if (retval) goto cleanup; inode_bitmap = fs->inode_map->bitmap; } ext2fs_free_mem(&buf); if (fs->flags & EXT2_FLAG_IMAGE_FILE) { if (inode_bitmap) { blk = (fs->image_header->offset_inodemap / fs->blocksize); retval = io_channel_read_blk(fs->image_io, blk, -(inode_nbytes * fs->group_desc_count), inode_bitmap); if (retval) goto cleanup; } if (block_bitmap) { blk = (fs->image_header->offset_blockmap / fs->blocksize); retval = io_channel_read_blk(fs->image_io, blk, -(block_nbytes * fs->group_desc_count), block_bitmap); if (retval) goto cleanup; } return 0; } for (i = 0; i < fs->group_desc_count; i++) { if (block_bitmap) { blk = fs->group_desc[i].bg_block_bitmap; if (lazy_flag && fs->group_desc[i].bg_flags & EXT2_BG_BLOCK_UNINIT) blk = 0; if (blk) { retval = io_channel_read_blk(fs->io, blk, -block_nbytes, block_bitmap); if (retval) { retval = EXT2_ET_BLOCK_BITMAP_READ; goto cleanup; } #ifdef EXT2_BIG_ENDIAN_BITMAPS if (!((fs->flags & EXT2_FLAG_SWAP_BYTES) || (fs->flags & EXT2_FLAG_SWAP_BYTES_READ))) ext2fs_swap_bitmap(fs, block_bitmap, block_nbytes); #endif } else memset(block_bitmap, 0xff, block_nbytes); block_bitmap += block_nbytes; } if (inode_bitmap) { blk = fs->group_desc[i].bg_inode_bitmap; if (lazy_flag && fs->group_desc[i].bg_flags & EXT2_BG_INODE_UNINIT) blk = 0; if (blk) { retval = io_channel_read_blk(fs->io, blk, -inode_nbytes, inode_bitmap); if (retval) { retval = EXT2_ET_INODE_BITMAP_READ; goto cleanup; } #ifdef EXT2_BIG_ENDIAN_BITMAPS if (!((fs->flags & EXT2_FLAG_SWAP_BYTES) || (fs->flags & EXT2_FLAG_SWAP_BYTES_READ))) ext2fs_swap_bitmap(fs, inode_bitmap, inode_nbytes); #endif } else memset(inode_bitmap, 0xff, inode_nbytes); inode_bitmap += inode_nbytes; } } return 0; cleanup: if (do_block) { ext2fs_free_mem(&fs->block_map); fs->block_map = 0; } if (do_inode) { ext2fs_free_mem(&fs->inode_map); fs->inode_map = 0; } if (buf) ext2fs_free_mem(&buf); return retval; }
static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block) { dgrp_t i; char *block_bitmap = 0, *inode_bitmap = 0; char *buf; errcode_t retval; int block_nbytes = EXT2_CLUSTERS_PER_GROUP(fs->super) / 8; int inode_nbytes = EXT2_INODES_PER_GROUP(fs->super) / 8; int csum_flag; unsigned int cnt; blk64_t blk; blk64_t blk_itr = EXT2FS_B2C(fs, fs->super->s_first_data_block); blk64_t blk_cnt; ext2_ino_t ino_itr = 1; ext2_ino_t ino_cnt; EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); if ((block_nbytes > (int) fs->blocksize) || (inode_nbytes > (int) fs->blocksize)) return EXT2_ET_CORRUPT_SUPERBLOCK; fs->write_bitmaps = ext2fs_write_bitmaps; csum_flag = ext2fs_has_group_desc_csum(fs); retval = ext2fs_get_mem(strlen(fs->device_name) + 80, &buf); if (retval) return retval; if (do_block) { if (fs->block_map) ext2fs_free_block_bitmap(fs->block_map); strcpy(buf, "block bitmap for "); strcat(buf, fs->device_name); retval = ext2fs_allocate_block_bitmap(fs, buf, &fs->block_map); if (retval) goto cleanup; retval = io_channel_alloc_buf(fs->io, 0, &block_bitmap); if (retval) goto cleanup; } else block_nbytes = 0; if (do_inode) { if (fs->inode_map) ext2fs_free_inode_bitmap(fs->inode_map); strcpy(buf, "inode bitmap for "); strcat(buf, fs->device_name); retval = ext2fs_allocate_inode_bitmap(fs, buf, &fs->inode_map); if (retval) goto cleanup; retval = io_channel_alloc_buf(fs->io, 0, &inode_bitmap); if (retval) goto cleanup; } else inode_nbytes = 0; ext2fs_free_mem(&buf); if (fs->flags & EXT2_FLAG_IMAGE_FILE) { blk = (ext2fs_le32_to_cpu(fs->image_header->offset_inodemap) / fs->blocksize); ino_cnt = fs->super->s_inodes_count; while (inode_bitmap && ino_cnt > 0) { retval = io_channel_read_blk64(fs->image_io, blk++, 1, inode_bitmap); if (retval) goto cleanup; cnt = fs->blocksize << 3; if (cnt > ino_cnt) cnt = ino_cnt; retval = ext2fs_set_inode_bitmap_range2(fs->inode_map, ino_itr, cnt, inode_bitmap); if (retval) goto cleanup; ino_itr += cnt; ino_cnt -= cnt; } blk = (ext2fs_le32_to_cpu(fs->image_header->offset_blockmap) / fs->blocksize); blk_cnt = EXT2_GROUPS_TO_CLUSTERS(fs->super, fs->group_desc_count); while (block_bitmap && blk_cnt > 0) { retval = io_channel_read_blk64(fs->image_io, blk++, 1, block_bitmap); if (retval) goto cleanup; cnt = fs->blocksize << 3; if (cnt > blk_cnt) cnt = blk_cnt; retval = ext2fs_set_block_bitmap_range2(fs->block_map, blk_itr, cnt, block_bitmap); if (retval) goto cleanup; blk_itr += cnt; blk_cnt -= cnt; } goto success_cleanup; } for (i = 0; i < fs->group_desc_count; i++) { if (block_bitmap) { blk = ext2fs_block_bitmap_loc(fs, i); if (csum_flag && ext2fs_bg_flags_test(fs, i, EXT2_BG_BLOCK_UNINIT) && ext2fs_group_desc_csum_verify(fs, i)) blk = 0; if (blk) { retval = io_channel_read_blk64(fs->io, blk, 1, block_bitmap); if (retval) { retval = EXT2_ET_BLOCK_BITMAP_READ; goto cleanup; } /* verify block bitmap checksum */ if (!(fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) && !ext2fs_block_bitmap_csum_verify(fs, i, block_bitmap, block_nbytes)) { retval = EXT2_ET_BLOCK_BITMAP_CSUM_INVALID; goto cleanup; } } else memset(block_bitmap, 0, block_nbytes); cnt = block_nbytes << 3; retval = ext2fs_set_block_bitmap_range2(fs->block_map, blk_itr, cnt, block_bitmap); if (retval) goto cleanup; blk_itr += block_nbytes << 3; } if (inode_bitmap) { blk = ext2fs_inode_bitmap_loc(fs, i); if (csum_flag && ext2fs_bg_flags_test(fs, i, EXT2_BG_INODE_UNINIT) && ext2fs_group_desc_csum_verify(fs, i)) blk = 0; if (blk) { retval = io_channel_read_blk64(fs->io, blk, 1, inode_bitmap); if (retval) { retval = EXT2_ET_INODE_BITMAP_READ; goto cleanup; } /* verify inode bitmap checksum */ if (!(fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) && !ext2fs_inode_bitmap_csum_verify(fs, i, inode_bitmap, inode_nbytes)) { retval = EXT2_ET_INODE_BITMAP_CSUM_INVALID; goto cleanup; } } else memset(inode_bitmap, 0, inode_nbytes); cnt = inode_nbytes << 3; retval = ext2fs_set_inode_bitmap_range2(fs->inode_map, ino_itr, cnt, inode_bitmap); if (retval) goto cleanup; ino_itr += inode_nbytes << 3; } } /* Mark group blocks for any BLOCK_UNINIT groups */ if (do_block) { retval = mark_uninit_bg_group_blocks(fs); if (retval) goto cleanup; } success_cleanup: if (inode_bitmap) ext2fs_free_mem(&inode_bitmap); if (block_bitmap) ext2fs_free_mem(&block_bitmap); return 0; cleanup: if (do_block) { ext2fs_free_mem(&fs->block_map); fs->block_map = 0; } if (do_inode) { ext2fs_free_mem(&fs->inode_map); fs->inode_map = 0; } if (inode_bitmap) ext2fs_free_mem(&inode_bitmap); if (block_bitmap) ext2fs_free_mem(&block_bitmap); if (buf) ext2fs_free_mem(&buf); return retval; }
void e2fsck_pass3(e2fsck_t ctx) { ext2_filsys fs = ctx->fs; struct dir_info_iter *iter; #ifdef RESOURCE_TRACK struct resource_track rtrack; #endif struct problem_context pctx; struct dir_info *dir; unsigned long maxdirs, count; init_resource_track(&rtrack, ctx->fs->io); clear_problem_context(&pctx); #ifdef MTRACE mtrace_print("Pass 3"); #endif if (!(ctx->options & E2F_OPT_PREEN)) fix_problem(ctx, PR_3_PASS_HEADER, &pctx); /* * Allocate some bitmaps to do loop detection. */ pctx.errcode = e2fsck_allocate_inode_bitmap(fs, _("inode done bitmap"), EXT2FS_BMAP64_AUTODIR, "inode_done_map", &inode_done_map); if (pctx.errcode) { pctx.num = 2; fix_problem(ctx, PR_3_ALLOCATE_IBITMAP_ERROR, &pctx); ctx->flags |= E2F_FLAG_ABORT; goto abort_exit; } print_resource_track(ctx, _("Peak memory"), &ctx->global_rtrack, NULL); check_root(ctx); if (ctx->flags & E2F_FLAG_SIGNAL_MASK) goto abort_exit; ext2fs_mark_inode_bitmap2(inode_done_map, EXT2_ROOT_INO); maxdirs = e2fsck_get_num_dirinfo(ctx); count = 1; if (ctx->progress) if ((ctx->progress)(ctx, 3, 0, maxdirs)) goto abort_exit; iter = e2fsck_dir_info_iter_begin(ctx); while ((dir = e2fsck_dir_info_iter(ctx, iter)) != 0) { if (ctx->flags & E2F_FLAG_SIGNAL_MASK) goto abort_exit; if (ctx->progress && (ctx->progress)(ctx, 3, count++, maxdirs)) goto abort_exit; if (ext2fs_test_inode_bitmap2(ctx->inode_dir_map, dir->ino)) if (check_directory(ctx, dir->ino, &pctx)) goto abort_exit; } e2fsck_dir_info_iter_end(ctx, iter); /* * Force the creation of /lost+found if not present */ if ((ctx->flags & E2F_OPT_READONLY) == 0) e2fsck_get_lost_and_found(ctx, 1); /* * If there are any directories that need to be indexed or * optimized, do it here. */ e2fsck_rehash_directories(ctx); abort_exit: e2fsck_free_dir_info(ctx); if (inode_loop_detect) { ext2fs_free_inode_bitmap(inode_loop_detect); inode_loop_detect = 0; } if (inode_done_map) { ext2fs_free_inode_bitmap(inode_done_map); inode_done_map = 0; } print_resource_track(ctx, _("Pass 3"), &rtrack, ctx->fs->io); }
void e2fsck_pass2(e2fsck_t ctx) { struct ext2_super_block *sb = ctx->fs->super; struct problem_context pctx; ext2_filsys fs = ctx->fs; char *buf; #ifdef RESOURCE_TRACK struct resource_track rtrack; #endif struct check_dir_struct cd; struct dx_dir_info *dx_dir; struct dx_dirblock_info *dx_db, *dx_parent; unsigned int save_type; int b; int i, depth; problem_t code; int bad_dir; init_resource_track(&rtrack, ctx->fs->io); clear_problem_context(&cd.pctx); #ifdef MTRACE mtrace_print("Pass 2"); #endif if (!(ctx->options & E2F_OPT_PREEN)) fix_problem(ctx, PR_2_PASS_HEADER, &cd.pctx); e2fsck_setup_tdb_icount(ctx, EXT2_ICOUNT_OPT_INCREMENT, &ctx->inode_count); if (ctx->inode_count) cd.pctx.errcode = 0; else { e2fsck_set_bitmap_type(fs, EXT2FS_BMAP64_RBTREE, "inode_count", &save_type); cd.pctx.errcode = ext2fs_create_icount2(fs, EXT2_ICOUNT_OPT_INCREMENT, 0, ctx->inode_link_info, &ctx->inode_count); fs->default_bitmap_type = save_type; } if (cd.pctx.errcode) { fix_problem(ctx, PR_2_ALLOCATE_ICOUNT, &cd.pctx); ctx->flags |= E2F_FLAG_ABORT; return; } buf = (char *) e2fsck_allocate_memory(ctx, 2*fs->blocksize, "directory scan buffer"); /* * Set up the parent pointer for the root directory, if * present. (If the root directory is not present, we will * create it in pass 3.) */ (void) e2fsck_dir_info_set_parent(ctx, EXT2_ROOT_INO, EXT2_ROOT_INO); cd.buf = buf; cd.ctx = ctx; cd.count = 1; cd.max = ext2fs_dblist_count2(fs->dblist); if (ctx->progress) (void) (ctx->progress)(ctx, 2, 0, cd.max); if (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) ext2fs_dblist_sort2(fs->dblist, special_dir_block_cmp); cd.pctx.errcode = ext2fs_dblist_iterate2(fs->dblist, check_dir_block, &cd); if (ctx->flags & E2F_FLAG_SIGNAL_MASK || ctx->flags & E2F_FLAG_RESTART) return; if (ctx->flags & E2F_FLAG_RESTART_LATER) { ctx->flags |= E2F_FLAG_RESTART; return; } if (cd.pctx.errcode) { fix_problem(ctx, PR_2_DBLIST_ITERATE, &cd.pctx); ctx->flags |= E2F_FLAG_ABORT; return; } #ifdef ENABLE_HTREE for (i=0; (dx_dir = e2fsck_dx_dir_info_iter(ctx, &i)) != 0;) { if (ctx->flags & E2F_FLAG_SIGNAL_MASK) return; if (dx_dir->numblocks == 0) continue; clear_problem_context(&pctx); bad_dir = 0; pctx.dir = dx_dir->ino; dx_db = dx_dir->dx_block; if (dx_db->flags & DX_FLAG_REFERENCED) dx_db->flags |= DX_FLAG_DUP_REF; else dx_db->flags |= DX_FLAG_REFERENCED; /* * Find all of the first and last leaf blocks, and * update their parent's min and max hash values */ for (b=0, dx_db = dx_dir->dx_block; b < dx_dir->numblocks; b++, dx_db++) { if ((dx_db->type != DX_DIRBLOCK_LEAF) || !(dx_db->flags & (DX_FLAG_FIRST | DX_FLAG_LAST))) continue; dx_parent = &dx_dir->dx_block[dx_db->parent]; /* * XXX Make sure dx_parent->min_hash > dx_db->min_hash */ if (dx_db->flags & DX_FLAG_FIRST) dx_parent->min_hash = dx_db->min_hash; /* * XXX Make sure dx_parent->max_hash < dx_db->max_hash */ if (dx_db->flags & DX_FLAG_LAST) dx_parent->max_hash = dx_db->max_hash; } for (b=0, dx_db = dx_dir->dx_block; b < dx_dir->numblocks; b++, dx_db++) { pctx.blkcount = b; pctx.group = dx_db->parent; code = 0; if (!(dx_db->flags & DX_FLAG_FIRST) && (dx_db->min_hash < dx_db->node_min_hash)) { pctx.blk = dx_db->min_hash; pctx.blk2 = dx_db->node_min_hash; code = PR_2_HTREE_MIN_HASH; fix_problem(ctx, code, &pctx); bad_dir++; } if (dx_db->type == DX_DIRBLOCK_LEAF) { depth = htree_depth(dx_dir, dx_db); if (depth != dx_dir->depth) { pctx.num = dx_dir->depth; code = PR_2_HTREE_BAD_DEPTH; fix_problem(ctx, code, &pctx); bad_dir++; } } /* * This test doesn't apply for the root block * at block #0 */ if (b && (dx_db->max_hash > dx_db->node_max_hash)) { pctx.blk = dx_db->max_hash; pctx.blk2 = dx_db->node_max_hash; code = PR_2_HTREE_MAX_HASH; fix_problem(ctx, code, &pctx); bad_dir++; } if (!(dx_db->flags & DX_FLAG_REFERENCED)) { code = PR_2_HTREE_NOTREF; fix_problem(ctx, code, &pctx); bad_dir++; } else if (dx_db->flags & DX_FLAG_DUP_REF) { code = PR_2_HTREE_DUPREF; fix_problem(ctx, code, &pctx); bad_dir++; } } if (bad_dir && fix_problem(ctx, PR_2_HTREE_CLEAR, &pctx)) { clear_htree(ctx, dx_dir->ino); dx_dir->numblocks = 0; } } e2fsck_free_dx_dir_info(ctx); #endif ext2fs_free_mem(&buf); ext2fs_free_dblist(fs->dblist); if (ctx->inode_bad_map) { ext2fs_free_inode_bitmap(ctx->inode_bad_map); ctx->inode_bad_map = 0; } if (ctx->inode_reg_map) { ext2fs_free_inode_bitmap(ctx->inode_reg_map); ctx->inode_reg_map = 0; } clear_problem_context(&pctx); if (ctx->large_files) { if (!(sb->s_feature_ro_compat & EXT2_FEATURE_RO_COMPAT_LARGE_FILE) && fix_problem(ctx, PR_2_FEATURE_LARGE_FILES, &pctx)) { sb->s_feature_ro_compat |= EXT2_FEATURE_RO_COMPAT_LARGE_FILE; fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY; ext2fs_mark_super_dirty(fs); } if (sb->s_rev_level == EXT2_GOOD_OLD_REV && fix_problem(ctx, PR_1_FS_REV_LEVEL, &pctx)) { ext2fs_update_dynamic_rev(fs); ext2fs_mark_super_dirty(fs); } } print_resource_track(ctx, _("Pass 2"), &rtrack, fs->io); }
void e2fsck_pass2(e2fsck_t ctx) { struct ext2_super_block *sb = ctx->fs->super; struct problem_context pctx; ext2_filsys fs = ctx->fs; char *buf; #ifdef RESOURCE_TRACK struct resource_track rtrack; #endif struct dir_info *dir; struct check_dir_struct cd; #ifdef RESOURCE_TRACK init_resource_track(&rtrack); #endif clear_problem_context(&cd.pctx); #ifdef MTRACE mtrace_print("Pass 2"); #endif if (!(ctx->options & E2F_OPT_PREEN)) fix_problem(ctx, PR_2_PASS_HEADER, &cd.pctx); cd.pctx.errcode = ext2fs_create_icount2(fs, EXT2_ICOUNT_OPT_INCREMENT, 0, ctx->inode_link_info, &ctx->inode_count); if (cd.pctx.errcode) { fix_problem(ctx, PR_2_ALLOCATE_ICOUNT, &cd.pctx); ctx->flags |= E2F_FLAG_ABORT; return; } buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize, "directory scan buffer"); /* * Set up the parent pointer for the root directory, if * present. (If the root directory is not present, we will * create it in pass 3.) */ dir = e2fsck_get_dir_info(ctx, EXT2_ROOT_INO); if (dir) dir->parent = EXT2_ROOT_INO; cd.buf = buf; cd.ctx = ctx; cd.count = 1; cd.max = ext2fs_dblist_count(fs->dblist); if (ctx->progress) (void) (ctx->progress)(ctx, 2, 0, cd.max); cd.pctx.errcode = ext2fs_dblist_iterate(fs->dblist, check_dir_block, &cd); if (ctx->flags & E2F_FLAG_SIGNAL_MASK) return; if (cd.pctx.errcode) { fix_problem(ctx, PR_2_DBLIST_ITERATE, &cd.pctx); ctx->flags |= E2F_FLAG_ABORT; return; } ext2fs_free_mem((void **) &buf); ext2fs_free_dblist(fs->dblist); if (ctx->inode_bad_map) { ext2fs_free_inode_bitmap(ctx->inode_bad_map); ctx->inode_bad_map = 0; } if (ctx->inode_reg_map) { ext2fs_free_inode_bitmap(ctx->inode_reg_map); ctx->inode_reg_map = 0; } clear_problem_context(&pctx); if (ctx->large_files) { if (!(sb->s_feature_ro_compat & EXT2_FEATURE_RO_COMPAT_LARGE_FILE) && fix_problem(ctx, PR_2_FEATURE_LARGE_FILES, &pctx)) { sb->s_feature_ro_compat |= EXT2_FEATURE_RO_COMPAT_LARGE_FILE; ext2fs_mark_super_dirty(fs); } if (sb->s_rev_level == EXT2_GOOD_OLD_REV && fix_problem(ctx, PR_1_FS_REV_LEVEL, &pctx)) { ext2fs_update_dynamic_rev(fs); ext2fs_mark_super_dirty(fs); } } else if (!ctx->large_files && (sb->s_feature_ro_compat & EXT2_FEATURE_RO_COMPAT_LARGE_FILE)) { if (fs->flags & EXT2_FLAG_RW) { sb->s_feature_ro_compat &= ~EXT2_FEATURE_RO_COMPAT_LARGE_FILE; ext2fs_mark_super_dirty(fs); } } #ifdef RESOURCE_TRACK if (ctx->options & E2F_OPT_TIME2) { e2fsck_clear_progbar(ctx); print_resource_track("Pass 2", &rtrack); } #endif }
/* * This function resets an e2fsck context; it is called when e2fsck * needs to be restarted. */ errcode_t e2fsck_reset_context(e2fsck_t ctx) { int i; ctx->flags &= E2F_RESET_FLAGS; ctx->lost_and_found = 0; ctx->bad_lost_and_found = 0; if (ctx->inode_used_map) { ext2fs_free_inode_bitmap(ctx->inode_used_map); ctx->inode_used_map = 0; } if (ctx->inode_dir_map) { ext2fs_free_inode_bitmap(ctx->inode_dir_map); ctx->inode_dir_map = 0; } if (ctx->inode_reg_map) { ext2fs_free_inode_bitmap(ctx->inode_reg_map); ctx->inode_reg_map = 0; } if (ctx->block_found_map) { ext2fs_free_block_bitmap(ctx->block_found_map); ctx->block_found_map = 0; } if (ctx->inode_link_info) { ext2fs_free_icount(ctx->inode_link_info); ctx->inode_link_info = 0; } if (ctx->journal_io) { if (ctx->fs && ctx->fs->io != ctx->journal_io) io_channel_close(ctx->journal_io); ctx->journal_io = 0; } if (ctx->fs && ctx->fs->dblist) { ext2fs_free_dblist(ctx->fs->dblist); ctx->fs->dblist = 0; } e2fsck_free_dir_info(ctx); e2fsck_free_dx_dir_info(ctx); if (ctx->refcount) { ea_refcount_free(ctx->refcount); ctx->refcount = 0; } if (ctx->refcount_extra) { ea_refcount_free(ctx->refcount_extra); ctx->refcount_extra = 0; } if (ctx->block_dup_map) { ext2fs_free_block_bitmap(ctx->block_dup_map); ctx->block_dup_map = 0; } if (ctx->block_ea_map) { ext2fs_free_block_bitmap(ctx->block_ea_map); ctx->block_ea_map = 0; } if (ctx->block_metadata_map) { ext2fs_free_block_bitmap(ctx->block_metadata_map); ctx->block_metadata_map = 0; } if (ctx->inode_bb_map) { ext2fs_free_inode_bitmap(ctx->inode_bb_map); ctx->inode_bb_map = 0; } if (ctx->inode_bad_map) { ext2fs_free_inode_bitmap(ctx->inode_bad_map); ctx->inode_bad_map = 0; } if (ctx->inode_imagic_map) { ext2fs_free_inode_bitmap(ctx->inode_imagic_map); ctx->inode_imagic_map = 0; } if (ctx->dirs_to_hash) { ext2fs_u32_list_free(ctx->dirs_to_hash); ctx->dirs_to_hash = 0; } /* * Clear the array of invalid meta-data flags */ if (ctx->invalid_inode_bitmap_flag) { ext2fs_free_mem(&ctx->invalid_inode_bitmap_flag); ctx->invalid_inode_bitmap_flag = 0; } if (ctx->invalid_block_bitmap_flag) { ext2fs_free_mem(&ctx->invalid_block_bitmap_flag); ctx->invalid_block_bitmap_flag = 0; } if (ctx->invalid_inode_table_flag) { ext2fs_free_mem(&ctx->invalid_inode_table_flag); ctx->invalid_inode_table_flag = 0; } if (ctx->encrypted_dirs) { ext2fs_u32_list_free(ctx->encrypted_dirs); ctx->encrypted_dirs = 0; } if (ctx->inode_count) { ext2fs_free_icount(ctx->inode_count); ctx->inode_count = 0; } /* Clear statistic counters */ ctx->fs_directory_count = 0; ctx->fs_regular_count = 0; ctx->fs_blockdev_count = 0; ctx->fs_chardev_count = 0; ctx->fs_links_count = 0; ctx->fs_symlinks_count = 0; ctx->fs_fast_symlinks_count = 0; ctx->fs_fifo_count = 0; ctx->fs_total_count = 0; ctx->fs_badblocks_count = 0; ctx->fs_sockets_count = 0; ctx->fs_ind_count = 0; ctx->fs_dind_count = 0; ctx->fs_tind_count = 0; ctx->fs_fragmented = 0; ctx->fs_fragmented_dir = 0; ctx->large_files = 0; for (i=0; i < MAX_EXTENT_DEPTH_COUNT; i++) ctx->extent_depth_count[i] = 0; /* Reset the superblock to the user's requested value */ ctx->superblock = ctx->use_superblock; return 0; }
static void check_inode_bitmaps(e2fsck_t ctx) { ext2_filsys fs = ctx->fs; ext2_ino_t i; unsigned int free_inodes = 0; int group_free = 0; int dirs_count = 0; int group = 0; unsigned int inodes = 0; ext2_ino_t *free_array; ext2_ino_t *dir_array; int actual, bitmap; errcode_t retval; struct problem_context pctx; int problem, save_problem, fixit, had_problem; int csum_flag; int skip_group = 0; int redo_flag = 0; ext2_ino_t first_free = fs->super->s_inodes_per_group + 1; clear_problem_context(&pctx); free_array = (ext2_ino_t *) e2fsck_allocate_memory(ctx, fs->group_desc_count * sizeof(ext2_ino_t), "free inode count array"); dir_array = (ext2_ino_t *) e2fsck_allocate_memory(ctx, fs->group_desc_count * sizeof(ext2_ino_t), "directory count array"); if ((1 < ext2fs_get_inode_bitmap_start2(ctx->inode_used_map)) || (fs->super->s_inodes_count > ext2fs_get_inode_bitmap_end2(ctx->inode_used_map))) { pctx.num = 3; pctx.blk = 1; pctx.blk2 = fs->super->s_inodes_count; pctx.ino = ext2fs_get_inode_bitmap_start2(ctx->inode_used_map); pctx.ino2 = ext2fs_get_inode_bitmap_end2(ctx->inode_used_map); fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx); ctx->flags |= E2F_FLAG_ABORT; /* fatal */ goto errout; } if ((1 < ext2fs_get_inode_bitmap_start2(fs->inode_map)) || (fs->super->s_inodes_count > ext2fs_get_inode_bitmap_end2(fs->inode_map))) { pctx.num = 4; pctx.blk = 1; pctx.blk2 = fs->super->s_inodes_count; pctx.ino = ext2fs_get_inode_bitmap_start2(fs->inode_map); pctx.ino2 = ext2fs_get_inode_bitmap_end2(fs->inode_map); fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx); ctx->flags |= E2F_FLAG_ABORT; /* fatal */ goto errout; } csum_flag = EXT2_HAS_RO_COMPAT_FEATURE(fs->super, EXT4_FEATURE_RO_COMPAT_GDT_CSUM); redo_counts: had_problem = 0; save_problem = 0; pctx.ino = pctx.ino2 = 0; if (csum_flag && (ext2fs_bg_flags_test(fs, group, EXT2_BG_INODE_UNINIT))) skip_group++; /* Protect loop from wrap-around if inodes_count is maxed */ for (i = 1; i <= fs->super->s_inodes_count && i > 0; i++) { bitmap = 0; if (skip_group && i % fs->super->s_inodes_per_group == 1) { /* * Current inode is the first inode * in the current block group. */ if (ext2fs_test_inode_bitmap_range( ctx->inode_used_map, i, fs->super->s_inodes_per_group)) { /* * When the compared inodes in inodes bitmap * are 0, count the free inode, * skip the current block group. */ first_free = 1; inodes = fs->super->s_inodes_per_group - 1; group_free = inodes; free_inodes += inodes; i += inodes; skip_group = 0; goto do_counts; } } actual = ext2fs_fast_test_inode_bitmap2(ctx->inode_used_map, i); if (redo_flag) bitmap = actual; else if (!skip_group) bitmap = ext2fs_fast_test_inode_bitmap2(fs->inode_map, i); if (!actual == !bitmap) goto do_counts; if (!actual && bitmap) { /* * Inode wasn't used, but marked in bitmap */ problem = PR_5_INODE_UNUSED; } else /* if (actual && !bitmap) */ { /* * Inode used, but not in bitmap */ problem = PR_5_INODE_USED; /* We should never hit this, because it means that * inodes were marked in use that weren't noticed * in pass1 or pass 2. It is easier to fix the problem * than to kill e2fsck and leave the user stuck. */ if (skip_group) { struct problem_context pctx2; pctx2.blk = i; pctx2.group = group; if (fix_problem(ctx, PR_5_INODE_UNINIT,&pctx2)){ ext2fs_bg_flags_clear(fs, group, EXT2_BG_INODE_UNINIT); skip_group = 0; } } } if (pctx.ino == 0) { pctx.ino = pctx.ino2 = i; save_problem = problem; } else { if ((problem == save_problem) && (pctx.ino2 == i-1)) pctx.ino2++; else { print_bitmap_problem(ctx, save_problem, &pctx); pctx.ino = pctx.ino2 = i; save_problem = problem; } } ctx->flags |= E2F_FLAG_PROG_SUPPRESS; had_problem++; /* * If there a problem we should turn off the discard so we * do not compromise the filesystem. */ ctx->options &= ~E2F_OPT_DISCARD; do_counts: inodes++; if (bitmap) { if (ext2fs_test_inode_bitmap2(ctx->inode_dir_map, i)) dirs_count++; if (inodes > first_free) { e2fsck_discard_inodes(ctx, group, first_free, inodes - first_free); first_free = fs->super->s_inodes_per_group + 1; } } else { group_free++; free_inodes++; if (first_free > inodes) first_free = inodes; } if ((inodes == fs->super->s_inodes_per_group) || (i == fs->super->s_inodes_count)) { /* * If the last inode is free, we can discard it as well. */ if (!bitmap && inodes >= first_free) e2fsck_discard_inodes(ctx, group, first_free, inodes - first_free + 1); /* * If discard zeroes data and the group inode table * was not zeroed yet, set itable as zeroed */ if ((ctx->options & E2F_OPT_DISCARD) && io_channel_discard_zeroes_data(fs->io) && !(ext2fs_bg_flags_test(fs, group, EXT2_BG_INODE_ZEROED))) { ext2fs_bg_flags_set(fs, group, EXT2_BG_INODE_ZEROED); ext2fs_group_desc_csum_set(fs, group); } first_free = fs->super->s_inodes_per_group + 1; free_array[group] = group_free; dir_array[group] = dirs_count; group ++; inodes = 0; skip_group = 0; group_free = 0; dirs_count = 0; if (ctx->progress) if ((ctx->progress)(ctx, 5, group + fs->group_desc_count, fs->group_desc_count*2)) goto errout; if (csum_flag && (i != fs->super->s_inodes_count) && (ext2fs_bg_flags_test(fs, group, EXT2_BG_INODE_UNINIT) )) skip_group++; } } if (pctx.ino) print_bitmap_problem(ctx, save_problem, &pctx); if (had_problem) fixit = end_problem_latch(ctx, PR_LATCH_IBITMAP); else fixit = -1; ctx->flags &= ~E2F_FLAG_PROG_SUPPRESS; if (fixit == 1) { ext2fs_free_inode_bitmap(fs->inode_map); retval = ext2fs_copy_bitmap(ctx->inode_used_map, &fs->inode_map); if (retval) { clear_problem_context(&pctx); fix_problem(ctx, PR_5_COPY_IBITMAP_ERROR, &pctx); ctx->flags |= E2F_FLAG_ABORT; goto errout; } ext2fs_set_bitmap_padding(fs->inode_map); ext2fs_mark_ib_dirty(fs); /* redo counts */ inodes = 0; free_inodes = 0; group_free = 0; dirs_count = 0; group = 0; memset(free_array, 0, fs->group_desc_count * sizeof(int)); memset(dir_array, 0, fs->group_desc_count * sizeof(int)); redo_flag++; goto redo_counts; } else if (fixit == 0) ext2fs_unmark_valid(fs); for (i = 0; i < fs->group_desc_count; i++) { if (free_array[i] != ext2fs_bg_free_inodes_count(fs, i)) { pctx.group = i; pctx.ino = ext2fs_bg_free_inodes_count(fs, i); pctx.ino2 = free_array[i]; if (fix_problem(ctx, PR_5_FREE_INODE_COUNT_GROUP, &pctx)) { ext2fs_bg_free_inodes_count_set(fs, i, free_array[i]); ext2fs_mark_super_dirty(fs); } else ext2fs_unmark_valid(fs); } if (dir_array[i] != ext2fs_bg_used_dirs_count(fs, i)) { pctx.group = i; pctx.ino = ext2fs_bg_used_dirs_count(fs, i); pctx.ino2 = dir_array[i]; if (fix_problem(ctx, PR_5_FREE_DIR_COUNT_GROUP, &pctx)) { ext2fs_bg_used_dirs_count_set(fs, i, dir_array[i]); ext2fs_mark_super_dirty(fs); } else ext2fs_unmark_valid(fs); } } if (free_inodes != fs->super->s_free_inodes_count) { pctx.group = -1; pctx.ino = fs->super->s_free_inodes_count; pctx.ino2 = free_inodes; if (fix_problem(ctx, PR_5_FREE_INODE_COUNT, &pctx)) { fs->super->s_free_inodes_count = free_inodes; ext2fs_mark_super_dirty(fs); } } errout: ext2fs_free_mem(&free_array); ext2fs_free_mem(&dir_array); }
void e2fsck_pass4(e2fsck_t ctx) { ext2_filsys fs = ctx->fs; ext2_ino_t i; struct ext2_inode inode; #ifdef RESOURCE_TRACK struct resource_track rtrack; #endif struct problem_context pctx; __u16 link_count, link_counted; char *buf = 0; int group, maxgroup; #ifdef RESOURCE_TRACK init_resource_track(&rtrack); #endif #ifdef MTRACE mtrace_print("Pass 4"); #endif clear_problem_context(&pctx); if (!(ctx->options & E2F_OPT_PREEN)) fix_problem(ctx, PR_4_PASS_HEADER, &pctx); group = 0; maxgroup = fs->group_desc_count; if (ctx->progress) if ((ctx->progress)(ctx, 4, 0, maxgroup)) return; /* Protect loop from wrap-around if s_inodes_count maxed */ for (i=1; i <= fs->super->s_inodes_count && i > 0; i++) { if (ctx->flags & E2F_FLAG_SIGNAL_MASK) goto errout; if ((i % fs->super->s_inodes_per_group) == 0) { group++; if (ctx->progress) if ((ctx->progress)(ctx, 4, group, maxgroup)) goto errout; } if (i == EXT2_BAD_INO || (i > EXT2_ROOT_INO && i < EXT2_FIRST_INODE(fs->super))) continue; if (!(ext2fs_test_inode_bitmap(ctx->inode_used_map, i)) || (ctx->inode_imagic_map && ext2fs_test_inode_bitmap(ctx->inode_imagic_map, i)) || (ctx->inode_bb_map && ext2fs_test_inode_bitmap(ctx->inode_bb_map, i))) continue; ext2fs_icount_fetch(ctx->inode_link_info, i, &link_count); ext2fs_icount_fetch(ctx->inode_count, i, &link_counted); if (link_counted == 0) { if (!buf) buf = e2fsck_allocate_memory(ctx, fs->blocksize, "bad_inode buffer"); if (e2fsck_process_bad_inode(ctx, 0, i, buf)) continue; if (disconnect_inode(ctx, i)) continue; ext2fs_icount_fetch(ctx->inode_link_info, i, &link_count); ext2fs_icount_fetch(ctx->inode_count, i, &link_counted); } if (link_counted != link_count) { e2fsck_read_inode(ctx, i, &inode, "pass4"); pctx.ino = i; pctx.inode = &inode; if (link_count != inode.i_links_count) { pctx.num = link_count; fix_problem(ctx, PR_4_INCONSISTENT_COUNT, &pctx); } pctx.num = link_counted; if (fix_problem(ctx, PR_4_BAD_REF_COUNT, &pctx)) { inode.i_links_count = link_counted; e2fsck_write_inode(ctx, i, &inode, "pass4"); } } } ext2fs_free_icount(ctx->inode_link_info); ctx->inode_link_info = 0; ext2fs_free_icount(ctx->inode_count); ctx->inode_count = 0; ext2fs_free_inode_bitmap(ctx->inode_bb_map); ctx->inode_bb_map = 0; ext2fs_free_inode_bitmap(ctx->inode_imagic_map); ctx->inode_imagic_map = 0; errout: if (buf) ext2fs_free_mem(&buf); #ifdef RESOURCE_TRACK if (ctx->options & E2F_OPT_TIME2) { e2fsck_clear_progbar(ctx); print_resource_track(_("Pass 4"), &rtrack); } #endif }
static void check_inode_bitmaps(e2fsck_t ctx) { ext2_filsys fs = ctx->fs; ext2_ino_t i; unsigned int free_inodes = 0; int group_free = 0; int dirs_count = 0; int group = 0; unsigned int inodes = 0; int *free_array; int *dir_array; int actual, bitmap; errcode_t retval; struct problem_context pctx; int problem, save_problem, fixit, had_problem; int lazy_bg = 0; int skip_group = 0; clear_problem_context(&pctx); free_array = (int *) e2fsck_allocate_memory(ctx, fs->group_desc_count * sizeof(int), "free inode count array"); dir_array = (int *) e2fsck_allocate_memory(ctx, fs->group_desc_count * sizeof(int), "directory count array"); if ((1 < ext2fs_get_inode_bitmap_start(ctx->inode_used_map)) || (fs->super->s_inodes_count > ext2fs_get_inode_bitmap_end(ctx->inode_used_map))) { pctx.num = 3; pctx.blk = 1; pctx.blk2 = fs->super->s_inodes_count; pctx.ino = ext2fs_get_inode_bitmap_start(ctx->inode_used_map); pctx.ino2 = ext2fs_get_inode_bitmap_end(ctx->inode_used_map); fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx); ctx->flags |= E2F_FLAG_ABORT; /* fatal */ goto errout; } if ((1 < ext2fs_get_inode_bitmap_start(fs->inode_map)) || (fs->super->s_inodes_count > ext2fs_get_inode_bitmap_end(fs->inode_map))) { pctx.num = 4; pctx.blk = 1; pctx.blk2 = fs->super->s_inodes_count; pctx.ino = ext2fs_get_inode_bitmap_start(fs->inode_map); pctx.ino2 = ext2fs_get_inode_bitmap_end(fs->inode_map); fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx); ctx->flags |= E2F_FLAG_ABORT; /* fatal */ goto errout; } if (EXT2_HAS_COMPAT_FEATURE(fs->super, EXT2_FEATURE_COMPAT_LAZY_BG)) lazy_bg++; redo_counts: had_problem = 0; save_problem = 0; pctx.ino = pctx.ino2 = 0; if (lazy_bg && (fs->group_desc[group].bg_flags & EXT2_BG_INODE_UNINIT)) skip_group++; /* Protect loop from wrap-around if inodes_count is maxed */ for (i = 1; i <= fs->super->s_inodes_count && i > 0; i++) { actual = ext2fs_fast_test_inode_bitmap(ctx->inode_used_map, i); if (skip_group) bitmap = 0; else bitmap = ext2fs_fast_test_inode_bitmap(fs->inode_map, i); if (actual == bitmap) goto do_counts; if (!actual && bitmap) { /* * Inode wasn't used, but marked in bitmap */ problem = PR_5_INODE_UNUSED; } else /* if (actual && !bitmap) */ { /* * Inode used, but not in bitmap */ problem = PR_5_INODE_USED; } if (pctx.ino == 0) { pctx.ino = pctx.ino2 = i; save_problem = problem; } else { if ((problem == save_problem) && (pctx.ino2 == i-1)) pctx.ino2++; else { print_bitmap_problem(ctx, save_problem, &pctx); pctx.ino = pctx.ino2 = i; save_problem = problem; } } ctx->flags |= E2F_FLAG_PROG_SUPPRESS; had_problem++; do_counts: if (bitmap) { if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, i)) dirs_count++; } else if (!skip_group) { group_free++; free_inodes++; } inodes++; if ((inodes == fs->super->s_inodes_per_group) || (i == fs->super->s_inodes_count)) { free_array[group] = group_free; dir_array[group] = dirs_count; group ++; inodes = 0; skip_group = 0; group_free = 0; dirs_count = 0; if (ctx->progress) if ((ctx->progress)(ctx, 5, group + fs->group_desc_count, fs->group_desc_count*2)) goto errout; if (lazy_bg && (i != fs->super->s_inodes_count) && (fs->group_desc[group].bg_flags & EXT2_BG_INODE_UNINIT)) skip_group++; } } if (pctx.ino) print_bitmap_problem(ctx, save_problem, &pctx); if (had_problem) fixit = end_problem_latch(ctx, PR_LATCH_IBITMAP); else fixit = -1; ctx->flags &= ~E2F_FLAG_PROG_SUPPRESS; if (fixit == 1) { ext2fs_free_inode_bitmap(fs->inode_map); retval = ext2fs_copy_bitmap(ctx->inode_used_map, &fs->inode_map); if (retval) { clear_problem_context(&pctx); fix_problem(ctx, PR_5_COPY_IBITMAP_ERROR, &pctx); ctx->flags |= E2F_FLAG_ABORT; goto errout; } ext2fs_set_bitmap_padding(fs->inode_map); ext2fs_mark_ib_dirty(fs); /* redo counts */ inodes = 0; free_inodes = 0; group_free = 0; dirs_count = 0; group = 0; memset(free_array, 0, fs->group_desc_count * sizeof(int)); memset(dir_array, 0, fs->group_desc_count * sizeof(int)); goto redo_counts; } else if (fixit == 0) ext2fs_unmark_valid(fs); for (i = 0; i < fs->group_desc_count; i++) { if (free_array[i] != fs->group_desc[i].bg_free_inodes_count) { pctx.group = i; pctx.ino = fs->group_desc[i].bg_free_inodes_count; pctx.ino2 = free_array[i]; if (fix_problem(ctx, PR_5_FREE_INODE_COUNT_GROUP, &pctx)) { fs->group_desc[i].bg_free_inodes_count = free_array[i]; ext2fs_mark_super_dirty(fs); } else ext2fs_unmark_valid(fs); } if (dir_array[i] != fs->group_desc[i].bg_used_dirs_count) { pctx.group = i; pctx.ino = fs->group_desc[i].bg_used_dirs_count; pctx.ino2 = dir_array[i]; if (fix_problem(ctx, PR_5_FREE_DIR_COUNT_GROUP, &pctx)) { fs->group_desc[i].bg_used_dirs_count = dir_array[i]; ext2fs_mark_super_dirty(fs); } else ext2fs_unmark_valid(fs); } } if (free_inodes != fs->super->s_free_inodes_count) { pctx.group = -1; pctx.ino = fs->super->s_free_inodes_count; pctx.ino2 = free_inodes; if (fix_problem(ctx, PR_5_FREE_INODE_COUNT, &pctx)) { fs->super->s_free_inodes_count = free_inodes; ext2fs_mark_super_dirty(fs); } else ext2fs_unmark_valid(fs); } errout: ext2fs_free_mem(&free_array); ext2fs_free_mem(&dir_array); }
/* * This function resets an e2fsck context; it is called when e2fsck * needs to be restarted. */ errcode_t e2fsck_reset_context(e2fsck_t ctx) { ctx->flags = 0; ctx->lost_and_found = 0; ctx->bad_lost_and_found = 0; if (ctx->inode_used_map) { ext2fs_free_inode_bitmap(ctx->inode_used_map); ctx->inode_used_map = 0; } if (ctx->inode_dir_map) { ext2fs_free_inode_bitmap(ctx->inode_dir_map); ctx->inode_dir_map = 0; } if (ctx->inode_reg_map) { ext2fs_free_inode_bitmap(ctx->inode_reg_map); ctx->inode_reg_map = 0; } if (ctx->block_found_map) { ext2fs_free_block_bitmap(ctx->block_found_map); ctx->block_found_map = 0; } if (ctx->inode_link_info) { ext2fs_free_icount(ctx->inode_link_info); ctx->inode_link_info = 0; } if (ctx->journal_io) { if (ctx->fs && ctx->fs->io != ctx->journal_io) io_channel_close(ctx->journal_io); ctx->journal_io = 0; } if (ctx->fs && ctx->fs->dblist) { ext2fs_free_dblist(ctx->fs->dblist); ctx->fs->dblist = 0; } e2fsck_free_dir_info(ctx); #ifdef ENABLE_HTREE e2fsck_free_dx_dir_info(ctx); #endif if (ctx->refcount) { ea_refcount_free(ctx->refcount); ctx->refcount = 0; } if (ctx->refcount_extra) { ea_refcount_free(ctx->refcount_extra); ctx->refcount_extra = 0; } if (ctx->block_dup_map) { ext2fs_free_block_bitmap(ctx->block_dup_map); ctx->block_dup_map = 0; } if (ctx->block_ea_map) { ext2fs_free_block_bitmap(ctx->block_ea_map); ctx->block_ea_map = 0; } if (ctx->inode_bb_map) { ext2fs_free_inode_bitmap(ctx->inode_bb_map); ctx->inode_bb_map = 0; } if (ctx->inode_bad_map) { ext2fs_free_inode_bitmap(ctx->inode_bad_map); ctx->inode_bad_map = 0; } if (ctx->inode_imagic_map) { ext2fs_free_inode_bitmap(ctx->inode_imagic_map); ctx->inode_imagic_map = 0; } if (ctx->dirs_to_hash) { ext2fs_u32_list_free(ctx->dirs_to_hash); ctx->dirs_to_hash = 0; } /* * Clear the array of invalid meta-data flags */ if (ctx->invalid_inode_bitmap_flag) { ext2fs_free_mem(&ctx->invalid_inode_bitmap_flag); ctx->invalid_inode_bitmap_flag = 0; } if (ctx->invalid_block_bitmap_flag) { ext2fs_free_mem(&ctx->invalid_block_bitmap_flag); ctx->invalid_block_bitmap_flag = 0; } if (ctx->invalid_inode_table_flag) { ext2fs_free_mem(&ctx->invalid_inode_table_flag); ctx->invalid_inode_table_flag = 0; } /* Clear statistic counters */ ctx->fs_directory_count = 0; ctx->fs_regular_count = 0; ctx->fs_blockdev_count = 0; ctx->fs_chardev_count = 0; ctx->fs_links_count = 0; ctx->fs_symlinks_count = 0; ctx->fs_fast_symlinks_count = 0; ctx->fs_fifo_count = 0; ctx->fs_total_count = 0; ctx->fs_badblocks_count = 0; ctx->fs_sockets_count = 0; ctx->fs_ind_count = 0; ctx->fs_dind_count = 0; ctx->fs_tind_count = 0; ctx->fs_fragmented = 0; ctx->large_files = 0; /* Reset the superblock to the user's requested value */ ctx->superblock = ctx->use_superblock; return 0; }
static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block) { dgrp_t i; char *block_bitmap = 0, *inode_bitmap = 0; char *buf; errcode_t retval; int block_nbytes = EXT2_CLUSTERS_PER_GROUP(fs->super) / 8; int inode_nbytes = EXT2_INODES_PER_GROUP(fs->super) / 8; int csum_flag = 0; unsigned int cnt; blk64_t blk; blk64_t blk_itr = EXT2FS_B2C(fs, fs->super->s_first_data_block); blk64_t blk_cnt; ext2_ino_t ino_itr = 1; ext2_ino_t ino_cnt; EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); if ((block_nbytes > fs->blocksize) || (inode_nbytes > fs->blocksize)) return EXT2_ET_CORRUPT_SUPERBLOCK; fs->write_bitmaps = ext2fs_write_bitmaps; if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super, EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) csum_flag = 1; retval = ext2fs_get_mem(strlen(fs->device_name) + 80, &buf); if (retval) return retval; if (do_block) { if (fs->block_map) ext2fs_free_block_bitmap(fs->block_map); strcpy(buf, "block bitmap for "); strcat(buf, fs->device_name); retval = ext2fs_allocate_block_bitmap(fs, buf, &fs->block_map); if (retval) goto cleanup; retval = io_channel_alloc_buf(fs->io, 0, &block_bitmap); if (retval) goto cleanup; } else block_nbytes = 0; if (do_inode) { if (fs->inode_map) ext2fs_free_inode_bitmap(fs->inode_map); strcpy(buf, "inode bitmap for "); strcat(buf, fs->device_name); retval = ext2fs_allocate_inode_bitmap(fs, buf, &fs->inode_map); if (retval) goto cleanup; retval = io_channel_alloc_buf(fs->io, 0, &inode_bitmap); if (retval) goto cleanup; } else inode_nbytes = 0; ext2fs_free_mem(&buf); if (fs->flags & EXT2_FLAG_IMAGE_FILE) { blk = (fs->image_header->offset_inodemap / fs->blocksize); ino_cnt = fs->super->s_inodes_count; while (inode_nbytes > 0) { retval = io_channel_read_blk64(fs->image_io, blk++, 1, inode_bitmap); if (retval) goto cleanup; cnt = fs->blocksize << 3; if (cnt > ino_cnt) cnt = ino_cnt; retval = ext2fs_set_inode_bitmap_range2(fs->inode_map, ino_itr, cnt, inode_bitmap); if (retval) goto cleanup; ino_itr += fs->blocksize << 3; ino_cnt -= fs->blocksize << 3; inode_nbytes -= fs->blocksize; } blk = (fs->image_header->offset_blockmap / fs->blocksize); blk_cnt = (blk64_t)EXT2_CLUSTERS_PER_GROUP(fs->super) * fs->group_desc_count; while (block_nbytes > 0) { retval = io_channel_read_blk64(fs->image_io, blk++, 1, block_bitmap); if (retval) goto cleanup; cnt = fs->blocksize << 3; if (cnt > blk_cnt) cnt = blk_cnt; retval = ext2fs_set_block_bitmap_range2(fs->block_map, blk_itr, cnt, block_bitmap); if (retval) goto cleanup; blk_itr += fs->blocksize << 3; blk_cnt -= fs->blocksize << 3; block_nbytes -= fs->blocksize; } goto success_cleanup; } for (i = 0; i < fs->group_desc_count; i++) { if (block_bitmap) { blk = ext2fs_block_bitmap_loc(fs, i); if (csum_flag && ext2fs_bg_flags_test(fs, i, EXT2_BG_BLOCK_UNINIT) && ext2fs_group_desc_csum_verify(fs, i)) blk = 0; if (blk) { retval = io_channel_read_blk64(fs->io, blk, 1, block_bitmap); if (retval) { retval = EXT2_ET_BLOCK_BITMAP_READ; goto cleanup; } } else memset(block_bitmap, 0, block_nbytes); cnt = block_nbytes << 3; retval = ext2fs_set_block_bitmap_range2(fs->block_map, blk_itr, cnt, block_bitmap); if (retval) goto cleanup; blk_itr += block_nbytes << 3; } if (inode_bitmap) { blk = ext2fs_inode_bitmap_loc(fs, i); if (csum_flag && ext2fs_bg_flags_test(fs, i, EXT2_BG_INODE_UNINIT) && ext2fs_group_desc_csum_verify(fs, i)) blk = 0; if (blk) { retval = io_channel_read_blk64(fs->io, blk, 1, inode_bitmap); if (retval) { retval = EXT2_ET_INODE_BITMAP_READ; goto cleanup; } } else memset(inode_bitmap, 0, inode_nbytes); cnt = inode_nbytes << 3; retval = ext2fs_set_inode_bitmap_range2(fs->inode_map, ino_itr, cnt, inode_bitmap); if (retval) goto cleanup; ino_itr += inode_nbytes << 3; } } success_cleanup: if (inode_bitmap) ext2fs_free_mem(&inode_bitmap); if (block_bitmap) ext2fs_free_mem(&block_bitmap); return 0; cleanup: if (do_block) { ext2fs_free_mem(&fs->block_map); fs->block_map = 0; } if (do_inode) { ext2fs_free_mem(&fs->inode_map); fs->inode_map = 0; } if (inode_bitmap) ext2fs_free_mem(&inode_bitmap); if (block_bitmap) ext2fs_free_mem(&block_bitmap); if (buf) ext2fs_free_mem(&buf); return retval; }
void e2fsck_pass4(e2fsck_t ctx) { ext2_filsys fs = ctx->fs; ext2_ino_t i; struct ext2_inode *inode; #ifdef RESOURCE_TRACK struct resource_track rtrack; #endif struct problem_context pctx; __u16 link_count, link_counted; char *buf = 0; dgrp_t group, maxgroup; init_resource_track(&rtrack, ctx->fs->io); #ifdef MTRACE mtrace_print("Pass 4"); #endif clear_problem_context(&pctx); if (!(ctx->options & E2F_OPT_PREEN)) fix_problem(ctx, PR_4_PASS_HEADER, &pctx); group = 0; maxgroup = fs->group_desc_count; if (ctx->progress) if ((ctx->progress)(ctx, 4, 0, maxgroup)) return; inode = e2fsck_allocate_memory(ctx, EXT2_INODE_SIZE(fs->super), "scratch inode"); /* Protect loop from wrap-around if s_inodes_count maxed */ for (i=1; i <= fs->super->s_inodes_count && i > 0; i++) { int isdir; if (ctx->flags & E2F_FLAG_SIGNAL_MASK) goto errout; if ((i % fs->super->s_inodes_per_group) == 0) { group++; if (ctx->progress) if ((ctx->progress)(ctx, 4, group, maxgroup)) goto errout; } if (i == EXT2_BAD_INO || (i > EXT2_ROOT_INO && i < EXT2_FIRST_INODE(fs->super))) continue; if (!(ext2fs_test_inode_bitmap2(ctx->inode_used_map, i)) || (ctx->inode_imagic_map && ext2fs_test_inode_bitmap2(ctx->inode_imagic_map, i)) || (ctx->inode_bb_map && ext2fs_test_inode_bitmap2(ctx->inode_bb_map, i))) continue; ext2fs_icount_fetch(ctx->inode_link_info, i, &link_count); ext2fs_icount_fetch(ctx->inode_count, i, &link_counted); if (link_counted == 0) { if (!buf) buf = e2fsck_allocate_memory(ctx, fs->blocksize, "bad_inode buffer"); if (e2fsck_process_bad_inode(ctx, 0, i, buf)) continue; if (disconnect_inode(ctx, i, inode)) continue; ext2fs_icount_fetch(ctx->inode_link_info, i, &link_count); ext2fs_icount_fetch(ctx->inode_count, i, &link_counted); } isdir = ext2fs_test_inode_bitmap2(ctx->inode_dir_map, i); if (isdir && (link_counted > EXT2_LINK_MAX)) link_counted = 1; if (link_counted != link_count) { e2fsck_read_inode(ctx, i, inode, "pass4"); pctx.ino = i; pctx.inode = inode; if ((link_count != inode->i_links_count) && !isdir && (inode->i_links_count <= EXT2_LINK_MAX)) { pctx.num = link_count; fix_problem(ctx, PR_4_INCONSISTENT_COUNT, &pctx); } pctx.num = link_counted; /* i_link_count was previously exceeded, but no longer * is, fix this but don't consider it an error */ if ((isdir && link_counted > 1 && (inode->i_flags & EXT2_INDEX_FL) && link_count == 1 && !(ctx->options & E2F_OPT_NO)) || fix_problem(ctx, PR_4_BAD_REF_COUNT, &pctx)) { inode->i_links_count = link_counted; e2fsck_write_inode(ctx, i, inode, "pass4"); } } } ext2fs_free_icount(ctx->inode_link_info); ctx->inode_link_info = 0; ext2fs_free_icount(ctx->inode_count); ctx->inode_count = 0; ext2fs_free_inode_bitmap(ctx->inode_bb_map); ctx->inode_bb_map = 0; ext2fs_free_inode_bitmap(ctx->inode_imagic_map); ctx->inode_imagic_map = 0; errout: if (buf) ext2fs_free_mem(&buf); ext2fs_free_mem(&inode); print_resource_track(ctx, _("Pass 4"), &rtrack, ctx->fs->io); }