123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262 |
- #include <u.h>
- #include <libc.h>
- #include <venti.h>
- #include <libsec.h>
- #include <avl.h>
- #include <bin.h>
- int changes;
- int rewrite;
- int ignoreerrors;
- int fast;
- int verbose;
- int nskip;
- int nwrite;
- VtConn *zsrc, *zdst;
- uchar zeroscore[VtScoreSize]; /* all zeros */
- typedef struct ScoreTree ScoreTree;
- struct ScoreTree
- {
- Avl avl;
- uchar score[VtScoreSize];
- int type;
- };
- Avltree *scoretree;
- Bin *scorebin;
- static int
- scoretreecmp(Avl *va, Avl *vb)
- {
- ScoreTree *a, *b;
- int i;
- a = (ScoreTree*)va;
- b = (ScoreTree*)vb;
- i = memcmp(a->score, b->score, VtScoreSize);
- if(i != 0)
- return i;
- return a->type - b->type;
- }
- static int
- havevisited(uchar score[VtScoreSize], int type)
- {
- ScoreTree a;
-
- if(scoretree == nil)
- return 0;
- memmove(a.score, score, VtScoreSize);
- a.type = type;
- return lookupavl(scoretree, &a.avl) != nil;
- }
- static void
- markvisited(uchar score[VtScoreSize], int type)
- {
- ScoreTree *a;
- Avl *old;
- if(scoretree == nil)
- return;
- a = binalloc(&scorebin, sizeof *a, 1);
- memmove(a->score, score, VtScoreSize);
- a->type = type;
- insertavl(scoretree, &a->avl, &old);
- }
- void
- usage(void)
- {
- fprint(2, "usage: %s [-fimrv] [-t type] srchost dsthost score\n", argv0);
- exits("usage");
- }
- void
- walk(uchar score[VtScoreSize], uint type, int base)
- {
- int i, n;
- uchar *buf;
- uchar nscore[VtScoreSize];
- VtEntry e;
- VtRoot root;
- if(memcmp(score, vtzeroscore, VtScoreSize) == 0 || memcmp(score, zeroscore, VtScoreSize) == 0)
- return;
-
- if(havevisited(score, type)){
- nskip++;
- return;
- }
- buf = vtmallocz(VtMaxLumpSize);
- if(fast && vtread(zdst, score, type, buf, VtMaxLumpSize) >= 0){
- if(verbose)
- fprint(2, "skip %V\n", score);
- free(buf);
- return;
- }
- n = vtread(zsrc, score, type, buf, VtMaxLumpSize);
- if(n < 0){
- if(rewrite){
- changes++;
- memmove(score, vtzeroscore, VtScoreSize);
- }else if(!ignoreerrors)
- sysfatal("reading block %V (type %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.prev, VtRootType, 0);
- walk(root.score, VtDirType, 0);
- if(rewrite)
- vtrootpack(&root, buf); /* walk might have changed score */
- 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;
- walk(e.score, e.type, e.type&VtTypeBaseMask);
- /*
- * Don't repack unless we're rewriting -- some old
- * vac files have psize==0 and dsize==0, and these
- * get rewritten by vtentryunpack to have less strange
- * block sizes. So vtentryunpack; vtentrypack does not
- * guarantee to preserve the exact bytes in buf.
- */
- if(rewrite)
- vtentrypack(&e, buf, i);
- }
- 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;
- }
- nwrite++;
- if(vtwrite(zdst, nscore, type, buf, n) < 0){
- /* figure out score for better error message */
- /* can't use input argument - might have changed contents */
- n = vtzerotruncate(type, buf, n);
- sha1(buf, n, score, nil);
- sysfatal("writing block %V (type %d): %r", score, type);
- }
- if(!rewrite && memcmp(score, nscore, VtScoreSize) != 0){
- fprint(2, "not rewriting: wrote %V got %V\n", score, nscore);
- abort();
- sysfatal("not rewriting: wrote %V got %V", score, nscore);
- }
-
- markvisited(score, type);
- free(buf);
- }
- void
- main(int argc, char *argv[])
- {
- int type, n;
- uchar score[VtScoreSize];
- uchar *buf;
- char *prefix;
- fmtinstall('F', vtfcallfmt);
- fmtinstall('V', vtscorefmt);
- type = -1;
- ARGBEGIN{
- case 'V':
- chattyventi++;
- break;
- case 'f':
- fast = 1;
- break;
- case 'i':
- if(rewrite)
- usage();
- ignoreerrors = 1;
- break;
- case 'm':
- scoretree = mkavltree(scoretreecmp);
- break;
- case 'r':
- if(ignoreerrors)
- usage();
- rewrite = 1;
- break;
- case 't':
- type = atoi(EARGF(usage()));
- break;
- case 'v':
- verbose = 1;
- break;
- default:
- usage();
- break;
- }ARGEND
- if(argc != 3)
- usage();
- if(vtparsescore(argv[2], &prefix, score) < 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(type != -1){
- 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(changes)
- print("%s:%V (%d pointers rewritten)\n", prefix, score, changes);
- if(verbose)
- print("%d skipped, %d written\n", nskip, nwrite);
- if(vtsync(zdst) < 0)
- sysfatal("could not sync dst server: %r");
- exits(0);
- }
|