code: mafs

ref: 5c21eca829380c28769f79beabb7cc51f1787f97
dir: /find.c/

View raw version
#include <u.h>
#include <libc.h>
#include "dat.h"
#include "fns.h"

/*
	for an invalid used block, show the directory tree leading to it

	BUG: if the block is a Dentry, does not find it?
 */

enum
{
	Ndir = 128,
};

int debug = 0;
char *devfile = nil;
u64 parents[Ndir];
u64 findblkno;

void walkdentry(u64 blkno, s8 depth);
Tag *readtag(u64 blkno, u8 *buf);

static void
usage(void)
{
	fprint(2, "usage: used [-D ] fsfile blkno\n");
	exits("usage");
}

void
main(int argc, char *argv[])
{
	u64 size;

	ARGBEGIN{
	default:	usage();
	case 'D':	debug++; break;
	}ARGEND

	if(argc != 2)
		usage();

	devfile = argv[0];
	if(devfile == nil)
		sysfatal("no disk file");

	findblkno = atoll(argv[1]);
	if(findblkno == 0){
		fprint(2, "invalid block number %llud\n", findblkno);
		exits(nil);
	}

	if(devfile == nil)
		sysfatal("no disk file");

	if (access(devfile, AREAD) == -1)
		sysfatal("%s cannot access device", devfile);

	size = devinit(devfile);
	if(size == 0)
		panic("null size %s", devfile);
	if(debug)
		print("%s %llud bytes %llud blocks\n", devfile, size, size/Rawblocksize);

	walkdentry(Broot, 0);
	exits(0);
}

void
showparents(void)
{
	s8 i;

	for(i =0; i<Ndir-1 && parents[i] != 0; i++){
		print("%d %llud\n", i, parents[i]);
	}
}

int
checkvalid(u64 blkno, Tag *t, s16 tagtype, u64 qpath)
{
	int ret = 1;

	if(t->type != tagtype || t->path != qpath){
		/* if(debug) */
			fprint(2, "checkvalid invalid %llud tag/path expected %s/%llud actual %s/%llud\n",
					blkno, tagnames[tagtype], qpath, tagnames[t->type], t->path);
		fprint(2, "used: %llud\n", blkno);
		ret=0;
	}/*else
		print("%llud\n", blkno);*/
	if(blkno == findblkno){
		showparents();
		exits(nil);
	}
	return ret;
}

void
walkindir(u64 blkno, u16 tag, u16 bottomtag, u64 qpath, s8 depth)
{
	u8 buf[Rawblocksize], *cbuf;
	Tag *t, *ct;
	u64 cblkno, *bufa;
	int i;
	Spanid *s;
	u16 len;

	devread(blkno, buf, 1);
	t = (Tag*)buf;
	if(checkvalid(blkno, t, tag, qpath)){
		if(t->type == Tind0){
			s = (Spanid*)(buf+sizeof(Tag));
			for(i = 0; i<Nspanidperblock; i++){
				cblkno = s[i].blkno;
				len = s[i].len;
				if(cblkno == 0)
					return;
				cbuf = malloc(len*Rawblocksize);
				devread(cblkno, cbuf, len);
				ct = (Tag*)cbuf;
				if(ct->type == Tdentry && ct->type == bottomtag)
					/* another directory */
					walkdentry(cblkno, depth);
				else
					checkvalid(cblkno, ct, bottomtag, qpath);
				free(cbuf);
			}
		}else{
			bufa = (u64*)(buf+sizeof(Tag));
			cbuf = malloc(Rawblocksize);
			for(i = 0; i<Nindperblock; i++){
				cblkno = bufa[i];
				if(cblkno == 0)
					return;
				devread(cblkno, cbuf, 1);
				/* check tag */
				walkindir(cblkno, tag-1,  bottomtag, qpath, depth);
			}
			free(cbuf);
		}
	}
	return;
}

void
addparent(s8 depth, u64 dblkno)
{
	s8 i;

	for(i =Ndir-1; i>depth; i--){
		parents[i] = 0;
	}
	parents[depth] = dblkno;
}

void
showdepth(s8 depth)
{
	int i;

	for(i = 0; i<depth; i++)
		print(" ");
}

void
walkdentry(u64 blkno, s8 depth)
{
	u8 buf[Rawblocksize], *cbuf;
	Dentry *d;
	Tag *t, *ct;
	u64 cblkno;
	int i;
	u8 isdir;
	u16 len;

	devread(blkno, buf, 1);
	t = (Tag*)buf;
	d = (Dentry*)(buf+sizeof(Tag));
	isdir = (d->mode & DMDIR) > 0;
	showdepth(depth);
	print("%llud:%s\n", blkno, d->name);
	if(debug)
		print("walkdentry %llud tag %s name %s d->qid.path %llud\n",
				blkno, tagnames[t->type], d->name, d->qid.path);
	if(t->type != Tdentry || t->path != d->qid.path){
		if(debug)
			print("walkdentry invalid %llud tag/path expected %s/%llud actual %s/%llud\n",
					blkno, tagnames[Tdentry], d->qid.path, tagnames[t->type], t->path);
		fprint(2, "%llud\n", blkno);
	}/*else
		print("%llud\n", blkno);*/
	addparent(depth, blkno);
	for(i = 0; i<Ndspanid; i++){
		cblkno = d->dspans[i].blkno;
		len = d->dspans[i].len;
		if(cblkno == 0)
			return;
		cbuf = malloc(len*Rawblocksize);
		devread(cblkno, cbuf, len);
		ct = (Tag*)cbuf;
		if(isdir)
			walkdentry(cblkno, depth+1);
		else
			checkvalid(cblkno, ct, Tdata, d->qid.path);
		free(cbuf);
	}
	cbuf = malloc(Rawblocksize);
	for(i = 0; i<Niblock; i++){
		cblkno = d->iblocks[i];
		if(cblkno == 0)
			return;
		devread(cblkno, cbuf, 1);
		ct = (Tag*)cbuf;
		if(ct->type == Tind0+i){
			walkindir(cblkno, Tind0+i, isdir ? Tdentry : Tdata, d->qid.path, depth);
		}else{
			fprint(2, "invalid indir tag %llud\n", cblkno);
			fprint(2, "%llud\n", cblkno);
		}
	}
	free(cbuf);
	return;
}