/* * 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 function returns 1 if the inode's block entries actually * contain block entries. */ int ext2fs_inode_has_valid_blocks2(ext2_filsys fs, struct ext2_inode *inode) { /* * Only directories, regular files, and some symbolic links * have valid block entries. */ if (!LINUX_S_ISDIR(inode->i_mode) && !LINUX_S_ISREG(inode->i_mode) && !LINUX_S_ISLNK(inode->i_mode)) return 0; /* * If the symbolic link is a "fast symlink", then the symlink * target is stored in the block entries. */ if (LINUX_S_ISLNK (inode->i_mode)) { if (ext2fs_file_acl_block(fs, inode) == 0) { /* With no EA block, we can rely on i_blocks */ if (inode->i_blocks == 0) return 0; } else { /* With an EA block, life gets more tricky */ if (inode->i_size >= EXT2_N_BLOCKS*4) return 1; /* definitely using i_block[] */ if (inode->i_size > 4 && inode->i_block[1] == 0) return 1; /* definitely using i_block[] */ return 0; /* Probably a fast symlink */ } } return 1; }
/* * This function expands '%IX' expressions */ static _INLINE_ void expand_inode_expression(FILE *f, ext2_filsys fs, char ch, struct problem_context *ctx) { struct ext2_inode *inode; struct ext2_inode_large *large_inode; if (!ctx || !ctx->inode) goto no_inode; inode = ctx->inode; large_inode = (struct ext2_inode_large *) inode; switch (ch) { case 's': if (LINUX_S_ISDIR(inode->i_mode)) fprintf(f, "%u", inode->i_size); else { #ifdef EXT2_NO_64_TYPE if (inode->i_size_high) fprintf(f, "0x%x%08x", inode->i_size_high, inode->i_size); else fprintf(f, "%u", inode->i_size); #else fprintf(f, "%llu", EXT2_I_SIZE(inode)); #endif } break; case 'S': fprintf(f, "%u", large_inode->i_extra_isize); break; case 'b': if (ext2fs_has_feature_huge_file(fs->super)) fprintf(f, "%llu", inode->i_blocks + (((long long) inode->osd2.linux2.l_i_blocks_hi) << 32)); else fprintf(f, "%u", inode->i_blocks); break; case 'l': fprintf(f, "%d", inode->i_links_count); break; case 'm': fprintf(f, "0%o", inode->i_mode); break; case 'M': print_time(f, inode->i_mtime); break; case 'F': fprintf(f, "%u", inode->i_faddr); break; case 'f': fprintf(f, "%llu", ext2fs_file_acl_block(fs, inode)); break; case 'd': fprintf(f, "%u", (LINUX_S_ISDIR(inode->i_mode) ? inode->i_dir_acl : 0)); break; case 'u': fprintf(f, "%d", inode_uid(*inode)); break; case 'g': fprintf(f, "%d", inode_gid(*inode)); break; case 't': if (LINUX_S_ISREG(inode->i_mode)) fputs(_("regular file"), f); else if (LINUX_S_ISDIR(inode->i_mode)) fputs(_("directory"), f); else if (LINUX_S_ISCHR(inode->i_mode)) fputs(_("character device"), f); else if (LINUX_S_ISBLK(inode->i_mode)) fputs(_("block device"), f); else if (LINUX_S_ISFIFO(inode->i_mode)) fputs(_("named pipe"), f); else if (LINUX_S_ISLNK(inode->i_mode)) fputs(_("symbolic link"), f); else if (LINUX_S_ISSOCK(inode->i_mode)) fputs(_("socket"), f); else fprintf(f, _("unknown file type with mode 0%o"), inode->i_mode); break; default: no_inode: fprintf(f, "%%I%c", ch); break; } }
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 (ext2fs_file_acl_block(fs, &inode) && !(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR)) { if (fix_problem(ctx, PR_2_FILE_ACL_ZERO, &pctx)) { ext2fs_file_acl_block_set(fs, &inode, 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 (ext2fs_file_acl_block(fs, &inode) && ((ext2fs_file_acl_block(fs, &inode) < fs->super->s_first_data_block) || (ext2fs_file_acl_block(fs, &inode) >= ext2fs_blocks_count(fs->super)))) { if (fix_problem(ctx, PR_2_FILE_ACL_BAD, &pctx)) { ext2fs_file_acl_block_set(fs, &inode, 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_bitmap2(ctx->inode_bad_map, ino); return 0; }