xref: /plan9/sys/src/cmd/venti/copy.c (revision 8ffb2bee45f0e1631dbb22b8d323212fb603680f)
1368c31abSDavid du Colombier #include <u.h>
2368c31abSDavid du Colombier #include <libc.h>
3368c31abSDavid du Colombier #include <venti.h>
4368c31abSDavid du Colombier #include <libsec.h>
5368c31abSDavid du Colombier #include <avl.h>
6368c31abSDavid du Colombier #include <bin.h>
76a9fc400SDavid du Colombier 
8368c31abSDavid du Colombier int changes;
9368c31abSDavid du Colombier int rewrite;
10368c31abSDavid du Colombier int ignoreerrors;
11368c31abSDavid du Colombier int fast;
12368c31abSDavid du Colombier int verbose;
13368c31abSDavid du Colombier int nskip;
14368c31abSDavid du Colombier int nwrite;
156a9fc400SDavid du Colombier 
16368c31abSDavid du Colombier VtConn *zsrc, *zdst;
17368c31abSDavid du Colombier uchar zeroscore[VtScoreSize];	/* all zeros */
18368c31abSDavid du Colombier 
19368c31abSDavid du Colombier typedef struct ScoreTree ScoreTree;
20368c31abSDavid du Colombier struct ScoreTree
21368c31abSDavid du Colombier {
22368c31abSDavid du Colombier 	Avl avl;
23368c31abSDavid du Colombier 	uchar score[VtScoreSize];
24368c31abSDavid du Colombier 	int type;
25368c31abSDavid du Colombier };
26368c31abSDavid du Colombier 
27368c31abSDavid du Colombier Avltree *scoretree;
28368c31abSDavid du Colombier Bin *scorebin;
29368c31abSDavid du Colombier 
30368c31abSDavid du Colombier static int
scoretreecmp(Avl * va,Avl * vb)31368c31abSDavid du Colombier scoretreecmp(Avl *va, Avl *vb)
32368c31abSDavid du Colombier {
33368c31abSDavid du Colombier 	ScoreTree *a, *b;
34368c31abSDavid du Colombier 	int i;
35368c31abSDavid du Colombier 
36368c31abSDavid du Colombier 	a = (ScoreTree*)va;
37368c31abSDavid du Colombier 	b = (ScoreTree*)vb;
38368c31abSDavid du Colombier 
39368c31abSDavid du Colombier 	i = memcmp(a->score, b->score, VtScoreSize);
40368c31abSDavid du Colombier 	if(i != 0)
41368c31abSDavid du Colombier 		return i;
42368c31abSDavid du Colombier 	return a->type - b->type;
43368c31abSDavid du Colombier }
44368c31abSDavid du Colombier 
45368c31abSDavid du Colombier static int
havevisited(uchar score[VtScoreSize],int type)46368c31abSDavid du Colombier havevisited(uchar score[VtScoreSize], int type)
47368c31abSDavid du Colombier {
48368c31abSDavid du Colombier 	ScoreTree a;
49368c31abSDavid du Colombier 
50368c31abSDavid du Colombier 	if(scoretree == nil)
51368c31abSDavid du Colombier 		return 0;
52368c31abSDavid du Colombier 	memmove(a.score, score, VtScoreSize);
53368c31abSDavid du Colombier 	a.type = type;
54368c31abSDavid du Colombier 	return lookupavl(scoretree, &a.avl) != nil;
55368c31abSDavid du Colombier }
56368c31abSDavid du Colombier 
57368c31abSDavid du Colombier static void
markvisited(uchar score[VtScoreSize],int type)58368c31abSDavid du Colombier markvisited(uchar score[VtScoreSize], int type)
59368c31abSDavid du Colombier {
60368c31abSDavid du Colombier 	ScoreTree *a;
61368c31abSDavid du Colombier 	Avl *old;
62368c31abSDavid du Colombier 
63368c31abSDavid du Colombier 	if(scoretree == nil)
64368c31abSDavid du Colombier 		return;
65368c31abSDavid du Colombier 	a = binalloc(&scorebin, sizeof *a, 1);
66368c31abSDavid du Colombier 	memmove(a->score, score, VtScoreSize);
67368c31abSDavid du Colombier 	a->type = type;
68368c31abSDavid du Colombier 	insertavl(scoretree, &a->avl, &old);
69368c31abSDavid du Colombier }
706a9fc400SDavid du Colombier 
716a9fc400SDavid du Colombier void
usage(void)726a9fc400SDavid du Colombier usage(void)
736a9fc400SDavid du Colombier {
74431b537fSDavid du Colombier 	fprint(2, "usage: %s [-fimrv] [-t type] srchost dsthost score\n", argv0);
756a9fc400SDavid du Colombier 	exits("usage");
766a9fc400SDavid du Colombier }
776a9fc400SDavid du Colombier 
786a9fc400SDavid du Colombier void
walk(uchar score[VtScoreSize],uint type,int base)796a9fc400SDavid du Colombier walk(uchar score[VtScoreSize], uint type, int base)
806a9fc400SDavid du Colombier {
81368c31abSDavid du Colombier 	int i, n;
826a9fc400SDavid du Colombier 	uchar *buf;
83368c31abSDavid du Colombier 	uchar nscore[VtScoreSize];
846a9fc400SDavid du Colombier 	VtEntry e;
856a9fc400SDavid du Colombier 	VtRoot root;
866a9fc400SDavid du Colombier 
87368c31abSDavid du Colombier 	if(memcmp(score, vtzeroscore, VtScoreSize) == 0 || memcmp(score, zeroscore, VtScoreSize) == 0)
886a9fc400SDavid du Colombier 		return;
896a9fc400SDavid du Colombier 
90368c31abSDavid du Colombier 	if(havevisited(score, type)){
91368c31abSDavid du Colombier 		nskip++;
92368c31abSDavid du Colombier 		return;
93368c31abSDavid du Colombier 	}
94368c31abSDavid du Colombier 
95368c31abSDavid du Colombier 	buf = vtmallocz(VtMaxLumpSize);
96368c31abSDavid du Colombier 	if(fast && vtread(zdst, score, type, buf, VtMaxLumpSize) >= 0){
97368c31abSDavid du Colombier 		if(verbose)
98368c31abSDavid du Colombier 			fprint(2, "skip %V\n", score);
996a9fc400SDavid du Colombier 		free(buf);
1006a9fc400SDavid du Colombier 		return;
1016a9fc400SDavid du Colombier 	}
1026a9fc400SDavid du Colombier 
103368c31abSDavid du Colombier 	n = vtread(zsrc, score, type, buf, VtMaxLumpSize);
1046a9fc400SDavid du Colombier 	if(n < 0){
105368c31abSDavid du Colombier 		if(rewrite){
106368c31abSDavid du Colombier 			changes++;
107368c31abSDavid du Colombier 			memmove(score, vtzeroscore, VtScoreSize);
108368c31abSDavid du Colombier 		}else if(!ignoreerrors)
109368c31abSDavid du Colombier 			sysfatal("reading block %V (type %d): %r", score, type);
1106a9fc400SDavid du Colombier 		return;
1116a9fc400SDavid du Colombier 	}
1126a9fc400SDavid du Colombier 
1136a9fc400SDavid du Colombier 	switch(type){
1146a9fc400SDavid du Colombier 	case VtRootType:
115368c31abSDavid du Colombier 		if(vtrootunpack(&root, buf) < 0){
1166a9fc400SDavid du Colombier 			fprint(2, "warning: could not unpack root in %V %d\n", score, type);
1176a9fc400SDavid du Colombier 			break;
1186a9fc400SDavid du Colombier 		}
1196a9fc400SDavid du Colombier 		walk(root.prev, VtRootType, 0);
120368c31abSDavid du Colombier 		walk(root.score, VtDirType, 0);
121368c31abSDavid du Colombier 		if(rewrite)
122368c31abSDavid du Colombier 			vtrootpack(&root, buf);	/* walk might have changed score */
1236a9fc400SDavid du Colombier 		break;
1246a9fc400SDavid du Colombier 
1256a9fc400SDavid du Colombier 	case VtDirType:
126*8ffb2beeSDavid du Colombier 		for(i=0; i*VtEntrySize<n; i++){
127368c31abSDavid du Colombier 			if(vtentryunpack(&e, buf, i) < 0){
1286a9fc400SDavid du Colombier 				fprint(2, "warning: could not unpack entry #%d in %V %d\n", i, score, type);
1296a9fc400SDavid du Colombier 				continue;
1306a9fc400SDavid du Colombier 			}
1316a9fc400SDavid du Colombier 			if(!(e.flags & VtEntryActive))
1326a9fc400SDavid du Colombier 				continue;
133368c31abSDavid du Colombier 			walk(e.score, e.type, e.type&VtTypeBaseMask);
134368c31abSDavid du Colombier 			/*
135368c31abSDavid du Colombier 			 * Don't repack unless we're rewriting -- some old
136368c31abSDavid du Colombier 			 * vac files have psize==0 and dsize==0, and these
137368c31abSDavid du Colombier 			 * get rewritten by vtentryunpack to have less strange
138368c31abSDavid du Colombier 			 * block sizes.  So vtentryunpack; vtentrypack does not
139368c31abSDavid du Colombier 			 * guarantee to preserve the exact bytes in buf.
140368c31abSDavid du Colombier 			 */
141368c31abSDavid du Colombier 			if(rewrite)
142368c31abSDavid du Colombier 				vtentrypack(&e, buf, i);
1436a9fc400SDavid du Colombier 		}
1446a9fc400SDavid du Colombier 		break;
1456a9fc400SDavid du Colombier 
1466a9fc400SDavid du Colombier 	case VtDataType:
1476a9fc400SDavid du Colombier 		break;
1486a9fc400SDavid du Colombier 
1496a9fc400SDavid du Colombier 	default:	/* pointers */
1506a9fc400SDavid du Colombier 		for(i=0; i<n; i+=VtScoreSize)
151368c31abSDavid du Colombier 			if(memcmp(buf+i, vtzeroscore, VtScoreSize) != 0)
152368c31abSDavid du Colombier 				walk(buf+i, type-1, base);
1536a9fc400SDavid du Colombier 		break;
1546a9fc400SDavid du Colombier 	}
1556a9fc400SDavid du Colombier 
156368c31abSDavid du Colombier 	nwrite++;
157368c31abSDavid du Colombier 	if(vtwrite(zdst, nscore, type, buf, n) < 0){
158368c31abSDavid du Colombier 		/* figure out score for better error message */
159368c31abSDavid du Colombier 		/* can't use input argument - might have changed contents */
160368c31abSDavid du Colombier 		n = vtzerotruncate(type, buf, n);
161368c31abSDavid du Colombier 		sha1(buf, n, score, nil);
162368c31abSDavid du Colombier 		sysfatal("writing block %V (type %d): %r", score, type);
163368c31abSDavid du Colombier 	}
164368c31abSDavid du Colombier 	if(!rewrite && memcmp(score, nscore, VtScoreSize) != 0){
165368c31abSDavid du Colombier 		fprint(2, "not rewriting: wrote %V got %V\n", score, nscore);
166368c31abSDavid du Colombier 		abort();
167368c31abSDavid du Colombier 		sysfatal("not rewriting: wrote %V got %V", score, nscore);
168368c31abSDavid du Colombier 	}
169368c31abSDavid du Colombier 
170368c31abSDavid du Colombier 	markvisited(score, type);
1716a9fc400SDavid du Colombier 	free(buf);
1726a9fc400SDavid du Colombier }
1736a9fc400SDavid du Colombier 
1740aa8dc3cSDavid du Colombier void
main(int argc,char * argv[])1756a9fc400SDavid du Colombier main(int argc, char *argv[])
1766a9fc400SDavid du Colombier {
1776a9fc400SDavid du Colombier 	int type, n;
1786a9fc400SDavid du Colombier 	uchar score[VtScoreSize];
1796a9fc400SDavid du Colombier 	uchar *buf;
180368c31abSDavid du Colombier 	char *prefix;
1816a9fc400SDavid du Colombier 
182368c31abSDavid du Colombier 	fmtinstall('F', vtfcallfmt);
183368c31abSDavid du Colombier 	fmtinstall('V', vtscorefmt);
184368c31abSDavid du Colombier 
185368c31abSDavid du Colombier 	type = -1;
1866a9fc400SDavid du Colombier 	ARGBEGIN{
187368c31abSDavid du Colombier 	case 'V':
188368c31abSDavid du Colombier 		chattyventi++;
189368c31abSDavid du Colombier 		break;
1906a9fc400SDavid du Colombier 	case 'f':
1916a9fc400SDavid du Colombier 		fast = 1;
1926a9fc400SDavid du Colombier 		break;
193368c31abSDavid du Colombier 	case 'i':
194368c31abSDavid du Colombier 		if(rewrite)
195368c31abSDavid du Colombier 			usage();
196368c31abSDavid du Colombier 		ignoreerrors = 1;
197368c31abSDavid du Colombier 		break;
198368c31abSDavid du Colombier 	case 'm':
199368c31abSDavid du Colombier 		scoretree = mkavltree(scoretreecmp);
200368c31abSDavid du Colombier 		break;
201368c31abSDavid du Colombier 	case 'r':
202368c31abSDavid du Colombier 		if(ignoreerrors)
203368c31abSDavid du Colombier 			usage();
204368c31abSDavid du Colombier 		rewrite = 1;
205368c31abSDavid du Colombier 		break;
206368c31abSDavid du Colombier 	case 't':
207368c31abSDavid du Colombier 		type = atoi(EARGF(usage()));
208368c31abSDavid du Colombier 		break;
209368c31abSDavid du Colombier 	case 'v':
210368c31abSDavid du Colombier 		verbose = 1;
211dc5a79c1SDavid du Colombier 		break;
2126a9fc400SDavid du Colombier 	default:
2136a9fc400SDavid du Colombier 		usage();
2146a9fc400SDavid du Colombier 		break;
2156a9fc400SDavid du Colombier 	}ARGEND
2166a9fc400SDavid du Colombier 
217368c31abSDavid du Colombier 	if(argc != 3)
2186a9fc400SDavid du Colombier 		usage();
2196a9fc400SDavid du Colombier 
220368c31abSDavid du Colombier 	if(vtparsescore(argv[2], &prefix, score) < 0)
221368c31abSDavid du Colombier 		sysfatal("could not parse score: %r");
2226a9fc400SDavid du Colombier 
223368c31abSDavid du Colombier 	buf = vtmallocz(VtMaxLumpSize);
2246a9fc400SDavid du Colombier 
225368c31abSDavid du Colombier 	zsrc = vtdial(argv[0]);
2266a9fc400SDavid du Colombier 	if(zsrc == nil)
227368c31abSDavid du Colombier 		sysfatal("could not dial src server: %r");
228368c31abSDavid du Colombier 	if(vtconnect(zsrc) < 0)
229368c31abSDavid du Colombier 		sysfatal("vtconnect src: %r");
2306a9fc400SDavid du Colombier 
231368c31abSDavid du Colombier 	zdst = vtdial(argv[1]);
2326a9fc400SDavid du Colombier 	if(zdst == nil)
233368c31abSDavid du Colombier 		sysfatal("could not dial dst server: %r");
234368c31abSDavid du Colombier 	if(vtconnect(zdst) < 0)
235368c31abSDavid du Colombier 		sysfatal("vtconnect dst: %r");
2366a9fc400SDavid du Colombier 
237368c31abSDavid du Colombier 	if(type != -1){
238368c31abSDavid du Colombier 		n = vtread(zsrc, score, type, buf, VtMaxLumpSize);
2396a9fc400SDavid du Colombier 		if(n < 0)
240368c31abSDavid du Colombier 			sysfatal("could not read block: %r");
2416a9fc400SDavid du Colombier 	}else{
2426a9fc400SDavid du Colombier 		for(type=0; type<VtMaxType; type++){
243368c31abSDavid du Colombier 			n = vtread(zsrc, score, type, buf, VtMaxLumpSize);
2446a9fc400SDavid du Colombier 			if(n >= 0)
2456a9fc400SDavid du Colombier 				break;
2466a9fc400SDavid du Colombier 		}
2476a9fc400SDavid du Colombier 		if(type == VtMaxType)
248368c31abSDavid du Colombier 			sysfatal("could not find block %V of any type", score);
2496a9fc400SDavid du Colombier 	}
2506a9fc400SDavid du Colombier 
2516a9fc400SDavid du Colombier 	walk(score, type, VtDirType);
252368c31abSDavid du Colombier 	if(changes)
253368c31abSDavid du Colombier 		print("%s:%V (%d pointers rewritten)\n", prefix, score, changes);
2546a9fc400SDavid du Colombier 
255368c31abSDavid du Colombier 	if(verbose)
256368c31abSDavid du Colombier 		print("%d skipped, %d written\n", nskip, nwrite);
2576a9fc400SDavid du Colombier 
258368c31abSDavid du Colombier 	if(vtsync(zdst) < 0)
259368c31abSDavid du Colombier 		sysfatal("could not sync dst server: %r");
260368c31abSDavid du Colombier 
2616a9fc400SDavid du Colombier 	exits(0);
2626a9fc400SDavid du Colombier }
263