/* * 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 "et/com_err.h" #include "e2fsck.h" static void check_block_bitmaps(ext2_filsys fs); static void check_inode_bitmaps(ext2_filsys fs); static void check_inode_end(ext2_filsys fs); static void check_block_end(ext2_filsys fs); static int do_fix = -1; static const char *fix_question = "Fix summary information"; void pass5(ext2_filsys fs) { struct resource_track rtrack; #ifdef MTRACE mtrace_print("Pass 5"); #endif init_resource_track(&rtrack); if (!preen) printf("Pass 5: Checking group summary information\n"); read_bitmaps(fs); check_block_bitmaps(fs); check_inode_bitmaps(fs); check_inode_end(fs); check_block_end(fs); ext2fs_free_inode_bitmap(inode_used_map); ext2fs_free_inode_bitmap(inode_dir_map); ext2fs_free_block_bitmap(block_found_map); if (tflag > 1) { printf("Pass 5: "); print_resource_track(&rtrack); } } static void check_block_bitmaps(ext2_filsys fs) { blk_t i; int *free_array; int group = 0; int blocks = 0; int free_blocks = 0; int group_free = 0; int actual, bitmap; const char *print_header = "Block bitmap differences:"; 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(block_found_map)) || (fs->super->s_blocks_count-1 > ext2fs_get_block_bitmap_end(block_found_map))) { printf("PROGRAMMING ERROR: filesystem endpoints (%d, %d)\n\t" "don't match block_found_map endpoints (%d, %d).\n", fs->super->s_first_data_block, fs->super->s_blocks_count -1, ext2fs_get_block_bitmap_start(block_found_map), ext2fs_get_block_bitmap_end(block_found_map)); 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))) { printf("PROGRAMMING ERROR: filesystem endpoints (%d, %d)\n\t" "don't match fs->block_map endpoints (%d, %d).\n", fs->super->s_first_data_block, fs->super->s_blocks_count -1, ext2fs_get_block_bitmap_start(fs->block_map), ext2fs_get_block_bitmap_end(fs->block_map)); fatal_error(0); } for (i = fs->super->s_first_data_block; i < fs->super->s_blocks_count; i++) { actual = ext2fs_fast_test_block_bitmap(block_found_map, i); bitmap = ext2fs_fast_test_block_bitmap(fs->block_map, i); if (actual == bitmap) goto do_counts; if (do_fix < 0) do_fix = ask(fix_question, 1); if (!preen && print_header) { printf(print_header); print_header = 0; } if (!actual && bitmap) { /* * Block not used, but marked in use in the bitmap. */ if (!preen) printf(" -%u", i); if (do_fix) ext2fs_unmark_block_bitmap(fs->block_map, i); } else { /* * Block used, but not marked in use in the bitmap. */ if (!preen) printf(" +%u", i); if (do_fix) ext2fs_mark_block_bitmap(fs->block_map, i); } if (do_fix) { ext2fs_mark_bb_dirty(fs); bitmap = actual; } else ext2fs_unmark_valid(fs); 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; } } if (!print_header) printf(". %s\n", fix_msg[do_fix]); for (i = 0; i < fs->group_desc_count; i++) { if (free_array[i] != fs->group_desc[i].bg_free_blocks_count) { if (do_fix < 0) do_fix = ask(fix_question, 1); if (!preen) printf("Free blocks count wrong for " "group %u (%u, counted=%d). %s\n", i, fs->group_desc[i].bg_free_blocks_count, free_array[i], fix_msg[do_fix]); if (do_fix) { 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) { if (do_fix < 0) do_fix = ask(fix_question, 1); if (!preen) printf("Free blocks count wrong " "(%u, counted=%d). %s\n", fs->super->s_free_blocks_count, free_blocks, fix_msg[do_fix]); if (do_fix) { 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(ext2_filsys 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; const char *print_header = "Inode bitmap differences:"; 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(inode_used_map)) || (fs->super->s_inodes_count > ext2fs_get_inode_bitmap_end(inode_used_map))) { printf("PROGRAMMING ERROR: filesystem inode endpoints (%d, %d)\n\t" "don't match inode_used_map endpoints (%d, %d).\n", 1, fs->super->s_inodes_count, ext2fs_get_inode_bitmap_start(inode_used_map), ext2fs_get_inode_bitmap_end(inode_used_map)); 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))) { printf("PROGRAMMING ERROR: filesystem inode endpoints (%d, %d)\n\t" "don't match fs->inode_map endpoints (%d, %d).\n", 1, fs->super->s_inodes_count, ext2fs_get_inode_bitmap_start(fs->inode_map), ext2fs_get_inode_bitmap_end(fs->inode_map)); fatal_error(0); } for (i = 1; i <= fs->super->s_inodes_count; i++) { actual = ext2fs_fast_test_inode_bitmap(inode_used_map, i); bitmap = ext2fs_fast_test_inode_bitmap(fs->inode_map, i); if (actual == bitmap) goto do_counts; if (do_fix < 0) do_fix = ask(fix_question, 1); if (!preen && print_header) { printf(print_header); print_header = 0; } if (!actual && bitmap) { /* * Inode wasn't used, but marked in bitmap */ if (!preen) printf(" -%lu", i); if (do_fix) ext2fs_unmark_inode_bitmap(fs->inode_map, i); } else if (actual && !bitmap) { /* * Inode used, but not in bitmap */ if (!preen) printf (" +%lu", i); if (do_fix) ext2fs_mark_inode_bitmap(fs->inode_map, i); } if (do_fix) { ext2fs_mark_ib_dirty(fs); bitmap = actual; } else ext2fs_unmark_valid(fs); do_counts: if (!bitmap) { group_free++; free_inodes++; } else { if (ext2fs_test_inode_bitmap(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; } } if (!print_header) printf(". %s\n", fix_msg[do_fix]); for (i = 0; i < fs->group_desc_count; i++) { if (free_array[i] != fs->group_desc[i].bg_free_inodes_count) { if (do_fix < 0) do_fix = ask(fix_question, 1); if (!preen) printf ("Free inodes count wrong for " "group #%lu (%u, counted=%d). %s\n", i, fs->group_desc[i].bg_free_inodes_count, free_array[i], fix_msg[do_fix]); if (do_fix) { 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) { if (do_fix < 0) do_fix = ask(fix_question, 1); if (!preen) printf ("Directories count wrong for " "group #%lu (%u, counted=%d). %s\n", i, fs->group_desc[i].bg_used_dirs_count, dir_array[i], fix_msg[do_fix]); if (do_fix) { 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) { if (do_fix < 0) do_fix = ask(fix_question, 1); if (!preen) printf("Free inodes count wrong " "(%u, counted=%d). %s\n", fs->super->s_free_inodes_count, free_inodes, fix_msg[do_fix]); if (do_fix) { 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(ext2_filsys fs) { ino_t end, save_inodes_count, i; errcode_t retval; end = EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count; retval = ext2fs_fudge_inode_bitmap_end(fs->inode_map, end, &save_inodes_count); if (retval) { com_err("check_inode_end", retval, "while trying to fudge end of inode bitmap"); 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)) { printf("Padding at end of inode bitmap is not set. "); if (ask("Fix", 1)) { 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; } } retval = ext2fs_fudge_inode_bitmap_end(fs->inode_map, save_inodes_count, 0); if (retval) { com_err("check_inode_end", retval, "while trying to fudge end of inode bitmap back"); fatal_error(0); } } static void check_block_end(ext2_filsys fs) { blk_t end, save_blocks_count, i; errcode_t retval; end = fs->block_map->start + (EXT2_BLOCKS_PER_GROUP(fs->super) * fs->group_desc_count) - 1; retval = ext2fs_fudge_block_bitmap_end(fs->block_map, end, &save_blocks_count); if (retval) { com_err("check_block_end", retval, "while trying to fudge end of block bitmap"); 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)) { printf("Padding at end of block bitmap is not set. "); if (ask("Fix", 1)) { 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; } } retval = ext2fs_fudge_block_bitmap_end(fs->block_map, save_blocks_count, 0); if (retval) { com_err("check_block_end", retval, "while trying to fudge end of block bitmap back"); fatal_error(0); } }