diff options
Diffstat (limited to 'src/cmd/vac/vtdump.c')
-rw-r--r-- | src/cmd/vac/vtdump.c | 391 |
1 files changed, 391 insertions, 0 deletions
diff --git a/src/cmd/vac/vtdump.c b/src/cmd/vac/vtdump.c new file mode 100644 index 00000000..963e4689 --- /dev/null +++ b/src/cmd/vac/vtdump.c @@ -0,0 +1,391 @@ +#include "stdinc.h" +#include <bio.h> + +typedef struct Source Source; + +struct Source +{ + ulong gen; + int psize; + int dsize; + int dir; + int active; + int depth; + uvlong size; + uchar score[VtScoreSize]; + int reserved; +}; + +int bsize; +Biobuf *bout; +VtRoot root; +int ver; +int cmp; +int all; +int find; +uchar fscore[VtScoreSize]; +VtSession *z; + +int vtGetUint16(uchar *p); +ulong vtGetUint32(uchar *p); +uvlong vtGetUint48(uchar *p); +void usage(void); +int parseScore(uchar *score, char *buf, int n); +void readRoot(VtRoot*, uchar *score, char *file); +int dumpDir(Source*, int indent); + +void +main(int argc, char *argv[]) +{ + char *host = nil; + uchar score[VtScoreSize]; + Source source; + uchar buf[VtMaxLumpSize]; + char *p; + int n; + + ARGBEGIN{ + case 'h': + host = ARGF(); + break; + case 'c': + cmp++; + break; + case 'f': + find++; + p = ARGF(); + if(p == nil || !parseScore(fscore, p, strlen(p))) + usage(); + break; + case 'a': + all = 1; + break; + }ARGEND + + vtAttach(); + + bout = vtMemAllocZ(sizeof(Biobuf)); + Binit(bout, 1, OWRITE); + + if(argc > 1) + usage(); + + vtAttach(); + + fmtinstall('V', vtScoreFmt); + fmtinstall('R', vtErrFmt); + + z = vtDial(host, 0); + if(z == nil) + vtFatal("could not connect to server: %s", vtGetError()); + + if(!vtConnect(z, 0)) + sysfatal("vtConnect: %r"); + + readRoot(&root, score, argv[0]); + ver = root.version; + bsize = root.blockSize; + if(!find) { + Bprint(bout, "score: %V\n", score); + Bprint(bout, "version: %d\n", ver); + Bprint(bout, "name: %s\n", root.name); + Bprint(bout, "type: %s\n", root.type); + Bprint(bout, "bsize: %d\n", bsize); + Bprint(bout, "prev: %V\n", root.prev); + } + + switch(ver) { + default: + sysfatal("unknown version"); + case VtRootVersion: + break; + } + + n = vtRead(z, root.score, VtDirType, buf, bsize); + if(n < 0) + sysfatal("could not read root dir"); + + /* fake up top level source */ + memset(&source, 0, sizeof(source)); + memmove(source.score, root.score, VtScoreSize); + source.psize = bsize; + source.dsize = bsize; + source.dir = 1; + source.active = 1; + source.depth = 0; + source.size = n; + + dumpDir(&source, 0); + + Bterm(bout); + + vtClose(z); + vtDetach(); + exits(0); +} + +void +sourcePrint(Source *s, int indent, int entry) +{ + int i; + uvlong size; + int ne; + + for(i=0; i<indent; i++) + Bprint(bout, " "); + Bprint(bout, "%4d", entry); + if(s->active) { + /* dir size in directory entries */ + if(s->dir) { + ne = s->dsize/VtEntrySize; + size = ne*(s->size/s->dsize) + (s->size%s->dsize)/VtEntrySize; + } else + size = s->size; + if(cmp) { + Bprint(bout, ": gen: %lud size: %llud", + s->gen, size); + if(!s->dir) + Bprint(bout, ": %V", s->score); + } else { + Bprint(bout, ": gen: %lud psize: %d dsize: %d", + s->gen, s->psize, s->dsize); + Bprint(bout, " depth: %d size: %llud: %V", + s->depth, size, s->score); + } + + if(s->reserved) + Bprint(bout, ": reserved not emtpy"); + } + Bprint(bout, "\n"); +} + +int +parse(Source *s, uchar *p) +{ + VtEntry dir; + + memset(s, 0, sizeof(*s)); + if(!vtEntryUnpack(&dir, p, 0)) + return 0; + + if(!(dir.flags & VtEntryActive)) + return 1; + + s->active = 1; + s->gen = dir.gen; + s->psize = dir.psize; + s->dsize = dir.size; + s->size = dir.size; + memmove(s->score, dir.score, VtScoreSize); + if(dir.flags & VtEntryDir) + s->dir = 1; + s->depth = dir.depth; + return 1; + +} + +int +sourceRead(Source *s, ulong block, uchar *p, int n) +{ + uchar buf[VtMaxLumpSize]; + uchar score[VtScoreSize]; + int i, nn, np, type; + int elem[VtPointerDepth]; + + memmove(score, s->score, VtScoreSize); + + np = s->psize/VtScoreSize; + for(i=0; i<s->depth; i++) { + elem[i] = block % np; + block /= np; + } + assert(block == 0); + + for(i=s->depth-1; i>=0; i--) { + nn = vtRead(z, score, VtPointerType0+i, buf, s->psize); + if(nn < 0) + return -1; + + if(!vtSha1Check(score, buf, nn)) { + vtSetError("vtSha1Check failed on root block"); + return -1; + } + + if((elem[i]+1)*VtScoreSize > nn) + return 0; + memmove(score, buf + elem[i]*VtScoreSize, VtScoreSize); + } + + if(s->dir) + type = VtDirType; + else + type = VtDataType; + + nn = vtRead(z, score, type, p, n); + if(nn < 0) + return -1; + + if(!vtSha1Check(score, p, nn)) { + vtSetError("vtSha1Check failed on root block"); + return -1; + } + + return nn; +} + +void +dumpFileContents(Source *s) +{ + int nb, lb, i, n; + uchar buf[VtMaxLumpSize]; + + nb = (s->size + s->dsize - 1)/s->dsize; + lb = s->size%s->dsize; + for(i=0; i<nb; i++) { + memset(buf, 0, s->dsize); + n = sourceRead(s, i, buf, s->dsize); + if(n < 0) { + fprint(2, "could not read block: %d: %s\n", i, vtGetError()); + continue; + } + if(i < nb-1) + Bwrite(bout, buf, s->dsize); + else + Bwrite(bout, buf, lb); + } +} + +void +dumpFile(Source *s, int indent) +{ + int nb, i, j, n; + uchar buf[VtMaxLumpSize]; + uchar score[VtScoreSize]; + + nb = (s->size + s->dsize - 1)/s->dsize; + for(i=0; i<nb; i++) { + memset(buf, 0, s->dsize); + n = sourceRead(s, i, buf, s->dsize); + if(n < 0) { + fprint(2, "could not read block: %d: %s\n", i, vtGetError()); + continue; + } + for(j=0; j<indent; j++) + Bprint(bout, " "); + vtSha1(score, buf, n); + Bprint(bout, "%4d: size: %ud: %V\n", i, n, score); + } +} + +int +dumpDir(Source *s, int indent) +{ + int pb, ne, nb, i, j, n, entry; + uchar buf[VtMaxLumpSize]; + Source ss; + + pb = s->dsize/VtEntrySize; + ne = pb*(s->size/s->dsize) + (s->size%s->dsize)/VtEntrySize; + nb = (s->size + s->dsize - 1)/s->dsize; + for(i=0; i<nb; i++) { + memset(buf, 0, s->dsize); + n = sourceRead(s, i, buf, s->dsize); + if(n < 0) { + fprint(2, "could not read block: %d: %s\n", i, vtGetError()); + continue; + } + for(j=0; j<pb; j++) { + entry = i*pb + j; + if(entry >= ne) + break; + parse(&ss, buf + j * VtEntrySize); + + if(!find) + sourcePrint(&ss, indent, entry); + else if(memcmp(ss.score, fscore, VtScoreSize) == 0) { + dumpFileContents(&ss); + return 0; + } + + if(ss.dir) { + if(!dumpDir(&ss, indent+1)) + return 0; + } else if(all) + dumpFile(&ss, indent+1); + } + } + return 1; +} + +void +usage(void) +{ + fprint(2, "%s: [file]\n", argv0); + exits("usage"); +} + +int +parseScore(uchar *score, char *buf, int n) +{ + int i, c; + + memset(score, 0, VtScoreSize); + + if(n < VtScoreSize*2) + return 0; + for(i=0; i<VtScoreSize*2; i++) { + if(buf[i] >= '0' && buf[i] <= '9') + c = buf[i] - '0'; + else if(buf[i] >= 'a' && buf[i] <= 'f') + c = buf[i] - 'a' + 10; + else if(buf[i] >= 'A' && buf[i] <= 'F') + c = buf[i] - 'A' + 10; + else { + return 0; + } + + if((i & 1) == 0) + c <<= 4; + + score[i>>1] |= c; + } + return 1; +} + +void +readRoot(VtRoot *root, uchar *score, char *file) +{ + int fd; + uchar buf[VtRootSize]; + int i, n, nn; + + if(file == 0) + fd = 0; + else { + fd = open(file, OREAD); + if(fd < 0) + sysfatal("could not open file: %s: %r\n", file); + } + n = readn(fd, buf, sizeof(buf)-1); + if(n < 0) + sysfatal("read failed: %r\n"); + buf[n] = 0; + close(fd); + + for(i=0; i<n; i++) { + if(!parseScore(score, (char*)(buf+i), n-i)) + continue; + nn = vtRead(z, score, VtRootType, buf, VtRootSize); + if(nn >= 0) { + if(nn != VtRootSize) + sysfatal("vtRead on root too short"); + if(!vtSha1Check(score, buf, VtRootSize)) + sysfatal("vtSha1Check failed on root block"); + if(!vtRootUnpack(root, buf)) + sysfatal("could not parse root: %r"); + return; + } + } + + sysfatal("could not find root"); +} |