Blob


1 #include <u.h>
2 #include <libc.h>
3 #include <venti.h>
4 #include <libsec.h>
5 #include <thread.h>
7 int changes;
8 int rewrite;
9 int ignoreerrors;
10 int fast;
11 int verbose;
12 VtConn *zsrc, *zdst;
14 void
15 usage(void)
16 {
17 fprint(2, "usage: copy [-fir] [-t type] srchost dsthost score\n");
18 threadexitsall("usage");
19 }
21 void
22 walk(uchar score[VtScoreSize], uint type, int base)
23 {
24 int i, n;
25 uchar *buf;
26 VtEntry e;
27 VtRoot root;
29 if(memcmp(score, vtzeroscore, VtScoreSize) == 0)
30 return;
32 buf = vtmallocz(VtMaxLumpSize);
33 if(fast && vtread(zdst, score, type, buf, VtMaxLumpSize) >= 0){
34 if(verbose)
35 fprint(2, "skip %V\n", score);
36 free(buf);
37 return;
38 }
40 n = vtread(zsrc, score, type, buf, VtMaxLumpSize);
41 if(n < 0){
42 if(rewrite){
43 changes++;
44 memmove(score, vtzeroscore, VtScoreSize);
45 }else if(!ignoreerrors)
46 sysfatal("reading block %V (type %d): %r", score, type);
47 return;
48 }
50 switch(type){
51 case VtRootType:
52 if(vtrootunpack(&root, buf) < 0){
53 fprint(2, "warning: could not unpack root in %V %d\n", score, type);
54 break;
55 }
56 walk(root.score, VtDirType, 0);
57 walk(root.prev, VtRootType, 0);
58 vtrootpack(&root, buf); /* walk might have changed score */
59 break;
61 case VtDirType:
62 for(i=0; i<n/VtEntrySize; i++){
63 if(vtentryunpack(&e, buf, i) < 0){
64 fprint(2, "warning: could not unpack entry #%d in %V %d\n", i, score, type);
65 continue;
66 }
67 if(!(e.flags & VtEntryActive))
68 continue;
69 walk(e.score, e.type, e.type&VtTypeBaseMask);
70 vtentrypack(&e, buf, i);
71 }
72 break;
74 case VtDataType:
75 break;
77 default: /* pointers */
78 for(i=0; i<n; i+=VtScoreSize)
79 if(memcmp(buf+i, vtzeroscore, VtScoreSize) != 0)
80 walk(buf+i, type-1, base);
81 break;
82 }
84 if(vtwrite(zdst, score, type, buf, n) < 0){
85 /* figure out score for better error message */
86 /* can't use input argument - might have changed contents */
87 n = vtzerotruncate(type, buf, n);
88 sha1(buf, n, score, nil);
89 sysfatal("writing block %V (type %d): %r", score, type);
90 }
91 free(buf);
92 }
94 void
95 threadmain(int argc, char *argv[])
96 {
97 int type, n;
98 uchar score[VtScoreSize];
99 uchar *buf;
100 char *prefix;
102 fmtinstall('F', vtfcallfmt);
103 fmtinstall('V', vtscorefmt);
105 type = -1;
106 ARGBEGIN{
107 case 'f':
108 fast = 1;
109 break;
110 case 'i':
111 if(rewrite)
112 usage();
113 ignoreerrors = 1;
114 break;
115 case 'r':
116 if(ignoreerrors)
117 usage();
118 rewrite = 1;
119 break;
120 case 't':
121 type = atoi(EARGF(usage()));
122 break;
123 default:
124 usage();
125 break;
126 }ARGEND
128 if(argc != 3)
129 usage();
131 if(vtparsescore(argv[2], &prefix, score) < 0)
132 sysfatal("could not parse score: %r");
134 buf = vtmallocz(VtMaxLumpSize);
136 zsrc = vtdial(argv[0]);
137 if(zsrc == nil)
138 sysfatal("could not dial src server: %r");
139 if(vtconnect(zsrc) < 0)
140 sysfatal("vtconnect src: %r");
142 zdst = vtdial(argv[1]);
143 if(zdst == nil)
144 sysfatal("could not dial dst server: %r");
145 if(vtconnect(zdst) < 0)
146 sysfatal("vtconnect dst: %r");
148 if(type != -1){
149 n = vtread(zsrc, score, type, buf, VtMaxLumpSize);
150 if(n < 0)
151 sysfatal("could not read block: %r");
152 }else{
153 for(type=0; type<VtMaxType; type++){
154 n = vtread(zsrc, score, type, buf, VtMaxLumpSize);
155 if(n >= 0)
156 break;
158 if(type == VtMaxType)
159 sysfatal("could not find block %V of any type", score);
162 walk(score, type, VtDirType);
163 if(changes)
164 print("%s:%V (%d pointers rewritten)\n", prefix, score, changes);
166 if(vtsync(zdst) < 0)
167 sysfatal("could not sync dst server: %r");
169 threadexitsall(0);