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 VtConn *z;
29 int vtgetuint16(uchar *p);
30 ulong vtgetuint32(uchar *p);
31 uvlong vtgetuint48(uchar *p);
32 void usage(void);
33 void readroot(VtRoot*, uchar *score, char *file);
34 int dumpdir(Source*, int indent);
35 int timevtread(VtConn*, uchar*, int, void*, int);
37 int mainstacksize = 512*1024;
39 void
40 threadmain(int argc, char *argv[])
41 {
42 char *host = nil, *pref;
43 uchar score[VtScoreSize];
44 Source source;
45 char *p;
46 int n;
47 uchar buf[VtMaxLumpSize];
49 ARGBEGIN{
50 case 'h':
51 host = ARGF();
52 break;
53 case 'c':
54 cmp++;
55 break;
56 case 'f':
57 find++;
58 p = ARGF();
59 if(p == nil || vtparsescore(p, &pref, fscore) < 0 || !pref || strcmp(pref, "vac") != 0)
60 usage();
61 break;
62 case 'a':
63 all = 1;
64 break;
65 }ARGEND
67 bout = vtmallocz(sizeof(Biobuf));
68 Binit(bout, 1, OWRITE);
70 if(argc > 1)
71 usage();
73 fmtinstall('V', vtscorefmt);
74 fmtinstall('H', encodefmt);
76 z = vtdial(host);
77 if(z == nil)
78 sysfatal("could not connect to server: %r");
80 if(vtconnect(z) < 0)
81 sysfatal("vtconnect: %r");
83 readroot(&root, score, argv[0]);
84 bsize = root.blocksize;
85 if(!find) {
86 Bprint(bout, "score: %V\n", score);
87 Bprint(bout, "name: %s\n", root.name);
88 Bprint(bout, "type: %s\n", root.type);
89 Bprint(bout, "bsize: %d\n", bsize);
90 Bprint(bout, "prev: %V\n", root.prev);
91 }
93 fprint(2, "read...\n");
94 n = timevtread(z, root.score, VtDirType, buf, bsize);
95 if(n < 0)
96 sysfatal("could not read root dir");
98 fprint(2, "...\n");
99 /* fake up top level source */
100 memset(&source, 0, sizeof(source));
101 memmove(source.score, root.score, VtScoreSize);
102 source.psize = bsize;
103 source.dsize = bsize;
104 source.dir = 1;
105 source.active = 1;
106 source.depth = 0;
107 source.size = n;
109 dumpdir(&source, 0);
111 Bterm(bout);
113 vthangup(z);
114 threadexitsall(0);
117 void
118 sourceprint(Source *s, int indent, int entry)
120 int i;
121 uvlong size;
122 int ne;
124 for(i=0; i<indent; i++)
125 Bprint(bout, " ");
126 Bprint(bout, "%4d", entry);
127 if(s->active) {
128 /* dir size in directory entries */
129 if(s->dir) {
130 ne = s->dsize/VtEntrySize;
131 size = ne*(s->size/s->dsize) + (s->size%s->dsize)/VtEntrySize;
132 } else
133 size = s->size;
134 if(cmp) {
135 Bprint(bout, ": gen: %lud size: %llud",
136 s->gen, size);
137 if(!s->dir)
138 Bprint(bout, ": %V", s->score);
139 } else {
140 Bprint(bout, ": gen: %lud psize: %d dsize: %d",
141 s->gen, s->psize, s->dsize);
142 Bprint(bout, " depth: %d size: %llud: %V",
143 s->depth, size, s->score);
146 if(s->reserved)
147 Bprint(bout, ": reserved not emtpy");
149 Bprint(bout, "\n");
152 int
153 parse(Source *s, uchar *p)
155 VtEntry dir;
157 memset(s, 0, sizeof(*s));
158 if(vtentryunpack(&dir, p, 0) < 0)
159 return -1;
161 if(!(dir.flags & VtEntryActive))
162 return 0;
164 s->active = 1;
165 s->gen = dir.gen;
166 s->psize = dir.psize;
167 s->dsize = dir.dsize;
168 s->size = dir.size;
169 memmove(s->score, dir.score, VtScoreSize);
170 if((dir.type&~VtTypeDepthMask) == VtDirType)
171 s->dir = 1;
172 s->depth = dir.type&VtTypeDepthMask;
173 return 0;
176 int
177 sourceread(Source *s, ulong block, uchar *p, int n)
179 uchar *buf;
180 uchar score[VtScoreSize];
181 int i, nn, np, type;
182 int elem[VtPointerDepth];
184 buf = vtmalloc(VtMaxLumpSize);
186 memmove(score, s->score, VtScoreSize);
188 np = s->psize/VtScoreSize;
189 for(i=0; i<s->depth; i++) {
190 elem[i] = block % np;
191 block /= np;
193 assert(block == 0);
195 for(i=s->depth-1; i>=0; i--) {
196 nn = timevtread(z, score, (s->dir ? VtDirType : VtDataType)+1+i, buf, s->psize);
197 if(nn < 0){
198 fprint(2, "vtread %V %d: %r\n", score, (s->dir ? VtDirType : VtDataType)+1+i);
199 free(buf);
200 return -1;
203 if((elem[i]+1)*VtScoreSize > nn){
204 free(buf);
205 return 0;
207 memmove(score, buf + elem[i]*VtScoreSize, VtScoreSize);
210 if(s->dir)
211 type = VtDirType;
212 else
213 type = VtDataType;
215 nn = timevtread(z, score, type, p, n);
216 if(nn < 0){
217 fprint(2, "vtread %V %d: %r\n", score, type);
218 abort();
219 free(buf);
220 return -1;
223 free(buf);
224 return nn;
227 void
228 dumpfilecontents(Source *s)
230 int nb, lb, i, n;
231 uchar buf[VtMaxLumpSize];
233 nb = (s->size + s->dsize - 1)/s->dsize;
234 lb = s->size%s->dsize;
235 for(i=0; i<nb; i++) {
236 memset(buf, 0, s->dsize);
237 n = sourceread(s, i, buf, s->dsize);
238 if(n < 0) {
239 fprint(2, "could not read block: %d: %r\n", i);
240 continue;
242 if(i < nb-1)
243 Bwrite(bout, buf, s->dsize);
244 else
245 Bwrite(bout, buf, lb);
249 void
250 dumpfile(Source *s, int indent)
252 int nb, i, j, n;
253 uchar *buf;
254 uchar score[VtScoreSize];
256 buf = vtmalloc(VtMaxLumpSize);
257 nb = (s->size + s->dsize - 1)/s->dsize;
258 for(i=0; i<nb; i++) {
259 memset(buf, 0, s->dsize);
260 n = sourceread(s, i, buf, s->dsize);
261 if(n < 0) {
262 fprint(2, "could not read block: %d: %r\n", i);
263 continue;
265 for(j=0; j<indent; j++)
266 Bprint(bout, " ");
267 sha1(buf, n, score, nil);
268 Bprint(bout, "%4d: size: %ud: %V\n", i, n, score);
270 vtfree(buf);
273 int
274 dumpdir(Source *s, int indent)
276 int pb, ne, nb, i, j, n, entry;
277 Source ss;
278 uchar *buf;
280 buf = vtmalloc(VtMaxLumpSize);
281 pb = s->dsize/VtEntrySize;
282 ne = pb*(s->size/s->dsize) + (s->size%s->dsize)/VtEntrySize;
283 nb = (s->size + s->dsize - 1)/s->dsize;
284 for(i=0; i<nb; i++) {
285 memset(buf, 0, s->dsize);
286 n = sourceread(s, i, buf, s->dsize);
287 if(n < 0) {
288 fprint(2, "could not read block: %d: %r\n", i);
289 continue;
291 for(j=0; j<pb; j++) {
292 entry = i*pb + j;
293 if(entry >= ne)
294 break;
295 parse(&ss, buf + j * VtEntrySize);
297 if(!find)
298 sourceprint(&ss, indent, entry);
299 else if(memcmp(ss.score, fscore, VtScoreSize) == 0) {
300 dumpfilecontents(&ss);
301 free(buf);
302 return -1;
305 if(ss.dir) {
306 if(dumpdir(&ss, indent+1) < 0){
307 free(buf);
308 return -1;
310 } else if(all)
311 dumpfile(&ss, indent+1);
314 free(buf);
315 return 0;
318 void
319 usage(void)
321 fprint(2, "%s: [file]\n", argv0);
322 threadexits("usage");
325 void
326 readroot(VtRoot *root, uchar *score, char *file)
328 int fd;
329 char *pref;
330 char buf[VtRootSize];
331 int n, nn;
333 if(file == 0)
334 fd = 0;
335 else {
336 fd = open(file, OREAD);
337 if(fd < 0)
338 sysfatal("could not open file: %s: %r\n", file);
340 n = readn(fd, buf, sizeof(buf)-1);
341 if(n < 0)
342 sysfatal("read failed: %r\n");
343 if(n==0 || buf[n-1] != '\n')
344 sysfatal("not a root file");
345 buf[n-1] = 0;
346 close(fd);
348 if(vtparsescore(buf, &pref, score) < 0){
349 sysfatal("not a root file");
351 nn = timevtread(z, score, VtRootType, buf, VtRootSize);
352 if(nn < 0)
353 sysfatal("cannot read root %V", score);
354 if(vtrootunpack(root, buf) < 0)
355 sysfatal("cannot parse root: %r");
358 int
359 timevtread(VtConn *z, uchar *score, int type, void *buf, int nbuf)
361 /*
362 ulong t0, t1;
363 int n;
365 t0 = nsec();
366 n = vtread(z, score, type, buf, nbuf);
367 t1 = nsec();
368 fprint(2, "read %V: %.6f seconds\n", score, (t1-t0)/1.e9);
369 return n;
370 */
371 return vtread(z, score, type, buf, nbuf);