/* * Helper function which writes out a directory block. */ static int write_dir_block(ext2_filsys fs, blk_t *block_nr, e2_blkcnt_t blockcnt, blk_t ref_block EXT2FS_ATTR((unused)), int ref_offset EXT2FS_ATTR((unused)), void *priv_data) { struct write_dir_struct *wd = (struct write_dir_struct *) priv_data; blk_t blk; char *dir; if (*block_nr == 0) return 0; if (blockcnt >= wd->outdir->num) { e2fsck_read_bitmaps(wd->ctx); blk = *block_nr; ext2fs_unmark_block_bitmap2(wd->ctx->block_found_map, blk); ext2fs_block_alloc_stats(fs, blk, -1); *block_nr = 0; wd->cleared++; return BLOCK_CHANGED; } if (blockcnt < 0) return 0; dir = wd->outdir->buf + (blockcnt * fs->blocksize); wd->err = ext2fs_write_dir_block(fs, *block_nr, dir); if (wd->err) return BLOCK_ABORT; 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; __u32 count; struct del_block del_block; e2fsck_read_inode(ctx, ino, &inode, "deallocate_inode"); e2fsck_clear_inode(ctx, ino, &inode, 0, "deallocate_inode"); clear_problem_context(&pctx); pctx.ino = ino; /* * Fix up the bitmaps... */ e2fsck_read_bitmaps(ctx); ext2fs_inode_alloc_stats2(fs, ino, -1, LINUX_S_ISDIR(inode.i_mode)); if (ext2fs_file_acl_block(fs, &inode) && (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR)) { pctx.errcode = ext2fs_adjust_ea_refcount3(fs, ext2fs_file_acl_block(fs, &inode), block_buf, -1, &count, ino); if (pctx.errcode == EXT2_ET_BAD_EA_BLOCK_NUM) { pctx.errcode = 0; count = 1; } if (pctx.errcode) { pctx.blk = ext2fs_file_acl_block(fs, &inode); fix_problem(ctx, PR_2_ADJ_EA_REFCOUNT, &pctx); ctx->flags |= E2F_FLAG_ABORT; return; } if (count == 0) { ext2fs_unmark_block_bitmap2(ctx->block_found_map, ext2fs_file_acl_block(fs, &inode)); ext2fs_block_alloc_stats2(fs, ext2fs_file_acl_block(fs, &inode), -1); } ext2fs_file_acl_block_set(fs, &inode, 0); } if (!ext2fs_inode_has_valid_blocks2(fs, &inode)) return; if (LINUX_S_ISREG(inode.i_mode) && EXT2_I_SIZE(&inode) >= 0x80000000UL) ctx->large_files--; del_block.ctx = ctx; del_block.num = 0; pctx.errcode = ext2fs_block_iterate3(fs, ino, 0, block_buf, deallocate_inode_block, &del_block); if (pctx.errcode) { fix_problem(ctx, PR_2_DEALLOC_INODE, &pctx); ctx->flags |= E2F_FLAG_ABORT; return; } }
/* * 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, struct ext2_inode *inode) { ext2_filsys fs = ctx->fs; struct problem_context pctx; __u32 eamagic = 0; int extra_size = 0; if (EXT2_INODE_SIZE(fs->super) > EXT2_GOOD_OLD_INODE_SIZE) { e2fsck_read_inode_full(ctx, i, inode,EXT2_INODE_SIZE(fs->super), "pass4: disconnect_inode"); extra_size = ((struct ext2_inode_large *)inode)->i_extra_isize; } else { e2fsck_read_inode(ctx, i, inode, "pass4: disconnect_inode"); } clear_problem_context(&pctx); pctx.ino = i; pctx.inode = inode; if (EXT2_INODE_SIZE(fs->super) -EXT2_GOOD_OLD_INODE_SIZE -extra_size >0) eamagic = *(__u32 *)(((char *)inode) +EXT2_GOOD_OLD_INODE_SIZE + extra_size); /* * 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 && eamagic != EXT2_EXT_ATTR_MAGIC && (LINUX_S_ISREG(inode->i_mode) || LINUX_S_ISDIR(inode->i_mode))) { if (fix_problem(ctx, PR_4_ZERO_LEN_INODE, &pctx)) { e2fsck_clear_inode(ctx, i, inode, 0, "disconnect_inode"); /* * Fix up the bitmaps... */ e2fsck_read_bitmaps(ctx); 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; }
void swap_filesys(e2fsck_t ctx) { ext2_filsys fs = ctx->fs; #ifdef RESOURCE_TRACK struct resource_track rtrack; init_resource_track(&rtrack); #endif if (!(ctx->options & E2F_OPT_PREEN)) printf(_("Pass 0: Doing byte-swap of filesystem\n")); #ifdef MTRACE mtrace_print("Byte swap"); #endif if (fs->super->s_mnt_count) { fprintf(stderr, _("%s: the filesystem must be freshly " "checked using fsck\n" "and not mounted before trying to " "byte-swap it.\n"), ctx->device_name); ctx->flags |= E2F_FLAG_ABORT; return; } if (fs->flags & EXT2_FLAG_SWAP_BYTES) { fs->flags &= ~(EXT2_FLAG_SWAP_BYTES| EXT2_FLAG_SWAP_BYTES_WRITE); fs->flags |= EXT2_FLAG_SWAP_BYTES_READ; } else { fs->flags &= ~EXT2_FLAG_SWAP_BYTES_READ; fs->flags |= EXT2_FLAG_SWAP_BYTES_WRITE; } swap_inodes(ctx); if (ctx->flags & E2F_FLAG_SIGNAL_MASK) return; if (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE) fs->flags |= EXT2_FLAG_SWAP_BYTES; fs->flags &= ~(EXT2_FLAG_SWAP_BYTES_READ| EXT2_FLAG_SWAP_BYTES_WRITE); #ifdef EXT2_BIG_ENDIAN_BITMAPS e2fsck_read_bitmaps(ctx); ext2fs_swap_bitmap(fs->inode_map); ext2fs_swap_bitmap(fs->block_map); fs->flags |= EXT2_FLAG_BB_DIRTY | EXT2_FLAG_IB_DIRTY; #endif fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY; ext2fs_flush(fs); fs->flags |= EXT2_FLAG_MASTER_SB_ONLY; #ifdef RESOURCE_TRACK if (ctx->options & E2F_OPT_TIME2) print_resource_track(_("Byte swap"), &rtrack); #endif }
/* * 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; }
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 }
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; __u32 count; e2fsck_read_inode(ctx, ino, &inode, "deallocate_inode"); e2fsck_clear_inode(ctx, ino, &inode, 0, "deallocate_inode"); clear_problem_context(&pctx); pctx.ino = ino; e2fsck_read_bitmaps(ctx); ext2fs_inode_alloc_stats2(fs, ino, -1, LINUX_S_ISDIR(inode.i_mode)); if (inode.i_file_acl && (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR)) { pctx.errcode = ext2fs_adjust_ea_refcount(fs, inode.i_file_acl, block_buf, -1, &count); if (pctx.errcode == EXT2_ET_BAD_EA_BLOCK_NUM) { pctx.errcode = 0; count = 1; } if (pctx.errcode) { pctx.blk = inode.i_file_acl; fix_problem(ctx, PR_2_ADJ_EA_REFCOUNT, &pctx); ctx->flags |= E2F_FLAG_ABORT; return; } if (count == 0) { ext2fs_unmark_block_bitmap(ctx->block_found_map, inode.i_file_acl); ext2fs_block_alloc_stats(fs, inode.i_file_acl, -1); } inode.i_file_acl = 0; } if (!ext2fs_inode_has_valid_blocks(&inode)) return; if (LINUX_S_ISREG(inode.i_mode) && (inode.i_size_high || inode.i_size & 0x80000000UL)) ctx->large_files--; 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; } }
/* * Helper function which writes out a directory block. */ static int write_dir_block(ext2_filsys fs, blk64_t *block_nr, e2_blkcnt_t blockcnt, blk64_t ref_block EXT2FS_ATTR((unused)), int ref_offset EXT2FS_ATTR((unused)), void *priv_data) { struct write_dir_struct *wd = (struct write_dir_struct *) priv_data; blk64_t blk; char *dir, *buf = 0; if (*block_nr == 0) return 0; if (blockcnt < 0) return 0; if (blockcnt < wd->outdir->num) dir = wd->outdir->buf + (blockcnt * fs->blocksize); else if (wd->ctx->lost_and_found == wd->dir) { /* Don't release any extra directory blocks for lost+found */ wd->err = ext2fs_new_dir_block(fs, 0, 0, &buf); if (wd->err) return BLOCK_ABORT; dir = buf; wd->outdir->num++; } else { /* We don't need this block, so release it */ e2fsck_read_bitmaps(wd->ctx); blk = *block_nr; /* * In theory, we only release blocks from the end of the * directory file, so it's fine to clobber a whole cluster at * once. */ if (blk % EXT2FS_CLUSTER_RATIO(fs) == 0) { ext2fs_block_alloc_stats2(fs, blk, -1); wd->cleared++; } *block_nr = 0; return BLOCK_CHANGED; } wd->err = ext2fs_write_dir_block4(fs, *block_nr, dir, 0, wd->dir); if (buf) ext2fs_free_mem(&buf); if (wd->err) return BLOCK_ABORT; 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; } }
/* * Helper function which writes out a directory block. */ static int write_dir_block(ext2_filsys fs, blk64_t *block_nr, e2_blkcnt_t blockcnt, blk64_t ref_block EXT2FS_ATTR((unused)), int ref_offset EXT2FS_ATTR((unused)), void *priv_data) { struct write_dir_struct *wd = (struct write_dir_struct *) priv_data; blk64_t blk; char *dir; if (*block_nr == 0) return 0; if (blockcnt >= wd->outdir->num) { e2fsck_read_bitmaps(wd->ctx); blk = *block_nr; /* * In theory, we only release blocks from the end of the * directory file, so it's fine to clobber a whole cluster at * once. */ if (blk % EXT2FS_CLUSTER_RATIO(fs) == 0) { ext2fs_unmark_block_bitmap2(wd->ctx->block_found_map, blk); ext2fs_block_alloc_stats2(fs, blk, -1); wd->cleared++; } *block_nr = 0; return BLOCK_CHANGED; } if (blockcnt < 0) return 0; dir = wd->outdir->buf + (blockcnt * fs->blocksize); wd->err = ext2fs_write_dir_block3(fs, *block_nr, dir, 0); if (wd->err) return BLOCK_ABORT; return 0; }
/* * This routine gets the lost_and_found inode, making it a directory * if necessary */ ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix) { ext2_filsys fs = ctx->fs; ext2_ino_t ino; blk64_t blk; errcode_t retval; struct ext2_inode inode; char * block; static const char name[] = "lost+found"; struct problem_context pctx; if (ctx->lost_and_found) return ctx->lost_and_found; clear_problem_context(&pctx); retval = ext2fs_lookup(fs, EXT2_ROOT_INO, name, sizeof(name)-1, 0, &ino); if (retval && !fix) return 0; if (!retval) { if (ext2fs_check_directory(fs, ino) == 0) { ctx->lost_and_found = ino; return ino; } /* Lost+found isn't a directory! */ if (!fix) return 0; pctx.ino = ino; if (!fix_problem(ctx, PR_3_LPF_NOTDIR, &pctx)) return 0; /* OK, unlink the old /lost+found file. */ pctx.errcode = ext2fs_unlink(fs, EXT2_ROOT_INO, name, ino, 0); if (pctx.errcode) { pctx.str = "ext2fs_unlink"; fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx); return 0; } (void) e2fsck_dir_info_set_parent(ctx, ino, 0); e2fsck_adjust_inode_count(ctx, ino, -1); } else if (retval != EXT2_ET_FILE_NOT_FOUND) { pctx.errcode = retval; fix_problem(ctx, PR_3_ERR_FIND_LPF, &pctx); } if (!fix_problem(ctx, PR_3_NO_LF_DIR, 0)) return 0; /* * Read the inode and block bitmaps in; we'll be messing with * them. */ e2fsck_read_bitmaps(ctx); /* * First, find a free block */ retval = ext2fs_new_block2(fs, 0, ctx->block_found_map, &blk); if (retval) { pctx.errcode = retval; fix_problem(ctx, PR_3_ERR_LPF_NEW_BLOCK, &pctx); return 0; } ext2fs_mark_block_bitmap2(ctx->block_found_map, blk); ext2fs_block_alloc_stats2(fs, blk, +1); /* * Next find a free inode. */ retval = ext2fs_new_inode(fs, EXT2_ROOT_INO, 040700, ctx->inode_used_map, &ino); if (retval) { pctx.errcode = retval; fix_problem(ctx, PR_3_ERR_LPF_NEW_INODE, &pctx); return 0; } ext2fs_mark_inode_bitmap2(ctx->inode_used_map, ino); ext2fs_mark_inode_bitmap2(ctx->inode_dir_map, ino); ext2fs_inode_alloc_stats2(fs, ino, +1, 1); /* * Now let's create the actual data block for the inode */ retval = ext2fs_new_dir_block(fs, ino, EXT2_ROOT_INO, &block); if (retval) { pctx.errcode = retval; fix_problem(ctx, PR_3_ERR_LPF_NEW_DIR_BLOCK, &pctx); return 0; } retval = ext2fs_write_dir_block4(fs, blk, block, 0, ino); ext2fs_free_mem(&block); if (retval) { pctx.errcode = retval; fix_problem(ctx, PR_3_ERR_LPF_WRITE_BLOCK, &pctx); return 0; } /* * Set up the inode structure */ memset(&inode, 0, sizeof(inode)); inode.i_mode = 040700; inode.i_size = fs->blocksize; inode.i_atime = inode.i_ctime = inode.i_mtime = ctx->now; inode.i_links_count = 2; ext2fs_iblk_set(fs, &inode, 1); inode.i_block[0] = blk; /* * Next, write out the inode. */ pctx.errcode = ext2fs_write_new_inode(fs, ino, &inode); if (pctx.errcode) { pctx.str = "ext2fs_write_inode"; fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx); return 0; } /* * Finally, create the directory link */ pctx.errcode = ext2fs_link(fs, EXT2_ROOT_INO, name, ino, EXT2_FT_DIR); if (pctx.errcode) { pctx.str = "ext2fs_link"; fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx); return 0; } /* * Miscellaneous bookkeeping that needs to be kept straight. */ e2fsck_add_dir_info(ctx, ino, EXT2_ROOT_INO); e2fsck_adjust_inode_count(ctx, EXT2_ROOT_INO, 1); ext2fs_icount_store(ctx->inode_count, ino, 2); ext2fs_icount_store(ctx->inode_link_info, ino, 2); ctx->lost_and_found = ino; quota_data_add(ctx->qctx, &inode, ino, fs->blocksize); quota_data_inodes(ctx->qctx, &inode, ino, +1); #if 0 printf("/lost+found created; inode #%lu\n", ino); #endif return ino; }
/* * This makes sure the root inode is present; if not, we ask if the * user wants us to create it. Not creating it is a fatal error. */ static void check_root(e2fsck_t ctx) { ext2_filsys fs = ctx->fs; blk64_t blk; struct ext2_inode inode; char * block; struct problem_context pctx; clear_problem_context(&pctx); if (ext2fs_test_inode_bitmap2(ctx->inode_used_map, EXT2_ROOT_INO)) { /* * If the root inode is not a directory, die here. The * user must have answered 'no' in pass1 when we * offered to clear it. */ if (!(ext2fs_test_inode_bitmap2(ctx->inode_dir_map, EXT2_ROOT_INO))) { fix_problem(ctx, PR_3_ROOT_NOT_DIR_ABORT, &pctx); ctx->flags |= E2F_FLAG_ABORT; } return; } if (!fix_problem(ctx, PR_3_NO_ROOT_INODE, &pctx)) { fix_problem(ctx, PR_3_NO_ROOT_INODE_ABORT, &pctx); ctx->flags |= E2F_FLAG_ABORT; return; } e2fsck_read_bitmaps(ctx); /* * First, find a free block */ pctx.errcode = ext2fs_new_block2(fs, 0, ctx->block_found_map, &blk); if (pctx.errcode) { pctx.str = "ext2fs_new_block"; fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx); ctx->flags |= E2F_FLAG_ABORT; return; } ext2fs_mark_block_bitmap2(ctx->block_found_map, blk); ext2fs_mark_block_bitmap2(fs->block_map, blk); ext2fs_mark_bb_dirty(fs); /* * Now let's create the actual data block for the inode */ pctx.errcode = ext2fs_new_dir_block(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, &block); if (pctx.errcode) { pctx.str = "ext2fs_new_dir_block"; fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx); ctx->flags |= E2F_FLAG_ABORT; return; } pctx.errcode = ext2fs_write_dir_block4(fs, blk, block, 0, EXT2_ROOT_INO); if (pctx.errcode) { pctx.str = "ext2fs_write_dir_block"; fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx); ctx->flags |= E2F_FLAG_ABORT; return; } ext2fs_free_mem(&block); /* * Set up the inode structure */ memset(&inode, 0, sizeof(inode)); inode.i_mode = 040755; inode.i_size = fs->blocksize; inode.i_atime = inode.i_ctime = inode.i_mtime = ctx->now; inode.i_links_count = 2; ext2fs_iblk_set(fs, &inode, 1); inode.i_block[0] = blk; /* * Write out the inode. */ pctx.errcode = ext2fs_write_new_inode(fs, EXT2_ROOT_INO, &inode); if (pctx.errcode) { pctx.str = "ext2fs_write_inode"; fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx); ctx->flags |= E2F_FLAG_ABORT; return; } /* * Miscellaneous bookkeeping... */ e2fsck_add_dir_info(ctx, EXT2_ROOT_INO, EXT2_ROOT_INO); ext2fs_icount_store(ctx->inode_count, EXT2_ROOT_INO, 2); ext2fs_icount_store(ctx->inode_link_info, EXT2_ROOT_INO, 2); ext2fs_mark_inode_bitmap2(ctx->inode_used_map, EXT2_ROOT_INO); ext2fs_mark_inode_bitmap2(ctx->inode_dir_map, EXT2_ROOT_INO); ext2fs_mark_inode_bitmap2(fs->inode_map, EXT2_ROOT_INO); ext2fs_mark_ib_dirty(fs); }
void read_bad_blocks_file(e2fsck_t ctx, const char *bad_blocks_file, int replace_bad_blocks) { ext2_filsys fs = ctx->fs; errcode_t retval; badblocks_list bb_list = 0; FILE *f; char buf[1024]; e2fsck_read_bitmaps(ctx); /* * Make sure the bad block inode is sane. If there are any * illegal blocks, clear them. */ retval = ext2fs_block_iterate(fs, EXT2_BAD_INO, 0, 0, check_bb_inode_blocks, 0); if (retval) { com_err("ext2fs_block_iterate", retval, "%s", _("while sanity checking the bad blocks inode")); goto fatal; } /* * If we're appending to the bad blocks inode, read in the * current bad blocks. */ if (!replace_bad_blocks) { retval = ext2fs_read_bb_inode(fs, &bb_list); if (retval) { com_err("ext2fs_read_bb_inode", retval, "%s", _("while reading the bad blocks inode")); goto fatal; } } /* * Now read in the bad blocks from the file; if * bad_blocks_file is null, then try to run the badblocks * command. */ if (bad_blocks_file) { f = fopen(bad_blocks_file, "r"); if (!f) { com_err("read_bad_blocks_file", errno, _("while trying to open %s"), bad_blocks_file); goto fatal; } } else { sprintf(buf, "badblocks -b %d -X %s%s%s %llu", fs->blocksize, (ctx->options & E2F_OPT_PREEN) ? "" : "-s ", (ctx->options & E2F_OPT_WRITECHECK) ? "-n " : "", fs->device_name, ext2fs_blocks_count(fs->super)-1); f = popen(buf, "r"); if (!f) { com_err("read_bad_blocks_file", errno, _("while trying popen '%s'"), buf); goto fatal; } } retval = ext2fs_read_bb_FILE(fs, f, &bb_list, invalid_block); if (bad_blocks_file) fclose(f); else pclose(f); if (retval) { com_err("ext2fs_read_bb_FILE", retval, "%s", _("while reading in list of bad blocks from file")); goto fatal; } /* * Finally, update the bad blocks from the bad_block_map */ printf("%s: Updating bad block inode.\n", ctx->device_name); retval = ext2fs_update_bb_inode(fs, bb_list); if (retval) { com_err("ext2fs_update_bb_inode", retval, "%s", _("while updating bad block inode")); goto fatal; } ext2fs_badblocks_list_free(bb_list); return; fatal: ctx->flags |= E2F_FLAG_ABORT; return; }
/* * allocate_dir_block --- this function allocates a new directory * block for a particular inode; this is done if a directory has * a "hole" in it, or if a directory has a illegal block number * that was zeroed out and now needs to be replaced. */ static int allocate_dir_block(e2fsck_t ctx, struct ext2_db_entry *db, char *buf, struct problem_context *pctx) { ext2_filsys fs = ctx->fs; blk_t blk; char *block; struct ext2_inode inode; if (fix_problem(ctx, PR_2_DIRECTORY_HOLE, pctx) == 0) return 1; /* * Read the inode and block bitmaps in; we'll be messing with * them. */ e2fsck_read_bitmaps(ctx); /* * First, find a free block */ pctx->errcode = ext2fs_new_block(fs, 0, ctx->block_found_map, &blk); if (pctx->errcode) { pctx->str = "ext2fs_new_block"; fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx); return 1; } ext2fs_mark_block_bitmap(ctx->block_found_map, blk); ext2fs_mark_block_bitmap(fs->block_map, blk); ext2fs_mark_bb_dirty(fs); /* * Now let's create the actual data block for the inode */ if (db->blockcnt) pctx->errcode = ext2fs_new_dir_block(fs, 0, 0, &block); else pctx->errcode = ext2fs_new_dir_block(fs, db->ino, EXT2_ROOT_INO, &block); if (pctx->errcode) { pctx->str = "ext2fs_new_dir_block"; fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx); return 1; } pctx->errcode = ext2fs_write_dir_block(fs, blk, block); ext2fs_free_mem((void **) &block); if (pctx->errcode) { pctx->str = "ext2fs_write_dir_block"; fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx); return 1; } /* * Update the inode block count */ e2fsck_read_inode(ctx, db->ino, &inode, "allocate_dir_block"); inode.i_blocks += fs->blocksize / 512; if (inode.i_size < (db->blockcnt+1) * fs->blocksize) inode.i_size = (db->blockcnt+1) * fs->blocksize; e2fsck_write_inode(ctx, db->ino, &inode, "allocate_dir_block"); /* * Finally, update the block pointers for the inode */ db->blk = blk; pctx->errcode = ext2fs_block_iterate2(fs, db->ino, BLOCK_FLAG_HOLE, 0, update_dir_block, db); if (pctx->errcode) { pctx->str = "ext2fs_block_iterate"; fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx); return 1; } return 0; }
void read_bad_blocks_file(e2fsck_t ctx, const char *bad_blocks_file, int replace_bad_blocks) { ext2_filsys fs = ctx->fs; errcode_t retval; badblocks_list bb_list = 0; FILE *f; char buf[1024]; e2fsck_read_bitmaps(ctx); retval = ext2fs_block_iterate(fs, EXT2_BAD_INO, 0, 0, check_bb_inode_blocks, 0); if (retval) { com_err("ext2fs_block_iterate", retval, _("while sanity checking the bad blocks inode")); goto fatal; } if (!replace_bad_blocks) { retval = ext2fs_read_bb_inode(fs, &bb_list); if (retval) { com_err("ext2fs_read_bb_inode", retval, _("while reading the bad blocks inode")); goto fatal; } } if (bad_blocks_file) { f = fopen(bad_blocks_file, "r"); if (!f) { com_err("read_bad_blocks_file", errno, _("while trying to open %s"), bad_blocks_file); goto fatal; } } else { sprintf(buf, "badblocks -b %d -X %s%s%s %d", fs->blocksize, (ctx->options & E2F_OPT_PREEN) ? "" : "-s ", (ctx->options & E2F_OPT_WRITECHECK) ? "-n " : "", fs->device_name, fs->super->s_blocks_count-1); f = popen(buf, "r"); if (!f) { com_err("read_bad_blocks_file", errno, _("while trying popen '%s'"), buf); goto fatal; } } retval = ext2fs_read_bb_FILE(fs, f, &bb_list, invalid_block); if (bad_blocks_file) fclose(f); else pclose(f); if (retval) { com_err("ext2fs_read_bb_FILE", retval, _("while reading in list of bad blocks from file")); goto fatal; } printf("%s: Updating bad block inode.\n", ctx->device_name); retval = ext2fs_update_bb_inode(fs, bb_list); if (retval) { com_err("ext2fs_update_bb_inode", retval, _("while updating bad block inode")); goto fatal; } ext2fs_badblocks_list_free(bb_list); return; fatal: ctx->flags |= E2F_FLAG_ABORT; return; }
/* * This routine gets the lost_and_found inode, making it a directory * if necessary */ ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix) { ext2_filsys fs = ctx->fs; ext2_ino_t ino; blk64_t blk; errcode_t retval; struct ext2_inode inode; char * block; static const char name[] = "lost+found"; struct problem_context pctx; int will_rehash, flags; if (ctx->lost_and_found) return ctx->lost_and_found; clear_problem_context(&pctx); will_rehash = e2fsck_dir_will_be_rehashed(ctx, EXT2_ROOT_INO); if (will_rehash) { flags = ctx->fs->flags; ctx->fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS; } retval = ext2fs_lookup(fs, EXT2_ROOT_INO, name, sizeof(name)-1, 0, &ino); if (will_rehash) ctx->fs->flags = (flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) | (ctx->fs->flags & ~EXT2_FLAG_IGNORE_CSUM_ERRORS); if (retval && !fix) return 0; if (!retval) { /* Lost+found shouldn't have inline data */ retval = ext2fs_read_inode(fs, ino, &inode); if (fix && retval) return 0; if (fix && (inode.i_flags & EXT4_INLINE_DATA_FL)) { if (!fix_problem(ctx, PR_3_LPF_INLINE_DATA, &pctx)) return 0; goto unlink; } if (fix && (inode.i_flags & EXT4_ENCRYPT_FL)) { if (!fix_problem(ctx, PR_3_LPF_ENCRYPTED, &pctx)) return 0; goto unlink; } if (ext2fs_check_directory(fs, ino) == 0) { ctx->lost_and_found = ino; return ino; } /* Lost+found isn't a directory! */ if (!fix) return 0; pctx.ino = ino; if (!fix_problem(ctx, PR_3_LPF_NOTDIR, &pctx)) return 0; unlink: /* OK, unlink the old /lost+found file. */ pctx.errcode = ext2fs_unlink(fs, EXT2_ROOT_INO, name, ino, 0); if (pctx.errcode) { pctx.str = "ext2fs_unlink"; fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx); return 0; } (void) e2fsck_dir_info_set_parent(ctx, ino, 0); e2fsck_adjust_inode_count(ctx, ino, -1); /* * If the old lost+found was a directory, we've just * disconnected it from the directory tree, which * means we need to restart the directory tree scan. * The simplest way to do this is restart the whole * e2fsck operation. */ if (LINUX_S_ISDIR(inode.i_mode)) ctx->flags |= E2F_FLAG_RESTART; } else if (retval != EXT2_ET_FILE_NOT_FOUND) { pctx.errcode = retval; fix_problem(ctx, PR_3_ERR_FIND_LPF, &pctx); } if (!fix_problem(ctx, PR_3_NO_LF_DIR, 0)) return 0; /* * Read the inode and block bitmaps in; we'll be messing with * them. */ e2fsck_read_bitmaps(ctx); /* * First, find a free block */ if (ctx->lnf_repair_block) { blk = ctx->lnf_repair_block; ctx->lnf_repair_block = 0; goto skip_new_block; } retval = ext2fs_new_block2(fs, 0, ctx->block_found_map, &blk); if (retval == EXT2_ET_BLOCK_ALLOC_FAIL && fix_problem(ctx, PR_3_LPF_NO_SPACE, &pctx)) { fix_problem(ctx, PR_3_NO_SPACE_TO_RECOVER, &pctx); ctx->lost_and_found = EXT2_ROOT_INO; return 0; } if (retval) { pctx.errcode = retval; fix_problem(ctx, PR_3_ERR_LPF_NEW_BLOCK, &pctx); return 0; } ext2fs_mark_block_bitmap2(ctx->block_found_map, blk); skip_new_block: ext2fs_block_alloc_stats2(fs, blk, +1); /* * Next find a free inode. */ retval = ext2fs_new_inode(fs, EXT2_ROOT_INO, 040700, ctx->inode_used_map, &ino); if (retval == EXT2_ET_INODE_ALLOC_FAIL && fix_problem(ctx, PR_3_LPF_NO_SPACE, &pctx)) { fix_problem(ctx, PR_3_NO_SPACE_TO_RECOVER, &pctx); ctx->lost_and_found = EXT2_ROOT_INO; return 0; } if (retval) { pctx.errcode = retval; fix_problem(ctx, PR_3_ERR_LPF_NEW_INODE, &pctx); return 0; } ext2fs_mark_inode_bitmap2(ctx->inode_used_map, ino); ext2fs_mark_inode_bitmap2(ctx->inode_dir_map, ino); ext2fs_inode_alloc_stats2(fs, ino, +1, 1); /* * Set up the inode structure */ memset(&inode, 0, sizeof(inode)); inode.i_mode = 040700; inode.i_size = fs->blocksize; inode.i_atime = inode.i_ctime = inode.i_mtime = ctx->now; inode.i_links_count = 2; ext2fs_iblk_set(fs, &inode, 1); inode.i_block[0] = blk; /* * Next, write out the inode. */ pctx.errcode = ext2fs_write_new_inode(fs, ino, &inode); if (pctx.errcode) { pctx.str = "ext2fs_write_inode"; fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx); return 0; } /* * Now let's create the actual data block for the inode. * Due to metadata_csum, the directory block MUST be written * after the inode is written to disk! */ retval = ext2fs_new_dir_block(fs, ino, EXT2_ROOT_INO, &block); if (retval) { pctx.errcode = retval; fix_problem(ctx, PR_3_ERR_LPF_NEW_DIR_BLOCK, &pctx); return 0; } retval = ext2fs_write_dir_block4(fs, blk, block, 0, ino); ext2fs_free_mem(&block); if (retval) { pctx.errcode = retval; fix_problem(ctx, PR_3_ERR_LPF_WRITE_BLOCK, &pctx); return 0; } /* * Finally, create the directory link */ pctx.errcode = ext2fs_link(fs, EXT2_ROOT_INO, name, ino, EXT2_FT_DIR); if (pctx.errcode == EXT2_ET_DIR_NO_SPACE) { pctx.errcode = ext2fs_expand_dir(fs, EXT2_ROOT_INO); if (pctx.errcode) goto link_error; pctx.errcode = ext2fs_link(fs, EXT2_ROOT_INO, name, ino, EXT2_FT_DIR); } if (pctx.errcode) { link_error: pctx.str = "ext2fs_link"; fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx); return 0; } /* * Miscellaneous bookkeeping that needs to be kept straight. */ e2fsck_add_dir_info(ctx, ino, EXT2_ROOT_INO); e2fsck_adjust_inode_count(ctx, EXT2_ROOT_INO, 1); ext2fs_icount_store(ctx->inode_count, ino, 2); ext2fs_icount_store(ctx->inode_link_info, ino, 2); ctx->lost_and_found = ino; quota_data_add(ctx->qctx, &inode, ino, fs->blocksize); quota_data_inodes(ctx->qctx, &inode, ino, +1); #if 0 printf("/lost+found created; inode #%lu\n", ino); #endif return ino; }