e2fsprogs/debugfs/icheck.c
Theodore Ts'o e1018eeaa3 Add new debugfs commands and arguments which make it easier to
recover deleted files.  The lsdel command now takes an optional
argument which allows the user to only see the most recently
deleted files.  Also added a new command, undel, which automates
undeleting a deleted inode and linking it back to a directory.
Also added an optional count argument to the testb, freeb, setb,
and find_free_block commands.  The ls command now takes a new
option, -d, which lists deleted directory entries.

Factored out out commonly used code into utility subroutines
for ease of maintenance and to make the executable size smaller.
2002-01-03 04:55:25 -05:00

160 lines
3.3 KiB
C

/*
* icheck.c --- given a list of blocks, generate a list of inodes
*
* Copyright (C) 1994 Theodore Ts'o. This file may be redistributed
* under the terms of the GNU Public License.
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <time.h>
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#include <sys/types.h>
#include "debugfs.h"
struct block_info {
blk_t blk;
ext2_ino_t ino;
};
struct block_walk_struct {
struct block_info *barray;
e2_blkcnt_t blocks_left;
e2_blkcnt_t num_blocks;
ext2_ino_t inode;
};
static int icheck_proc(ext2_filsys fs,
blk_t *block_nr,
e2_blkcnt_t blockcnt,
blk_t ref_block,
int ref_offset,
void *private)
{
struct block_walk_struct *bw = (struct block_walk_struct *) private;
e2_blkcnt_t i;
for (i=0; i < bw->num_blocks; i++) {
if (bw->barray[i].blk == *block_nr) {
bw->barray[i].ino = bw->inode;
bw->blocks_left--;
}
}
if (!bw->blocks_left)
return BLOCK_ABORT;
return 0;
}
void do_icheck(int argc, char **argv)
{
struct block_walk_struct bw;
struct block_info *binfo;
int i;
ext2_inode_scan scan = 0;
ext2_ino_t ino;
struct ext2_inode inode;
errcode_t retval;
char *block_buf;
if (argc < 2) {
com_err(argv[0], 0, "Usage: icheck <block number> ...");
return;
}
if (check_fs_open(argv[0]))
return;
bw.barray = malloc(sizeof(struct block_info) * argc);
if (!bw.barray) {
com_err("icheck", ENOMEM,
"while allocating inode info array");
return;
}
memset(bw.barray, 0, sizeof(struct block_info) * argc);
block_buf = malloc(current_fs->blocksize * 3);
if (!block_buf) {
com_err("icheck", ENOMEM, "while allocating block buffer");
goto error_out;
}
for (i=1; i < argc; i++) {
if (strtoblk(argv[0], argv[i], &bw.barray[i-1].blk))
return;
}
bw.num_blocks = bw.blocks_left = argc-1;
retval = ext2fs_open_inode_scan(current_fs, 0, &scan);
if (retval) {
com_err("icheck", retval, "while opening inode scan");
goto error_out;
}
do {
retval = ext2fs_get_next_inode(scan, &ino, &inode);
} while (retval == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE);
if (retval) {
com_err("icheck", retval, "while starting inode scan");
goto error_out;
}
while (ino) {
if (!inode.i_links_count)
goto next;
if (!ext2fs_inode_has_valid_blocks(&inode))
goto next;
/*
* To handle filesystems touched by 0.3c extfs; can be
* removed later.
*/
if (inode.i_dtime)
goto next;
bw.inode = ino;
retval = ext2fs_block_iterate2(current_fs, ino, 0, block_buf,
icheck_proc, &bw);
if (retval) {
com_err("icheck", retval,
"while calling ext2fs_block_iterate");
goto next;
}
if (bw.blocks_left == 0)
break;
next:
do {
retval = ext2fs_get_next_inode(scan, &ino, &inode);
} while (retval == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE);
if (retval) {
com_err("icheck", retval,
"while doing inode scan");
goto error_out;
}
}
printf("Block\tInode number\n");
for (i=0, binfo = bw.barray; i < bw.num_blocks; i++, binfo++) {
if (binfo->ino == 0) {
printf("%u\t<block not found>\n", binfo->blk);
continue;
}
printf("%u\t%u\n", binfo->blk, binfo->ino);
}
error_out:
free(bw.barray);
free(block_buf);
if (scan)
ext2fs_close_inode_scan(scan);
return;
}