code: mafs

ref: 5c21eca829380c28769f79beabb7cc51f1787f97
dir: /used.c/

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

/*
	go through all the blocks and write out all the used block numbers
	to be used by the checker
	Starting from root, walk down each dentry printing out the linked blocks with invalid tags
 */

int debug = 0;
char *devfile = nil;
void walkdentry(u64 blkno);
int checkblock(u64 blkno, s16 tag, u64 qpath);

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

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

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

	if(argc != 1)
		usage();

	devfile = argv[0];
	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);

	checkblock(Bmagicb, Tmagic, Qpmagic);
	walkdentry(Broot);
	exits(0);
}

int
checkvalid(u64 blkno, Tag *t, s16 tagtype, u64 qpath)
{
	u16 i;

	if(t->type != tagtype || t->path != qpath || t->dirty != 0){
		/* if(debug) */
		fprint(2, "checkblock invalid %llud tag/path expected %s/%llud actual %s/%llud dirty %d\n",
			blkno, tagnames[tagtype], qpath, tagnames[t->type], t->path, t->dirty);
		fprint(2, "used: %llud\n", blkno);
		return 0;
	}
	if(debug)
		print("blkno %llud len %d tag %s\n", blkno, t->len, tagnames[t->type]);
	for(i = 0; i < t->len; i++){
		print("%llud\n", blkno+i);
	}
	return 1;
}

int
checkblock(u64 blkno, s16 tag, u64 qpath)
{
	u8 buf[Rawblocksize];
	Tag *t;

	devread(blkno, buf, 1);
	t = (Tag*)buf;
	return checkvalid(blkno, t, tag, qpath);
}

void
walkindir(u64 blkno, u16 tag, u16 bottomtag, u64 qpath)
{
	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)
					walkdentry(cblkno);
				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);
			}
			free(cbuf);
		}
	}
	return;
}

void
walkdentry(u64 blkno)
{
	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;
	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);
	/* do not list the data blocks used by /adm/frees
		as they are considered to be free blocks */
	if(blkno == Bdfrees)
		return;
	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);
		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);
		}else{
			fprint(2, "invalid indir tag %llud\n", cblkno);
			fprint(2, "%llud\n", cblkno);
		}
	}
	free(cbuf);
	return;
}