mirror of
https://git.kernel.org/pub/scm/fs/ext2/e2fsprogs.git
synced 2025-01-01 14:13:26 +08:00
1b6bf1759a
pass*.c, super.c: Massive changes to avoid using printf and com_err routines. All diagnostic messages are now routed through the fix_problem interface. pass2.c (check_dir_block): Check for duplicate '.' and '..' entries. problem.c, problem.h: Add new problem codes PR_2_DUP_DOT and PR_2_DUP_DOT_DOT. problem.c: Added new problem codes for some of the superblock corruption checks, and for the pass header messages. ("Pass 1: xxxxx") util.c (print_resource_track): Now takes a description argument. super.c, unix.c, e2fsck.c: New files to separate out the operating-specific operations out from e2fsck.c. e2fsck.c now contains the global e2fsck context management routines, and super.c contains the "pass 0" initial validation of the superblock and global block group descriptors. pass1.c, pass2.c, pass3.c, pass4.c, pass5.c, util.c: Eliminate (nearly) all global variables and moved them to the e2fsck context structure. problem.c, problem.h: Added new problem codes PR_0_SB_CORRUPT, PR_0_FS_SIZE_WRONG, PR_0_NO_FRAGMENTS, PR_0_BLOCKS_PER_GROUP, PR_0_FIRST_DATA_BLOCK expect.1, expect.2: Updated tests to align with e2fsck problem.c changes.
418 lines
11 KiB
C
418 lines
11 KiB
C
/*
|
|
* pass5.c --- check block and inode bitmaps against on-disk bitmaps
|
|
*
|
|
* Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o.
|
|
*
|
|
* %Begin-Header%
|
|
* This file may be redistributed under the terms of the GNU Public
|
|
* License.
|
|
* %End-Header%
|
|
*
|
|
*/
|
|
|
|
#include "e2fsck.h"
|
|
#include "problem.h"
|
|
|
|
static void check_block_bitmaps(e2fsck_t ctx);
|
|
static void check_inode_bitmaps(e2fsck_t ctx);
|
|
static void check_inode_end(e2fsck_t ctx);
|
|
static void check_block_end(e2fsck_t ctx);
|
|
|
|
void pass5(e2fsck_t ctx)
|
|
{
|
|
struct resource_track rtrack;
|
|
struct problem_context pctx;
|
|
|
|
#ifdef MTRACE
|
|
mtrace_print("Pass 5");
|
|
#endif
|
|
|
|
init_resource_track(&rtrack);
|
|
|
|
clear_problem_context(&pctx);
|
|
|
|
if (!(ctx->options & E2F_OPT_PREEN))
|
|
fix_problem(ctx, PR_5_PASS_HEADER, &pctx);
|
|
|
|
read_bitmaps(ctx);
|
|
|
|
check_block_bitmaps(ctx);
|
|
check_inode_bitmaps(ctx);
|
|
check_inode_end(ctx);
|
|
check_block_end(ctx);
|
|
|
|
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;
|
|
|
|
if (ctx->options & E2F_OPT_TIME2)
|
|
print_resource_track("Pass 5", &rtrack);
|
|
}
|
|
|
|
static void check_block_bitmaps(e2fsck_t ctx)
|
|
{
|
|
ext2_filsys fs = ctx->fs;
|
|
blk_t i;
|
|
int *free_array;
|
|
int group = 0;
|
|
int blocks = 0;
|
|
int free_blocks = 0;
|
|
int group_free = 0;
|
|
int actual, bitmap;
|
|
struct problem_context pctx;
|
|
int problem, fixit;
|
|
errcode_t retval;
|
|
|
|
clear_problem_context(&pctx);
|
|
free_array = allocate_memory(fs->group_desc_count * sizeof(int),
|
|
"free block count array");
|
|
|
|
if ((fs->super->s_first_data_block <
|
|
ext2fs_get_block_bitmap_start(ctx->block_found_map)) ||
|
|
(fs->super->s_blocks_count-1 >
|
|
ext2fs_get_block_bitmap_end(ctx->block_found_map))) {
|
|
pctx.num = 1;
|
|
pctx.blk = fs->super->s_first_data_block;
|
|
pctx.blk2 = fs->super->s_blocks_count -1;
|
|
pctx.ino = ext2fs_get_block_bitmap_start(ctx->block_found_map);
|
|
pctx.ino2 = ext2fs_get_block_bitmap_end(ctx->block_found_map);
|
|
fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
|
|
/* fatal */
|
|
fatal_error(0);
|
|
}
|
|
|
|
if ((fs->super->s_first_data_block <
|
|
ext2fs_get_block_bitmap_start(fs->block_map)) ||
|
|
(fs->super->s_blocks_count-1 >
|
|
ext2fs_get_block_bitmap_end(fs->block_map))) {
|
|
pctx.num = 2;
|
|
pctx.blk = fs->super->s_first_data_block;
|
|
pctx.blk2 = fs->super->s_blocks_count -1;
|
|
pctx.ino = ext2fs_get_block_bitmap_start(fs->block_map);
|
|
pctx.ino2 = ext2fs_get_block_bitmap_end(fs->block_map);
|
|
fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
|
|
/* fatal */
|
|
fatal_error(0);
|
|
}
|
|
|
|
redo_counts:
|
|
for (i = fs->super->s_first_data_block;
|
|
i < fs->super->s_blocks_count;
|
|
i++) {
|
|
actual = ext2fs_fast_test_block_bitmap(ctx->block_found_map, i);
|
|
bitmap = ext2fs_fast_test_block_bitmap(fs->block_map, i);
|
|
|
|
if (actual == bitmap)
|
|
goto do_counts;
|
|
|
|
if (!actual && bitmap) {
|
|
/*
|
|
* Block not used, but marked in use in the bitmap.
|
|
*/
|
|
problem = PR_5_UNUSED_BLOCK;
|
|
} else {
|
|
/*
|
|
* Block used, but not marked in use in the bitmap.
|
|
*/
|
|
problem = PR_5_BLOCK_USED;
|
|
}
|
|
pctx.blk = i;
|
|
fix_problem(ctx, problem, &pctx);
|
|
|
|
do_counts:
|
|
if (!bitmap) {
|
|
group_free++;
|
|
free_blocks++;
|
|
}
|
|
blocks ++;
|
|
if ((blocks == fs->super->s_blocks_per_group) ||
|
|
(i == fs->super->s_blocks_count-1)) {
|
|
free_array[group] = group_free;
|
|
group ++;
|
|
blocks = 0;
|
|
group_free = 0;
|
|
}
|
|
}
|
|
fixit = end_problem_latch(ctx, PR_LATCH_BBITMAP);
|
|
if (fixit == 1) {
|
|
ext2fs_free_block_bitmap(fs->block_map);
|
|
retval = ext2fs_copy_bitmap(ctx->block_found_map,
|
|
&fs->block_map);
|
|
/* XXX check retval --- should never fail! */
|
|
ext2fs_set_bitmap_padding(fs->block_map);
|
|
ext2fs_mark_bb_dirty(fs);
|
|
|
|
/* Redo the counts */
|
|
blocks = 0; free_blocks = 0; group_free = 0; group = 0;
|
|
memset(free_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_blocks_count) {
|
|
pctx.group = i;
|
|
pctx.blk = fs->group_desc[i].bg_free_blocks_count;
|
|
pctx.blk2 = free_array[i];
|
|
|
|
if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT_GROUP,
|
|
&pctx)) {
|
|
fs->group_desc[i].bg_free_blocks_count =
|
|
free_array[i];
|
|
ext2fs_mark_super_dirty(fs);
|
|
} else
|
|
ext2fs_unmark_valid(fs);
|
|
}
|
|
}
|
|
if (free_blocks != fs->super->s_free_blocks_count) {
|
|
pctx.group = 0;
|
|
pctx.blk = fs->super->s_free_blocks_count;
|
|
pctx.blk2 = free_blocks;
|
|
|
|
if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT, &pctx)) {
|
|
fs->super->s_free_blocks_count = free_blocks;
|
|
ext2fs_mark_super_dirty(fs);
|
|
} else
|
|
ext2fs_unmark_valid(fs);
|
|
}
|
|
free(free_array);
|
|
}
|
|
|
|
static void check_inode_bitmaps(e2fsck_t ctx)
|
|
{
|
|
ext2_filsys fs = ctx->fs;
|
|
ino_t i;
|
|
int free_inodes = 0;
|
|
int group_free = 0;
|
|
int dirs_count = 0;
|
|
int group = 0;
|
|
int inodes = 0;
|
|
int *free_array;
|
|
int *dir_array;
|
|
int actual, bitmap;
|
|
errcode_t retval;
|
|
struct problem_context pctx;
|
|
int problem, fixit;
|
|
|
|
clear_problem_context(&pctx);
|
|
free_array = allocate_memory(fs->group_desc_count * sizeof(int),
|
|
"free inode count array");
|
|
|
|
dir_array = allocate_memory(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);
|
|
/* fatal */
|
|
fatal_error(0);
|
|
}
|
|
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);
|
|
/* fatal */
|
|
fatal_error(0);
|
|
}
|
|
|
|
redo_counts:
|
|
for (i = 1; i <= fs->super->s_inodes_count; i++) {
|
|
actual = ext2fs_fast_test_inode_bitmap(ctx->inode_used_map, i);
|
|
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_UNUSED_INODE;
|
|
} else /* if (actual && !bitmap) */ {
|
|
/*
|
|
* Inode used, but not in bitmap
|
|
*/
|
|
problem = PR_5_INODE_USED;
|
|
}
|
|
pctx.ino = i;
|
|
fix_problem(ctx, problem, &pctx);
|
|
|
|
do_counts:
|
|
if (!bitmap) {
|
|
group_free++;
|
|
free_inodes++;
|
|
} else {
|
|
if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, i))
|
|
dirs_count++;
|
|
}
|
|
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;
|
|
group_free = 0;
|
|
dirs_count = 0;
|
|
}
|
|
}
|
|
fixit = end_problem_latch(ctx, PR_LATCH_IBITMAP);
|
|
if (fixit == 1) {
|
|
ext2fs_free_inode_bitmap(fs->inode_map);
|
|
retval = ext2fs_copy_bitmap(ctx->inode_used_map,
|
|
&fs->inode_map);
|
|
/* XXX check retval --- should never fail! */
|
|
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);
|
|
}
|
|
free(free_array);
|
|
free(dir_array);
|
|
}
|
|
|
|
static void check_inode_end(e2fsck_t ctx)
|
|
{
|
|
ext2_filsys fs = ctx->fs;
|
|
ino_t end, save_inodes_count, i;
|
|
struct problem_context pctx;
|
|
|
|
clear_problem_context(&pctx);
|
|
|
|
end = EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count;
|
|
pctx.errcode = ext2fs_fudge_inode_bitmap_end(fs->inode_map, end,
|
|
&save_inodes_count);
|
|
if (pctx.errcode) {
|
|
pctx.num = 1;
|
|
fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
|
|
fatal_error(0);
|
|
}
|
|
if (save_inodes_count == end)
|
|
return;
|
|
|
|
for (i = save_inodes_count + 1; i <= end; i++) {
|
|
if (!ext2fs_test_inode_bitmap(fs->inode_map, i)) {
|
|
if (fix_problem(ctx, PR_5_INODE_BMAP_PADDING, &pctx)) {
|
|
for (i = save_inodes_count + 1; i <= end; i++)
|
|
ext2fs_mark_inode_bitmap(fs->inode_map,
|
|
i);
|
|
ext2fs_mark_ib_dirty(fs);
|
|
} else
|
|
ext2fs_unmark_valid(fs);
|
|
break;
|
|
}
|
|
}
|
|
|
|
pctx.errcode = ext2fs_fudge_inode_bitmap_end(fs->inode_map,
|
|
save_inodes_count, 0);
|
|
if (pctx.errcode) {
|
|
pctx.num = 2;
|
|
fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
|
|
fatal_error(0);
|
|
}
|
|
}
|
|
|
|
static void check_block_end(e2fsck_t ctx)
|
|
{
|
|
ext2_filsys fs = ctx->fs;
|
|
blk_t end, save_blocks_count, i;
|
|
struct problem_context pctx;
|
|
|
|
clear_problem_context(&pctx);
|
|
|
|
end = fs->block_map->start +
|
|
(EXT2_BLOCKS_PER_GROUP(fs->super) * fs->group_desc_count) - 1;
|
|
pctx.errcode = ext2fs_fudge_block_bitmap_end(fs->block_map, end,
|
|
&save_blocks_count);
|
|
if (pctx.errcode) {
|
|
pctx.num = 3;
|
|
fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
|
|
fatal_error(0);
|
|
}
|
|
if (save_blocks_count == end)
|
|
return;
|
|
|
|
for (i = save_blocks_count + 1; i <= end; i++) {
|
|
if (!ext2fs_test_block_bitmap(fs->block_map, i)) {
|
|
if (fix_problem(ctx, PR_5_BLOCK_BMAP_PADDING, &pctx)) {
|
|
for (i = save_blocks_count + 1; i < end; i++)
|
|
ext2fs_mark_block_bitmap(fs->block_map,
|
|
i);
|
|
ext2fs_mark_bb_dirty(fs);
|
|
} else
|
|
ext2fs_unmark_valid(fs);
|
|
break;
|
|
}
|
|
}
|
|
|
|
pctx.errcode = ext2fs_fudge_block_bitmap_end(fs->block_map,
|
|
save_blocks_count, 0);
|
|
if (pctx.errcode) {
|
|
pctx.num = 4;
|
|
fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
|
|
fatal_error(0);
|
|
}
|
|
}
|
|
|
|
|
|
|