o Implement findblk command: find the inode(s) owning the specified

disk block(s) number(s).

Obtained from:	NetBSD
MFC after:	2 months
This commit is contained in:
Maxim Konovalov 2006-06-02 12:55:26 +00:00
parent b2adc703fd
commit 82d9b14e16
2 changed files with 272 additions and 1 deletions

View File

@ -28,7 +28,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd September 14, 1995
.Dd June 2, 2006
.Dt FSDB 8
.Os
.Sh NAME
@ -117,6 +117,12 @@ Print out the active inode.
Print out the block list of the active inode.
Note that the printout can become long for large files, since all
indirect block pointers will also be printed.
.Pp
.It Cm findblk Ar disk block number ...
Find the inode(s) owning the specified disk block(s) number(s).
Note that these are not absolute disk blocks numbers, but offsets from the
start of the partition.
.Pp
.It Cm uplink
Increment the active inode's link count.
.Pp

View File

@ -52,6 +52,13 @@ static const char rcsid[] =
static void usage(void) __dead2;
int cmdloop(void);
static int compare_blk32(uint32_t *wantedblk, uint32_t curblk);
static int compare_blk64(uint64_t *wantedblk, uint64_t curblk);
static int founddatablk(uint64_t blk);
static int find_blks32(uint32_t *buf, int size, uint32_t *blknum);
static int find_blks64(uint64_t *buf, int size, uint64_t *blknum);
static int find_indirblks32(uint32_t blk, int ind_level, uint32_t *blknum);
static int find_indirblks64(uint64_t blk, int ind_level, uint64_t *blknum);
static void
usage(void)
@ -129,6 +136,7 @@ CMDFUNC(uplink); /* incr link */
CMDFUNC(downlink); /* decr link */
CMDFUNC(linkcount); /* set link count */
CMDFUNC(quit); /* quit */
CMDFUNC(findblk); /* find block */
CMDFUNC(ls); /* list directory */
CMDFUNC(rm); /* remove name */
CMDFUNC(ln); /* add name */
@ -160,6 +168,7 @@ struct cmdtable cmds[] = {
{ "uplink", "Increment link count", 1, 1, FL_WR, uplink },
{ "downlink", "Decrement link count", 1, 1, FL_WR, downlink },
{ "linkcount", "Set link count to COUNT", 2, 2, FL_WR, linkcount },
{ "findblk", "Find inode owning disk block(s)", 2, 33, FL_RO, findblk},
{ "ls", "List current inode as directory", 1, 1, FL_RO, ls },
{ "rm", "Remove NAME from current inode directory", 2, 2, FL_WR | FL_ST, rm },
{ "del", "Remove NAME from current inode directory", 2, 2, FL_WR | FL_ST, rm },
@ -415,6 +424,262 @@ CMDFUNCSTART(ls)
return 0;
}
static int findblk_numtofind;
static int wantedblksize;
CMDFUNCSTART(findblk)
{
ino_t inum, inosused;
uint32_t *wantedblk32;
uint64_t *wantedblk64;
struct cg *cgp = &cgrp;
int c, i, is_ufs2;
wantedblksize = (argc - 1);
is_ufs2 = sblock.fs_magic == FS_UFS2_MAGIC;
ocurrent = curinum;
if (is_ufs2) {
wantedblk64 = calloc(wantedblksize, sizeof(uint64_t));
if (wantedblk64 == NULL)
err(1, "malloc");
for (i = 1; i < argc; i++)
wantedblk64[i - 1] = dbtofsb(&sblock, strtoull(argv[i], NULL, 0));
} else {
wantedblk32 = calloc(wantedblksize, sizeof(uint32_t));
if (wantedblk32 == NULL)
err(1, "malloc");
for (i = 1; i < argc; i++)
wantedblk32[i - 1] = dbtofsb(&sblock, strtoull(argv[i], NULL, 0));
}
findblk_numtofind = wantedblksize;
/*
* sblock.fs_ncg holds a number of cylinder groups.
* Iterate over all cylinder groups.
*/
for (c = 0; c < sblock.fs_ncg; c++) {
/*
* sblock.fs_ipg holds a number of inodes per cylinder group.
* Calculate a highest inode number for a given cylinder group.
*/
inum = c * sblock.fs_ipg;
/* Read cylinder group. */
getblk(&cgblk, cgtod(&sblock, c), sblock.fs_cgsize);
memcpy(cgp, cgblk.b_un.b_cg, sblock.fs_cgsize);
/*
* Get a highest used inode number for a given cylinder group.
* For UFS1 all inodes initialized at the newfs stage.
*/
if (is_ufs2)
inosused = cgp->cg_initediblk;
else
inosused = sblock.fs_ipg;
for (; inosused > 0; inum++, inosused--) {
/* Skip magic inodes: 0, WINO, ROOTINO. */
if (inum < ROOTINO)
continue;
/*
* Check if the block we are looking for is just an inode block.
*
* ino_to_fsba() - get block containing inode from its number.
* INOPB() - get a number of inodes in one disk block.
*/
if (is_ufs2 ?
compare_blk64(wantedblk64, ino_to_fsba(&sblock, inum)) :
compare_blk32(wantedblk32, ino_to_fsba(&sblock, inum))) {
printf("block %llu: inode block (%d-%d)\n",
(unsigned long long)fsbtodb(&sblock,
ino_to_fsba(&sblock, inum)),
(inum / INOPB(&sblock)) * INOPB(&sblock),
(inum / INOPB(&sblock) + 1) * INOPB(&sblock));
findblk_numtofind--;
if (findblk_numtofind == 0)
goto end;
}
/* Get on-disk inode aka dinode. */
curinum = inum;
curinode = ginode(inum);
/* Find IFLNK dinode with allocated data blocks. */
switch (DIP(curinode, di_mode) & IFMT) {
case IFDIR:
case IFREG:
if (DIP(curinode, di_blocks) == 0)
continue;
break;
case IFLNK:
{
uint64_t size = DIP(curinode, di_size);
if (size > 0 && size < sblock.fs_maxsymlinklen &&
DIP(curinode, di_blocks) == 0)
continue;
else
break;
}
default:
continue;
}
/* Look through direct data blocks. */
if (is_ufs2 ?
find_blks64(curinode->dp2.di_db, NDADDR, wantedblk64) :
find_blks32(curinode->dp1.di_db, NDADDR, wantedblk32))
goto end;
for (i = 0; i < NIADDR; i++) {
/*
* Does the block we are looking for belongs to the
* indirect blocks?
*/
if (is_ufs2 ?
compare_blk64(wantedblk64, curinode->dp2.di_ib[i]) :
compare_blk32(wantedblk32, curinode->dp1.di_ib[i]))
if (founddatablk(is_ufs2 ? curinode->dp2.di_ib[i] :
curinode->dp1.di_ib[i]))
goto end;
/*
* Search through indirect, double and triple indirect
* data blocks.
*/
if (is_ufs2 ? (curinode->dp2.di_ib[i] != 0) :
(curinode->dp1.di_ib[i] != 0))
if (is_ufs2 ?
find_indirblks64(curinode->dp2.di_ib[i], i,
wantedblk64) :
find_indirblks32(curinode->dp1.di_ib[i], i,
wantedblk32))
goto end;
}
}
}
end:
curinum = ocurrent;
curinode = ginode(curinum);
return 0;
}
static int
compare_blk32(uint32_t *wantedblk, uint32_t curblk)
{
int i;
for (i = 0; i < wantedblksize; i++) {
if (wantedblk[i] != 0 && wantedblk[i] == curblk) {
wantedblk[i] = 0;
return 1;
}
}
return 0;
}
static int
compare_blk64(uint64_t *wantedblk, uint64_t curblk)
{
int i;
for (i = 0; i < wantedblksize; i++) {
if (wantedblk[i] != 0 && wantedblk[i] == curblk) {
wantedblk[i] = 0;
return 1;
}
}
return 0;
}
static int
founddatablk(uint64_t blk)
{
printf("%llu: data block of inode %d\n",
(unsigned long long)fsbtodb(&sblock, blk), curinum);
findblk_numtofind--;
if (findblk_numtofind == 0)
return 1;
return 0;
}
static int
find_blks32(uint32_t *buf, int size, uint32_t *wantedblk)
{
int blk;
for (blk = 0; blk < size; blk++) {
if (buf[blk] == 0)
continue;
if (compare_blk32(wantedblk, buf[blk])) {
if (founddatablk(buf[blk]))
return 1;
}
}
return 0;
}
static int
find_indirblks32(uint32_t blk, int ind_level, uint32_t *wantedblk)
{
#define MAXNINDIR (MAXBSIZE / sizeof(uint32_t))
uint32_t idblk[MAXNINDIR];
int i;
bread(fsreadfd, (char *)idblk, fsbtodb(&sblock, blk), (int)sblock.fs_bsize);
if (ind_level <= 0) {
if (find_blks32(idblk, sblock.fs_bsize / sizeof(uint32_t), wantedblk))
return 1;
} else {
ind_level--;
for (i = 0; i < sblock.fs_bsize / sizeof(uint32_t); i++) {
if (compare_blk32(wantedblk, idblk[i])) {
if (founddatablk(idblk[i]))
return 1;
}
if (idblk[i] != 0)
if (find_indirblks32(idblk[i], ind_level, wantedblk))
return 1;
}
}
#undef MAXNINDIR
return 0;
}
static int
find_blks64(uint64_t *buf, int size, uint64_t *wantedblk)
{
int blk;
for (blk = 0; blk < size; blk++) {
if (buf[blk] == 0)
continue;
if (compare_blk64(wantedblk, buf[blk])) {
if (founddatablk(buf[blk]))
return 1;
}
}
return 0;
}
static int
find_indirblks64(uint64_t blk, int ind_level, uint64_t *wantedblk)
{
#define MAXNINDIR (MAXBSIZE / sizeof(uint64_t))
uint64_t idblk[MAXNINDIR];
int i;
bread(fsreadfd, (char *)idblk, fsbtodb(&sblock, blk), (int)sblock.fs_bsize);
if (ind_level <= 0) {
if (find_blks64(idblk, sblock.fs_bsize / sizeof(uint64_t), wantedblk))
return 1;
} else {
ind_level--;
for (i = 0; i < sblock.fs_bsize / sizeof(uint64_t); i++) {
if (compare_blk64(wantedblk, idblk[i])) {
if (founddatablk(idblk[i]))
return 1;
}
if (idblk[i] != 0)
if (find_indirblks64(idblk[i], ind_level, wantedblk))
return 1;
}
}
#undef MAXNINDIR
return 0;
}
int findino(struct inodesc *idesc); /* from fsck */
static int dolookup(char *name);