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);
36 void
37 threadmain(int argc, char *argv[])
38 {
39 char *host = nil, *pref;
40 uchar score[VtScoreSize];
41 Source source;
42 uchar buf[VtMaxLumpSize];
43 char *p;
44 int n;
46 ARGBEGIN{
47 case 'h':
48 host = ARGF();
49 break;
50 case 'c':
51 cmp++;
52 break;
53 case 'f':
54 find++;
55 p = ARGF();
56 if(p == nil || vtparsescore(p, &pref, fscore) < 0 || !pref || strcmp(pref, "vac") != 0)
57 usage();
58 break;
59 case 'a':
60 all = 1;
61 break;
62 }ARGEND
64 bout = vtmallocz(sizeof(Biobuf));
65 Binit(bout, 1, OWRITE);
67 if(argc > 1)
68 usage();
70 fmtinstall('V', vtscorefmt);
71 fmtinstall('H', encodefmt);
73 z = vtdial(host);
74 if(z == nil)
75 sysfatal("could not connect to server: %r");
77 if(vtconnect(z) < 0)
78 sysfatal("vtconnect: %r");
80 readroot(&root, score, argv[0]);
81 bsize = root.blocksize;
82 if(!find) {
83 Bprint(bout, "score: %V\n", score);
84 Bprint(bout, "name: %s\n", root.name);
85 Bprint(bout, "type: %s\n", root.type);
86 Bprint(bout, "bsize: %d\n", bsize);
87 Bprint(bout, "prev: %V\n", root.prev);
88 }
90 n = vtread(z, root.score, VtDirType, buf, bsize);
91 if(n < 0)
92 sysfatal("could not read root dir");
94 /* fake up top level source */
95 memset(&source, 0, sizeof(source));
96 memmove(source.score, root.score, VtScoreSize);
97 source.psize = bsize;
98 source.dsize = bsize;
99 source.dir = 1;
100 source.active = 1;
101 source.depth = 0;
102 source.size = n;
104 dumpdir(&source, 0);
106 Bterm(bout);
108 vthangup(z);
109 threadexitsall(0);
112 void
113 sourceprint(Source *s, int indent, int entry)
115 int i;
116 uvlong size;
117 int ne;
119 for(i=0; i<indent; i++)
120 Bprint(bout, " ");
121 Bprint(bout, "%4d", entry);
122 if(s->active) {
123 /* dir size in directory entries */
124 if(s->dir) {
125 ne = s->dsize/VtEntrySize;
126 size = ne*(s->size/s->dsize) + (s->size%s->dsize)/VtEntrySize;
127 } else
128 size = s->size;
129 if(cmp) {
130 Bprint(bout, ": gen: %lud size: %llud",
131 s->gen, size);
132 if(!s->dir)
133 Bprint(bout, ": %V", s->score);
134 } else {
135 Bprint(bout, ": gen: %lud psize: %d dsize: %d",
136 s->gen, s->psize, s->dsize);
137 Bprint(bout, " depth: %d size: %llud: %V",
138 s->depth, size, s->score);
141 if(s->reserved)
142 Bprint(bout, ": reserved not emtpy");
144 Bprint(bout, "\n");
147 int
148 parse(Source *s, uchar *p)
150 VtEntry dir;
152 memset(s, 0, sizeof(*s));
153 if(vtentryunpack(&dir, p, 0) < 0)
154 return -1;
156 if(!(dir.flags & VtEntryActive))
157 return 0;
159 s->active = 1;
160 s->gen = dir.gen;
161 s->psize = dir.psize;
162 s->dsize = dir.size;
163 s->size = dir.size;
164 memmove(s->score, dir.score, VtScoreSize);
165 if((dir.type&~VtTypeDepthMask) == VtDirType)
166 s->dir = 1;
167 fprint(2, "sdir %d type %d %.*H\n", s->dir, dir.type, VtEntrySize, p);
168 s->depth = dir.type&VtTypeDepthMask;
169 return 0;
172 int
173 sourceread(Source *s, ulong block, uchar *p, int n)
175 uchar *buf;
176 uchar score[VtScoreSize];
177 int i, nn, np, type;
178 int elem[VtPointerDepth];
180 buf = vtmalloc(VtMaxLumpSize);
182 memmove(score, s->score, VtScoreSize);
184 np = s->psize/VtScoreSize;
185 for(i=0; i<s->depth; i++) {
186 elem[i] = block % np;
187 block /= np;
189 assert(block == 0);
191 for(i=s->depth-1; i>=0; i--) {
192 nn = vtread(z, score, (s->dir ? VtDirType : VtDataType)+1+i, buf, s->psize);
193 if(nn < 0){
194 fprint(2, "vtread %V %d: %r\n", score, (s->dir ? VtDirType : VtDataType)+1+i);
195 free(buf);
196 return -1;
199 if((elem[i]+1)*VtScoreSize > nn){
200 free(buf);
201 return 0;
203 memmove(score, buf + elem[i]*VtScoreSize, VtScoreSize);
206 if(s->dir)
207 type = VtDirType;
208 else
209 type = VtDataType;
211 nn = vtread(z, score, type, p, n);
212 if(nn < 0){
213 fprint(2, "vtread %V %d: %r\n", score, type);
214 abort();
215 free(buf);
216 return -1;
219 free(buf);
220 return nn;
223 void
224 dumpfilecontents(Source *s)
226 int nb, lb, i, n;
227 uchar buf[VtMaxLumpSize];
229 nb = (s->size + s->dsize - 1)/s->dsize;
230 lb = s->size%s->dsize;
231 for(i=0; i<nb; i++) {
232 memset(buf, 0, s->dsize);
233 n = sourceread(s, i, buf, s->dsize);
234 if(n < 0) {
235 fprint(2, "could not read block: %d: %r\n", i);
236 continue;
238 if(i < nb-1)
239 Bwrite(bout, buf, s->dsize);
240 else
241 Bwrite(bout, buf, lb);
245 void
246 dumpfile(Source *s, int indent)
248 int nb, i, j, n;
249 uchar *buf;
250 uchar score[VtScoreSize];
252 buf = vtmalloc(VtMaxLumpSize);
253 nb = (s->size + s->dsize - 1)/s->dsize;
254 for(i=0; i<nb; i++) {
255 memset(buf, 0, s->dsize);
256 n = sourceread(s, i, buf, s->dsize);
257 if(n < 0) {
258 fprint(2, "could not read block: %d: %r\n", i);
259 continue;
261 for(j=0; j<indent; j++)
262 Bprint(bout, " ");
263 sha1(buf, n, score, nil);
264 Bprint(bout, "%4d: size: %ud: %V\n", i, n, score);
266 vtfree(buf);
269 int
270 dumpdir(Source *s, int indent)
272 int pb, ne, nb, i, j, n, entry;
273 Source ss;
274 uchar *buf;
276 buf = vtmalloc(VtMaxLumpSize);
277 pb = s->dsize/VtEntrySize;
278 ne = pb*(s->size/s->dsize) + (s->size%s->dsize)/VtEntrySize;
279 nb = (s->size + s->dsize - 1)/s->dsize;
280 for(i=0; i<nb; i++) {
281 memset(buf, 0, s->dsize);
282 n = sourceread(s, i, buf, s->dsize);
283 if(n < 0) {
284 fprint(2, "could not read block: %d: %r\n", i);
285 continue;
287 for(j=0; j<pb; j++) {
288 entry = i*pb + j;
289 if(entry >= ne)
290 break;
291 parse(&ss, buf + j * VtEntrySize);
293 if(!find)
294 sourceprint(&ss, indent, entry);
295 else if(memcmp(ss.score, fscore, VtScoreSize) == 0) {
296 dumpfilecontents(&ss);
297 free(buf);
298 return -1;
301 if(ss.dir) {
302 if(dumpdir(&ss, indent+1) < 0){
303 free(buf);
304 return -1;
306 } else if(all)
307 dumpfile(&ss, indent+1);
310 free(buf);
311 return 0;
314 void
315 usage(void)
317 fprint(2, "%s: [file]\n", argv0);
318 threadexits("usage");
321 void
322 readroot(VtRoot *root, uchar *score, char *file)
324 int fd;
325 char *pref;
326 char buf[VtRootSize];
327 int n, nn;
329 if(file == 0)
330 fd = 0;
331 else {
332 fd = open(file, OREAD);
333 if(fd < 0)
334 sysfatal("could not open file: %s: %r\n", file);
336 n = readn(fd, buf, sizeof(buf)-1);
337 if(n < 0)
338 sysfatal("read failed: %r\n");
339 if(n==0 || buf[n-1] != '\n')
340 sysfatal("not a root file");
341 buf[n-1] = 0;
342 close(fd);
344 if(vtparsescore(buf, &pref, score) < 0){
345 sysfatal("not a root file");
347 nn = vtread(z, score, VtRootType, buf, VtRootSize);
348 if(nn < 0)
349 sysfatal("cannot read root %V", score);
350 if(vtrootunpack(root, buf) < 0)
351 sysfatal("cannot parse root: %r");