aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/vac/vtdump.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/vac/vtdump.c')
-rw-r--r--src/cmd/vac/vtdump.c391
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");
+}