11 // XXX What to do here?
12 VtMaxLumpSize = 65535,
24 uchar zeroscore[VtScoreSize]; /* all zeros */
26 typedef struct ScoreTree ScoreTree;
30 uchar score[VtScoreSize];
38 scoretreecmp(Avl *va, Avl *vb)
46 i = memcmp(a->score, b->score, VtScoreSize);
49 return a->type - b->type;
53 havevisited(uchar score[VtScoreSize], int type)
59 memmove(a.score, score, VtScoreSize);
61 return lookupavl(scoretree, &a.avl) != nil;
65 markvisited(uchar score[VtScoreSize], int type)
72 a = binalloc(&scorebin, sizeof *a, 1);
73 memmove(a->score, score, VtScoreSize);
75 insertavl(scoretree, &a->avl, &old);
81 fprint(2, "usage: copy [-fimrVv] [-t type] srchost dsthost score\n");
82 threadexitsall("usage");
86 walk(uchar score[VtScoreSize], uint type, int base, int depth)
90 uchar nscore[VtScoreSize];
95 for(i = 0; i < depth; i++)
97 fprint(2, "-> %d %d %d %V\n", depth, type, base, score);
100 if(memcmp(score, vtzeroscore, VtScoreSize) == 0 || memcmp(score, zeroscore, VtScoreSize) == 0)
103 if(havevisited(score, type)){
108 buf = vtmallocz(VtMaxLumpSize);
109 if(fast && vtread(zdst, score, type, buf, VtMaxLumpSize) >= 0){
111 fprint(2, "skip %V\n", score);
116 n = vtread(zsrc, score, type, buf, VtMaxLumpSize);
120 memmove(score, vtzeroscore, VtScoreSize);
121 }else if(!ignoreerrors)
122 sysfatal("reading block %V (type %d): %r", score, type);
128 if(vtrootunpack(&root, buf) < 0){
129 fprint(2, "warning: could not unpack root in %V %d\n", score, type);
132 walk(root.prev, VtRootType, 0, depth+1);
133 walk(root.score, VtDirType, 0, depth+1);
135 vtrootpack(&root, buf); /* walk might have changed score */
139 for(i=0; i*VtEntrySize < n; i++){
140 if(vtentryunpack(&e, buf, i) < 0){
141 fprint(2, "warning: could not unpack entry #%d in %V %d\n", i, score, type);
144 if(!(e.flags & VtEntryActive))
146 walk(e.score, e.type, e.type&VtTypeBaseMask, depth+1);
148 * Don't repack unless we're rewriting -- some old
149 * vac files have psize==0 and dsize==0, and these
150 * get rewritten by vtentryunpack to have less strange
151 * block sizes. So vtentryunpack; vtentrypack does not
152 * guarantee to preserve the exact bytes in buf.
155 vtentrypack(&e, buf, i);
162 default: /* pointers */
163 for(i=0; i<n; i+=VtScoreSize)
164 if(memcmp(buf+i, vtzeroscore, VtScoreSize) != 0)
165 walk(buf+i, type-1, base, depth+1);
170 if(vtwrite(zdst, nscore, type, buf, n) < 0){
171 /* figure out score for better error message */
172 /* can't use input argument - might have changed contents */
173 n = vtzerotruncate(type, buf, n);
174 sha1(buf, n, score, nil);
175 sysfatal("writing block %V (type %d): %r", score, type);
177 if(!rewrite && memcmp(score, nscore, VtScoreSize) != 0)
178 sysfatal("not rewriting: wrote %V got %V", score, nscore);
180 if((type !=0 || base !=0) && verbose){
181 n = vtzerotruncate(type, buf, n);
182 sha1(buf, n, score, nil);
184 for(i = 0; i < depth; i++)
186 fprint(2, "<- %V\n", score);
189 markvisited(score, type);
194 threadmain(int argc, char *argv[])
197 uchar score[VtScoreSize];
201 fmtinstall('F', vtfcallfmt);
202 fmtinstall('V', vtscorefmt);
218 scoretree = mkavltree(scoretreecmp);
226 type = atoi(EARGF(usage()));
239 if(vtparsescore(argv[2], &prefix, score) < 0)
240 sysfatal("could not parse score: %r");
242 buf = vtmallocz(VtMaxLumpSize);
244 zsrc = vtdial(argv[0]);
246 sysfatal("could not dial src server: %r");
247 if(vtconnect(zsrc) < 0)
248 sysfatal("vtconnect src: %r");
250 zdst = vtdial(argv[1]);
252 sysfatal("could not dial dst server: %r");
253 if(vtconnect(zdst) < 0)
254 sysfatal("vtconnect dst: %r");
257 n = vtread(zsrc, score, type, buf, VtMaxLumpSize);
259 sysfatal("could not read block: %r");
261 for(type=0; type<VtMaxType; type++){
262 n = vtread(zsrc, score, type, buf, VtMaxLumpSize);
266 if(type == VtMaxType)
267 sysfatal("could not find block %V of any type", score);
270 walk(score, type, VtDirType, 0);
272 print("%s:%V (%d pointers rewritten)\n", prefix, score, changes);
275 print("%d skipped, %d written\n", nskip, nwrite);
278 sysfatal("could not sync dst server: %r");