#include "stdinc.h" #include "dat.h" #include "fns.h" int fast; VtConn *zsrc, *zdst; void usage(void) { fprint(2, "usage: copy src-host dst-host score [type]\n"); threadexitsall("usage"); } int parsescore(uchar *score, char *buf, int n) { int i, c; memset(score, 0, VtScoreSize); if(n < VtScoreSize*2) return -1; 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 -1; } if((i & 1) == 0) c <<= 4; score[i>>1] |= c; } return 0; } void walk(uchar score[VtScoreSize], uint type, int base) { int i, n, sub; uchar *buf; VtEntry e; VtRoot root; if(memcmp(score, vtzeroscore, VtScoreSize) == 0) return; buf = vtmallocz(VtMaxLumpSize); if(fast && vtread(zdst, score, type, buf, VtMaxLumpSize) >= 0){ fprint(2, "skip %V\n", score); free(buf); return; } n = vtread(zsrc, score, type, buf, VtMaxLumpSize); if(n < 0){ fprint(2, "warning: could not read block %V %d: %r", score, type); return; } switch(type){ case VtRootType: if(vtrootunpack(&root, buf) < 0){ fprint(2, "warning: could not unpack root in %V %d\n", score, type); break; } walk(root.score, VtDirType, 0); walk(root.prev, VtRootType, 0); break; case VtDirType: for(i=0; i<n/VtEntrySize; i++){ if(vtentryunpack(&e, buf, i) < 0){ fprint(2, "warning: could not unpack entry #%d in %V %d\n", i, score, type); continue; } if(!(e.flags & VtEntryActive)) continue; if(e.flags&VtEntryDir) base = VtDirType; else base = VtDataType; sub = base | ((e.flags&VtEntryDepthMask)>>VtEntryDepthShift); walk(e.score, sub, base); } break; case VtDataType: break; default: /* pointers */ for(i=0; i<n; i+=VtScoreSize) if(memcmp(buf+i, vtzeroscore, VtScoreSize) != 0) walk(buf+i, type-1, base); break; } if(vtwrite(zdst, score, type, buf, n) < 0) fprint(2, "warning: could not write block %V %d: %r", score, type); free(buf); } void threadmain(int argc, char *argv[]) { int type, n; uchar score[VtScoreSize]; uchar *buf; ARGBEGIN{ case 'f': fast = 1; break; default: usage(); break; }ARGEND if(argc != 3 && argc != 4) usage(); fmtinstall('V', vtscorefmt); if(parsescore(score, argv[2], strlen(argv[2]) < 0)) sysfatal("could not parse score: %r"); buf = vtmallocz(VtMaxLumpSize); zsrc = vtdial(argv[0]); if(zsrc == nil) sysfatal("could not dial src server: %r"); if(vtconnect(zsrc) < 0) sysfatal("vtconnect src: %r"); zdst = vtdial(argv[1]); if(zdst == nil) sysfatal("could not dial dst server: %r"); if(vtconnect(zdst) < 0) sysfatal("vtconnect dst: %r"); if(argc == 4){ type = atoi(argv[3]); n = vtread(zsrc, score, type, buf, VtMaxLumpSize); if(n < 0) sysfatal("could not read block: %r"); }else{ for(type=0; type<VtMaxType; type++){ n = vtread(zsrc, score, type, buf, VtMaxLumpSize); if(n >= 0) break; } if(type == VtMaxType) sysfatal("could not find block %V of any type", score); } walk(score, type, VtDirType); if(vtsync(zdst) < 0) sysfatal("could not sync dst server: %r"); threadexitsall(0); }