Blob


1 #include "stdinc.h"
2 #include <bio.h>
4 typedef struct Source Source;
6 struct Source
7 {
8 ulong gen;
9 int psize;
10 int dsize;
11 int dir;
12 int active;
13 int depth;
14 uvlong size;
15 uchar score[VtScoreSize];
16 int reserved;
17 };
19 int bsize;
20 Biobuf *bout;
21 VtRoot root;
22 int ver;
23 int cmp;
24 int all;
25 int find;
26 uchar fscore[VtScoreSize];
27 VtSession *z;
29 int vtGetUint16(uchar *p);
30 ulong vtGetUint32(uchar *p);
31 uvlong vtGetUint48(uchar *p);
32 void usage(void);
33 int parseScore(uchar *score, char *buf, int n);
34 void readRoot(VtRoot*, uchar *score, char *file);
35 int dumpDir(Source*, int indent);
37 void
38 main(int argc, char *argv[])
39 {
40 char *host = nil;
41 uchar score[VtScoreSize];
42 Source source;
43 uchar buf[VtMaxLumpSize];
44 char *p;
45 int n;
47 ARGBEGIN{
48 case 'h':
49 host = ARGF();
50 break;
51 case 'c':
52 cmp++;
53 break;
54 case 'f':
55 find++;
56 p = ARGF();
57 if(p == nil || !parseScore(fscore, p, strlen(p)))
58 usage();
59 break;
60 case 'a':
61 all = 1;
62 break;
63 }ARGEND
65 vtAttach();
67 bout = vtMemAllocZ(sizeof(Biobuf));
68 Binit(bout, 1, OWRITE);
70 if(argc > 1)
71 usage();
73 vtAttach();
75 fmtinstall('V', vtScoreFmt);
76 fmtinstall('R', vtErrFmt);
78 z = vtDial(host, 0);
79 if(z == nil)
80 vtFatal("could not connect to server: %s", vtGetError());
82 if(!vtConnect(z, 0))
83 sysfatal("vtConnect: %r");
85 readRoot(&root, score, argv[0]);
86 ver = root.version;
87 bsize = root.blockSize;
88 if(!find) {
89 Bprint(bout, "score: %V\n", score);
90 Bprint(bout, "version: %d\n", ver);
91 Bprint(bout, "name: %s\n", root.name);
92 Bprint(bout, "type: %s\n", root.type);
93 Bprint(bout, "bsize: %d\n", bsize);
94 Bprint(bout, "prev: %V\n", root.prev);
95 }
97 switch(ver) {
98 default:
99 sysfatal("unknown version");
100 case VtRootVersion:
101 break;
104 n = vtRead(z, root.score, VtDirType, buf, bsize);
105 if(n < 0)
106 sysfatal("could not read root dir");
108 /* fake up top level source */
109 memset(&source, 0, sizeof(source));
110 memmove(source.score, root.score, VtScoreSize);
111 source.psize = bsize;
112 source.dsize = bsize;
113 source.dir = 1;
114 source.active = 1;
115 source.depth = 0;
116 source.size = n;
118 dumpDir(&source, 0);
120 Bterm(bout);
122 vtClose(z);
123 vtDetach();
124 exits(0);
127 void
128 sourcePrint(Source *s, int indent, int entry)
130 int i;
131 uvlong size;
132 int ne;
134 for(i=0; i<indent; i++)
135 Bprint(bout, " ");
136 Bprint(bout, "%4d", entry);
137 if(s->active) {
138 /* dir size in directory entries */
139 if(s->dir) {
140 ne = s->dsize/VtEntrySize;
141 size = ne*(s->size/s->dsize) + (s->size%s->dsize)/VtEntrySize;
142 } else
143 size = s->size;
144 if(cmp) {
145 Bprint(bout, ": gen: %lud size: %llud",
146 s->gen, size);
147 if(!s->dir)
148 Bprint(bout, ": %V", s->score);
149 } else {
150 Bprint(bout, ": gen: %lud psize: %d dsize: %d",
151 s->gen, s->psize, s->dsize);
152 Bprint(bout, " depth: %d size: %llud: %V",
153 s->depth, size, s->score);
156 if(s->reserved)
157 Bprint(bout, ": reserved not emtpy");
159 Bprint(bout, "\n");
162 int
163 parse(Source *s, uchar *p)
165 VtEntry dir;
167 memset(s, 0, sizeof(*s));
168 if(!vtEntryUnpack(&dir, p, 0))
169 return 0;
171 if(!(dir.flags & VtEntryActive))
172 return 1;
174 s->active = 1;
175 s->gen = dir.gen;
176 s->psize = dir.psize;
177 s->dsize = dir.size;
178 s->size = dir.size;
179 memmove(s->score, dir.score, VtScoreSize);
180 if(dir.flags & VtEntryDir)
181 s->dir = 1;
182 s->depth = dir.depth;
183 return 1;
187 int
188 sourceRead(Source *s, ulong block, uchar *p, int n)
190 uchar buf[VtMaxLumpSize];
191 uchar score[VtScoreSize];
192 int i, nn, np, type;
193 int elem[VtPointerDepth];
195 memmove(score, s->score, VtScoreSize);
197 np = s->psize/VtScoreSize;
198 for(i=0; i<s->depth; i++) {
199 elem[i] = block % np;
200 block /= np;
202 assert(block == 0);
204 for(i=s->depth-1; i>=0; i--) {
205 nn = vtRead(z, score, VtPointerType0+i, buf, s->psize);
206 if(nn < 0)
207 return -1;
209 if(!vtSha1Check(score, buf, nn)) {
210 vtSetError("vtSha1Check failed on root block");
211 return -1;
214 if((elem[i]+1)*VtScoreSize > nn)
215 return 0;
216 memmove(score, buf + elem[i]*VtScoreSize, VtScoreSize);
219 if(s->dir)
220 type = VtDirType;
221 else
222 type = VtDataType;
224 nn = vtRead(z, score, type, p, n);
225 if(nn < 0)
226 return -1;
228 if(!vtSha1Check(score, p, nn)) {
229 vtSetError("vtSha1Check failed on root block");
230 return -1;
233 return nn;
236 void
237 dumpFileContents(Source *s)
239 int nb, lb, i, n;
240 uchar buf[VtMaxLumpSize];
242 nb = (s->size + s->dsize - 1)/s->dsize;
243 lb = s->size%s->dsize;
244 for(i=0; i<nb; i++) {
245 memset(buf, 0, s->dsize);
246 n = sourceRead(s, i, buf, s->dsize);
247 if(n < 0) {
248 fprint(2, "could not read block: %d: %s\n", i, vtGetError());
249 continue;
251 if(i < nb-1)
252 Bwrite(bout, buf, s->dsize);
253 else
254 Bwrite(bout, buf, lb);
258 void
259 dumpFile(Source *s, int indent)
261 int nb, i, j, n;
262 uchar buf[VtMaxLumpSize];
263 uchar score[VtScoreSize];
265 nb = (s->size + s->dsize - 1)/s->dsize;
266 for(i=0; i<nb; i++) {
267 memset(buf, 0, s->dsize);
268 n = sourceRead(s, i, buf, s->dsize);
269 if(n < 0) {
270 fprint(2, "could not read block: %d: %s\n", i, vtGetError());
271 continue;
273 for(j=0; j<indent; j++)
274 Bprint(bout, " ");
275 vtSha1(score, buf, n);
276 Bprint(bout, "%4d: size: %ud: %V\n", i, n, score);
280 int
281 dumpDir(Source *s, int indent)
283 int pb, ne, nb, i, j, n, entry;
284 uchar buf[VtMaxLumpSize];
285 Source ss;
287 pb = s->dsize/VtEntrySize;
288 ne = pb*(s->size/s->dsize) + (s->size%s->dsize)/VtEntrySize;
289 nb = (s->size + s->dsize - 1)/s->dsize;
290 for(i=0; i<nb; i++) {
291 memset(buf, 0, s->dsize);
292 n = sourceRead(s, i, buf, s->dsize);
293 if(n < 0) {
294 fprint(2, "could not read block: %d: %s\n", i, vtGetError());
295 continue;
297 for(j=0; j<pb; j++) {
298 entry = i*pb + j;
299 if(entry >= ne)
300 break;
301 parse(&ss, buf + j * VtEntrySize);
303 if(!find)
304 sourcePrint(&ss, indent, entry);
305 else if(memcmp(ss.score, fscore, VtScoreSize) == 0) {
306 dumpFileContents(&ss);
307 return 0;
310 if(ss.dir) {
311 if(!dumpDir(&ss, indent+1))
312 return 0;
313 } else if(all)
314 dumpFile(&ss, indent+1);
317 return 1;
320 void
321 usage(void)
323 fprint(2, "%s: [file]\n", argv0);
324 exits("usage");
327 int
328 parseScore(uchar *score, char *buf, int n)
330 int i, c;
332 memset(score, 0, VtScoreSize);
334 if(n < VtScoreSize*2)
335 return 0;
336 for(i=0; i<VtScoreSize*2; i++) {
337 if(buf[i] >= '0' && buf[i] <= '9')
338 c = buf[i] - '0';
339 else if(buf[i] >= 'a' && buf[i] <= 'f')
340 c = buf[i] - 'a' + 10;
341 else if(buf[i] >= 'A' && buf[i] <= 'F')
342 c = buf[i] - 'A' + 10;
343 else {
344 return 0;
347 if((i & 1) == 0)
348 c <<= 4;
350 score[i>>1] |= c;
352 return 1;
355 void
356 readRoot(VtRoot *root, uchar *score, char *file)
358 int fd;
359 uchar buf[VtRootSize];
360 int i, n, nn;
362 if(file == 0)
363 fd = 0;
364 else {
365 fd = open(file, OREAD);
366 if(fd < 0)
367 sysfatal("could not open file: %s: %r\n", file);
369 n = readn(fd, buf, sizeof(buf)-1);
370 if(n < 0)
371 sysfatal("read failed: %r\n");
372 buf[n] = 0;
373 close(fd);
375 for(i=0; i<n; i++) {
376 if(!parseScore(score, (char*)(buf+i), n-i))
377 continue;
378 nn = vtRead(z, score, VtRootType, buf, VtRootSize);
379 if(nn >= 0) {
380 if(nn != VtRootSize)
381 sysfatal("vtRead on root too short");
382 if(!vtSha1Check(score, buf, VtRootSize))
383 sysfatal("vtSha1Check failed on root block");
384 if(!vtRootUnpack(root, buf))
385 sysfatal("could not parse root: %r");
386 return;
390 sysfatal("could not find root");