ref: b3e875d7db45fca0cde9f4efa12872f61afc54d7
dir: /used.c/
#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 TODO check that the file size is matched by the number of blocks */ Extents useds = {0}; int chatty9p = 0; char *devfile = nil; void *emalloc(u32); void panic(char *fmt, ...); 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 * mallocu32(u32 sz) { return mallocz((ulong)sz, 1); } void main(int argc, char *argv[]) { u64 size; Errenv env = {0}; envpp = privalloc(); *envpp = &env; if(waserror()){ panic(0, "err stack %d: %lux %lux %lux %lux %lux %lux", env.nlabel, env.label[0][JMPBUFPC], env.label[1][JMPBUFPC], env.label[2][JMPBUFPC], env.label[3][JMPBUFPC], env.label[4][JMPBUFPC], env.label[5][JMPBUFPC]); } 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, "useds", 0, 0, 2, nil, fprint, panic, emalloc); 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); ufree(&useds, blkno, len); return 1; } int checkdentry(u64 blkno, u8 tag, u64 qpath) { u8 buf[Blocksize]; Dentry *d; devread(blkno, buf, 1); d = (Dentry*)buf; return checkvalid(blkno, d->tag, d->path, tag, qpath, 1); } /* not checking the ending path as it would take too long */ void walkindir(u64 blkno, u16 tag, u16 bottomtag, u64 qpath, u64 *nblocksp) { u8 buf[Blocksize], cbuf[Blocksize]; u64 ebuf[Nu64perblock]; Indirect *t; Data *da; u64 cblkno, path; int i; Dentry *cd; devread(blkno, buf, 1); t = (Indirect*)buf; if(checkvalid(blkno, t->tagi, t->pathi, tag, qpath, 1)){ if(tag == Tind0){ for(i = 0; i<Nindperblock; i++){ cblkno = t->bufa[i]; if(cblkno == 0) return; if(bottomtag == Tdentry){ devread(cblkno, cbuf, 1); cd = (Dentry*)cbuf; if((cd->mode & DMDIR) > 0) walkdirectory(cblkno); else walkfile(cblkno); }else{ devread(cblkno, cbuf, 1); da = (Data*)cbuf; *nblocksp += da->len; devread(cblkno+da->len-1, ebuf, 1); path = ebuf[Dpathidx]; checkvalid(cblkno, da->tag, path, Tdata, qpath, da->len); } } }else{ for(i = 0; i<Nindperblock; i++){ cblkno = t->bufa[i]; if(cblkno == 0) return; walkindir(cblkno, tag-1, bottomtag, qpath, nblocksp); } } } return; } void walkdirectory(u64 blkno) { u8 buf[Blocksize], cbuf[Blocksize]; Dentry *d, *cd; Indirect *it; u64 cblkno; int i; devread(blkno, buf, 1); d = (Dentry*)buf; if(chatty9p) print("walkdirectory %llud tag %s d->path %llud\n", blkno, tagnames[d->tag], 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); ufree(&useds, blkno, 1); } /* do not list the data blocks used by /a/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; devread(cblkno, cbuf, 1); cd = (Dentry*)cbuf; if((cd->mode & DMDIR) > 0) walkdirectory(cblkno); else walkfile(cblkno); } for(i = 0; i<Niblock; i++){ cblkno = d->iblocks[i]; if(cblkno == 0) return; devread(cblkno, cbuf, 1); it = (Indirect*)cbuf; if(it->tagi == Tind0+i){ walkindir(cblkno, Tind0+i, Tdentry, d->qpath, nil); }else{ fprint(2, "invalid indir tag %llud\n", cblkno); fprint(2, "%llud\n", cblkno); } } return; } void walkfile(u64 blkno) { u8 buf[Blocksize], cbuf[Blocksize]; u64 ebuf[Nu64perblock], nblocks; Dentry *d; Data *ct; Indirect *it; u64 cblkno, path; int i; devread(blkno, buf, 1); d = (Dentry*)buf; if(chatty9p) print("walkfile %llud tag %s d->qid.path %llud\n", blkno, tagnames[d->tag], 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); ufree(&useds, blkno, 1); } /* do not list the data blocks used by /a/frees as they are considered to be free blocks */ if(blkno == Bdfrees) return; if(d->size <= Ddatasize) return; nblocks = 0; for(i = 0; i<Ndblock; i++){ cblkno = d->dblocks[i]; if(cblkno == 0) return; devread(cblkno, cbuf, 1); ct = (Data*)cbuf; nblocks += ct->len; devread(cblkno+ct->len-1, ebuf, 1); path = ebuf[Dpathidx]; checkvalid(cblkno, ct->tag, path, Tdata, d->qpath, ct->len); } for(i = 0; i<Niblock; i++){ cblkno = d->iblocks[i]; if(cblkno == 0) return; devread(cblkno, cbuf, 1); it = (Indirect*)cbuf; if(it->tagi == Tind0+i){ walkindir(cblkno, Tind0+i, Tdata, d->qpath, &nblocks); }else{ fprint(2, "invalid indir tag of block %llud %d %s\n", cblkno, it->tagi, tagnames[it->tagi]); fprint(2, "%llud\n", cblkno); } } if(d->size/Maxdatablocksize != nblocks/Maxdatablockunits || nlastdatablocks(d->size%Maxdatablocksize) != nblocks%Maxdatablockunits) fprint(2, "file size %llud is using %llud blocks\n", d->size, nblocks); return; }