1/* 2 * icheck.c --- given a list of blocks, generate a list of inodes 3 * 4 * Copyright (C) 1994 Theodore Ts'o. This file may be redistributed 5 * under the terms of the GNU Public License. 6 */ 7 8#include <stdio.h> 9#include <unistd.h> 10#include <stdlib.h> 11#include <ctype.h> 12#include <string.h> 13#include <time.h> 14#ifdef HAVE_ERRNO_H 15#include <errno.h> 16#endif 17#include <sys/types.h> 18 19#include "debugfs.h" 20 21struct block_info { 22 blk64_t blk; 23 ext2_ino_t ino; 24}; 25 26struct block_walk_struct { 27 struct block_info *barray; 28 e2_blkcnt_t blocks_left; 29 e2_blkcnt_t num_blocks; 30 ext2_ino_t inode; 31}; 32 33static int icheck_proc(ext2_filsys fs EXT2FS_ATTR((unused)), 34 blk64_t *block_nr, 35 e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)), 36 blk64_t ref_block EXT2FS_ATTR((unused)), 37 int ref_offset EXT2FS_ATTR((unused)), 38 void *private) 39{ 40 struct block_walk_struct *bw = (struct block_walk_struct *) private; 41 e2_blkcnt_t i; 42 43 for (i=0; i < bw->num_blocks; i++) { 44 if (!bw->barray[i].ino && bw->barray[i].blk == *block_nr) { 45 bw->barray[i].ino = bw->inode; 46 bw->blocks_left--; 47 } 48 } 49 if (!bw->blocks_left) 50 return BLOCK_ABORT; 51 52 return 0; 53} 54 55void do_icheck(int argc, char **argv) 56{ 57 struct block_walk_struct bw; 58 struct block_info *binfo; 59 int i; 60 ext2_inode_scan scan = 0; 61 ext2_ino_t ino; 62 struct ext2_inode inode; 63 errcode_t retval; 64 char *block_buf; 65 66 if (argc < 2) { 67 com_err(argv[0], 0, "Usage: icheck <block number> ..."); 68 return; 69 } 70 if (check_fs_open(argv[0])) 71 return; 72 73 bw.barray = malloc(sizeof(struct block_info) * argc); 74 if (!bw.barray) { 75 com_err("icheck", ENOMEM, 76 "while allocating inode info array"); 77 return; 78 } 79 memset(bw.barray, 0, sizeof(struct block_info) * argc); 80 81 block_buf = malloc(current_fs->blocksize * 3); 82 if (!block_buf) { 83 com_err("icheck", ENOMEM, "while allocating block buffer"); 84 goto error_out; 85 } 86 87 for (i=1; i < argc; i++) { 88 if (strtoblk(argv[0], argv[i], &bw.barray[i-1].blk)) 89 goto error_out; 90 } 91 92 bw.num_blocks = bw.blocks_left = argc-1; 93 94 retval = ext2fs_open_inode_scan(current_fs, 0, &scan); 95 if (retval) { 96 com_err("icheck", retval, "while opening inode scan"); 97 goto error_out; 98 } 99 100 do { 101 retval = ext2fs_get_next_inode(scan, &ino, &inode); 102 } while (retval == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE); 103 if (retval) { 104 com_err("icheck", retval, "while starting inode scan"); 105 goto error_out; 106 } 107 108 while (ino) { 109 blk64_t blk; 110 111 if (!inode.i_links_count) 112 goto next; 113 114 bw.inode = ino; 115 116 blk = ext2fs_file_acl_block(current_fs, &inode); 117 if (blk) { 118 icheck_proc(current_fs, &blk, 0, 119 0, 0, &bw); 120 if (bw.blocks_left == 0) 121 break; 122 ext2fs_file_acl_block_set(current_fs, &inode, blk); 123 } 124 125 if (!ext2fs_inode_has_valid_blocks2(current_fs, &inode)) 126 goto next; 127 /* 128 * To handle filesystems touched by 0.3c extfs; can be 129 * removed later. 130 */ 131 if (inode.i_dtime) 132 goto next; 133 134 retval = ext2fs_block_iterate3(current_fs, ino, 135 BLOCK_FLAG_READ_ONLY, block_buf, 136 icheck_proc, &bw); 137 if (retval) { 138 com_err("icheck", retval, 139 "while calling ext2fs_block_iterate"); 140 goto next; 141 } 142 143 if (bw.blocks_left == 0) 144 break; 145 146 next: 147 do { 148 retval = ext2fs_get_next_inode(scan, &ino, &inode); 149 } while (retval == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE); 150 if (retval) { 151 com_err("icheck", retval, 152 "while doing inode scan"); 153 goto error_out; 154 } 155 } 156 157 printf("Block\tInode number\n"); 158 for (i=0, binfo = bw.barray; i < bw.num_blocks; i++, binfo++) { 159 if (binfo->ino == 0) { 160 printf("%llu\t<block not found>\n", binfo->blk); 161 continue; 162 } 163 printf("%llu\t%u\n", binfo->blk, binfo->ino); 164 } 165 166error_out: 167 free(bw.barray); 168 free(block_buf); 169 if (scan) 170 ext2fs_close_inode_scan(scan); 171 return; 172} 173