code: mafs

ref: 56bd332994102b4e194819abb5e087a8895452f9
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
 */

Extents useds = {0};
int chatty9p = 0;
char *devfile = nil;
void walkdirectory(u64 blkno);
void walkfile(u64 blkno);
int checkdentry(u64 blkno, u8 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':	chatty9p= 8
	; 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(chatty9p)
		print("%s %llud bytes %llud blocks\n", devfile, size, size/Blocksize);

	initextents(&useds);
	checkdentry(Bdmagic, Tdentry, Qpmagic);
	walkdirectory(Bdroot);
	close(devfd);
	showextents(1, "", &useds);
	exits(0);
}

int
checkvalid(u64 blkno, u8 dtag, u64 dpath, u8 tag, u64 qpath, u16 len)
{
	if(dtag != tag || dpath != qpath){
		/* if(chatty9p) */
		fprint(2, "checkblock invalid %llud tag/path expected %s/%llud actual %s/%llud\n",
			blkno, tagnames[tag], qpath, tagnames[dtag], dpath);
		fprint(2, "used: %llud\n", blkno);
		return 0;
	}
	if(chatty9p)
		print("blkno %llud tag %s\n", blkno, tagnames[dtag]);
	// print("%llud\n", blkno);
	add(&useds, blkno, len);
	return 1;
}

int
checkdentry(u64 blkno, u8 tag, u64 qpath)
{
	u8 buf[Metadatablocksize];
	Dentry *d;

	devread(blkno, buf, Metadataunits);
	recentmetadata(buf, &d, nil);
	return checkvalid(blkno, d->tag, d->path, tag, qpath, Metadataunits);
}

void
walkindir(u64 blkno, u16 tag, u16 bottomtag, u64 qpath)
{
	u8 buf[Metadatablocksize], *cbuf;
	Indirect *t;
	Data *da;
	u64 cblkno;
	int i;
	Dentry *cd;

	devread(blkno, buf, Metadataunits);
	recentmetadata(buf, &t, nil);
	if(checkvalid(blkno, t->tag, t->path, tag, qpath, Metadataunits)){
		if(tag == Tind0){
			for(i = 0; i<Nindperblock; i++){
				cblkno = t->bufa[i];
				if(cblkno == 0)
					return;
				if(bottomtag == Tdentry){
					cbuf = malloc(Metadatablocksize);
					devread(cblkno, cbuf, Metadataunits);
					recentmetadata(cbuf, &cd, nil);
					if((cd->mode & DMDIR) > 0)
						walkdirectory(cblkno);
					else
						walkfile(cblkno);
					free(cbuf);
				}else{
					cbuf = malloc(Maxdatablockunits*Blocksize);
					devread(cblkno, cbuf, 1);
					da = (Data*)cbuf;
					checkvalid(cblkno, da->tag, da->path, Tdata, da->path, da->len);
					free(cbuf);
				}
			}
		}else{
			for(i = 0; i<Nindperblock; i++){
				cblkno = t->bufa[i];
				if(cblkno == 0)
					return;
				walkindir(cblkno, tag-1,  bottomtag, qpath);
			}
		}
	}
	return;
}

void
walkdirectory(u64 blkno)
{
	u8 buf[Metadatablocksize], *cbuf;
	Dentry *d, *cd;
	Indirect *it;
	u64 cblkno;
	int i;

	devread(blkno, buf, Metadataunits);
	recentmetadata(buf, &d, nil);
	if(chatty9p)
		print("walkdirectory %llud tag %s name %s d->path %llud\n",
				blkno, tagnames[d->tag], d->name, d->path);
	if(d->tag != Tdentry || d->path != d->qpath){
		if(chatty9p)
			print("walkdirectory invalid %llud tag/path expected %s/%llud actual %s/%llud\n",
					blkno, tagnames[Tdentry], d->qpath, tagnames[d->tag], d->path);
		fprint(2, "%llud\n", blkno);
	}else{
		// print("%llud\n", blkno);
		add(&useds, blkno, Metadataunits);
	}
	/* 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<Ndblock; i++){
		cblkno = d->dblocks[i];
		if(cblkno == 0)
			return;
		cbuf = malloc(Metadatablocksize);
		devread(cblkno, cbuf, Metadataunits);
		recentmetadata(cbuf, &cd, nil);
		if((cd->mode & DMDIR) > 0)
			walkdirectory(cblkno);
		else
			walkfile(cblkno);
		free(cbuf);
	}
	cbuf = malloc(Metadatablocksize);
	for(i = 0; i<Niblock; i++){
		cblkno = d->iblocks[i];
		if(cblkno == 0)
			return;
		devread(cblkno, cbuf, Metadataunits);
		recentmetadata(cbuf, &it, nil);
		if(it->tag == Tind0+i){
			walkindir(cblkno, Tind0+i, Tdentry, d->qpath);
		}else{
			fprint(2, "invalid indir tag %llud\n", cblkno);
			fprint(2, "%llud\n", cblkno);
		}
	}
	free(cbuf);
	return;
}

void
walkfile(u64 blkno)
{
	u8 buf[Metadatablocksize], *cbuf;
	Dentry *d;
	Data *ct;
	Indirect *it;
	u64 cblkno;
	int i;

	devread(blkno, buf, Metadataunits);
	recentmetadata(buf, &d, nil);
	if(chatty9p)
		print("walkfile %llud tag %s name %s d->qid.path %llud\n",
				blkno, tagnames[d->tag], d->name, d->qpath);
	if(d->tag != Tdentry || d->path != d->qpath){
		if(chatty9p)
			print("walkfile invalid %llud tag/path expected %s/%llud actual %s/%llud\n",
					blkno, tagnames[Tdentry], d->qpath, tagnames[d->tag], d->path);
		fprint(2, "%llud\n", blkno);
	}else{
		// print("%llud\n", blkno);
		add(&useds, blkno, Metadataunits);
	}
	/* do not list the data blocks used by /adm/frees
		as they are considered to be free blocks */
	if(blkno == Bdfrees)
		return;
	if(d->size <= Ddatasize)
		return;

	cbuf = malloc(Maxdatablockunits*Blocksize);
	for(i = 0; i<Ndblock; i++){
		cblkno = d->dblocks[i];
		if(cblkno == 0){
			free(cbuf);
			return;
		}
		devread(cblkno, cbuf, 1);
		ct = (Data*)cbuf;
		checkvalid(cblkno, ct->tag, ct->path, Tdata, d->qpath, ct->len);
	}
	for(i = 0; i<Niblock; i++){
		cblkno = d->iblocks[i];
		if(cblkno == 0){
			free(cbuf);
			return;
		}
		devread(cblkno, cbuf, Metadataunits);
		recentmetadata(buf, &it, nil);
		if(it->tag == Tind0+i){
			walkindir(cblkno, Tind0+i, Tdata, d->qpath);
		}else{
			fprint(2, "invalid indir tag %llud\n", cblkno);
			fprint(2, "%llud\n", cblkno);
		}
	}
	free(cbuf);
	return;
}