Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include <u.h>
2
#include <libc.h>
3
#include <venti.h>
4
#include <libsec.h>
5
#include <avl.h>
6
#include <bin.h>
7
 
8
int changes;
9
int rewrite;
10
int ignoreerrors;
11
int fast;
12
int verbose;
13
int nskip;
14
int nwrite;
15
 
16
VtConn *zsrc, *zdst;
17
uchar zeroscore[VtScoreSize];	/* all zeros */
18
 
19
typedef struct ScoreTree ScoreTree;
20
struct ScoreTree
21
{
22
	Avl avl;
23
	uchar score[VtScoreSize];
24
	int type;
25
};
26
 
27
Avltree *scoretree;
28
Bin *scorebin;
29
 
30
static int
31
scoretreecmp(Avl *va, Avl *vb)
32
{
33
	ScoreTree *a, *b;
34
	int i;
35
 
36
	a = (ScoreTree*)va;
37
	b = (ScoreTree*)vb;
38
 
39
	i = memcmp(a->score, b->score, VtScoreSize);
40
	if(i != 0)
41
		return i;
42
	return a->type - b->type;
43
}
44
 
45
static int
46
havevisited(uchar score[VtScoreSize], int type)
47
{
48
	ScoreTree a;
49
 
50
	if(scoretree == nil)
51
		return 0;
52
	memmove(a.score, score, VtScoreSize);
53
	a.type = type;
54
	return lookupavl(scoretree, &a.avl) != nil;
55
}
56
 
57
static void
58
markvisited(uchar score[VtScoreSize], int type)
59
{
60
	ScoreTree *a;
61
	Avl *old;
62
 
63
	if(scoretree == nil)
64
		return;
65
	a = binalloc(&scorebin, sizeof *a, 1);
66
	memmove(a->score, score, VtScoreSize);
67
	a->type = type;
68
	insertavl(scoretree, &a->avl, &old);
69
}
70
 
71
void
72
usage(void)
73
{
74
	fprint(2, "usage: %s [-fimrv] [-t type] srchost dsthost score\n", argv0);
75
	exits("usage");
76
}
77
 
78
void
79
walk(uchar score[VtScoreSize], uint type, int base)
80
{
81
	int i, n;
82
	uchar *buf;
83
	uchar nscore[VtScoreSize];
84
	VtEntry e;
85
	VtRoot root;
86
 
87
	if(memcmp(score, vtzeroscore, VtScoreSize) == 0 || memcmp(score, zeroscore, VtScoreSize) == 0)
88
		return;
89
 
90
	if(havevisited(score, type)){
91
		nskip++;
92
		return;
93
	}
94
 
95
	buf = vtmallocz(VtMaxLumpSize);
96
	if(fast && vtread(zdst, score, type, buf, VtMaxLumpSize) >= 0){
97
		if(verbose)
98
			fprint(2, "skip %V\n", score);
99
		free(buf);
100
		return;
101
	}
102
 
103
	n = vtread(zsrc, score, type, buf, VtMaxLumpSize);
104
	if(n < 0){
105
		if(rewrite){
106
			changes++;
107
			memmove(score, vtzeroscore, VtScoreSize);
108
		}else if(!ignoreerrors)
109
			sysfatal("reading block %V (type %d): %r", score, type);
110
		return;
111
	}
112
 
113
	switch(type){
114
	case VtRootType:
115
		if(vtrootunpack(&root, buf) < 0){
116
			fprint(2, "warning: could not unpack root in %V %d\n", score, type);
117
			break;
118
		}
119
		walk(root.prev, VtRootType, 0);
120
		walk(root.score, VtDirType, 0);
121
		if(rewrite)
122
			vtrootpack(&root, buf);	/* walk might have changed score */
123
		break;
124
 
125
	case VtDirType:
126
		for(i=0; i*VtEntrySize<n; i++){
127
			if(vtentryunpack(&e, buf, i) < 0){
128
				fprint(2, "warning: could not unpack entry #%d in %V %d\n", i, score, type);
129
				continue;
130
			}
131
			if(!(e.flags & VtEntryActive))
132
				continue;
133
			walk(e.score, e.type, e.type&VtTypeBaseMask);
134
			/*
135
			 * Don't repack unless we're rewriting -- some old 
136
			 * vac files have psize==0 and dsize==0, and these
137
			 * get rewritten by vtentryunpack to have less strange
138
			 * block sizes.  So vtentryunpack; vtentrypack does not
139
			 * guarantee to preserve the exact bytes in buf.
140
			 */
141
			if(rewrite)
142
				vtentrypack(&e, buf, i);
143
		}
144
		break;
145
 
146
	case VtDataType:
147
		break;
148
 
149
	default:	/* pointers */
150
		for(i=0; i<n; i+=VtScoreSize)
151
			if(memcmp(buf+i, vtzeroscore, VtScoreSize) != 0)
152
				walk(buf+i, type-1, base);
153
		break;
154
	}
155
 
156
	nwrite++;
157
	if(vtwrite(zdst, nscore, type, buf, n) < 0){
158
		/* figure out score for better error message */
159
		/* can't use input argument - might have changed contents */
160
		n = vtzerotruncate(type, buf, n);
161
		sha1(buf, n, score, nil);
162
		sysfatal("writing block %V (type %d): %r", score, type);
163
	}
164
	if(!rewrite && memcmp(score, nscore, VtScoreSize) != 0){
165
		fprint(2, "not rewriting: wrote %V got %V\n", score, nscore);
166
		abort();
167
		sysfatal("not rewriting: wrote %V got %V", score, nscore);
168
	}
169
 
170
	markvisited(score, type);
171
	free(buf);
172
}
173
 
174
void
175
main(int argc, char *argv[])
176
{
177
	int type, n;
178
	uchar score[VtScoreSize];
179
	uchar *buf;
180
	char *prefix;
181
 
182
	fmtinstall('F', vtfcallfmt);
183
	fmtinstall('V', vtscorefmt);
184
 
185
	type = -1;
186
	ARGBEGIN{
187
	case 'V':
188
		chattyventi++;
189
		break;
190
	case 'f':
191
		fast = 1;
192
		break;
193
	case 'i':
194
		if(rewrite)
195
			usage();
196
		ignoreerrors = 1;
197
		break;
198
	case 'm':
199
		scoretree = mkavltree(scoretreecmp);
200
		break;
201
	case 'r':
202
		if(ignoreerrors)
203
			usage();
204
		rewrite = 1;
205
		break;
206
	case 't':
207
		type = atoi(EARGF(usage()));
208
		break;
209
	case 'v':
210
		verbose = 1;
211
		break;
212
	default:
213
		usage();
214
		break;
215
	}ARGEND
216
 
217
	if(argc != 3)
218
		usage();
219
 
220
	if(vtparsescore(argv[2], &prefix, score) < 0)
221
		sysfatal("could not parse score: %r");
222
 
223
	buf = vtmallocz(VtMaxLumpSize);
224
 
225
	zsrc = vtdial(argv[0]);
226
	if(zsrc == nil)
227
		sysfatal("could not dial src server: %r");
228
	if(vtconnect(zsrc) < 0)
229
		sysfatal("vtconnect src: %r");
230
 
231
	zdst = vtdial(argv[1]);
232
	if(zdst == nil)
233
		sysfatal("could not dial dst server: %r");
234
	if(vtconnect(zdst) < 0)
235
		sysfatal("vtconnect dst: %r");
236
 
237
	if(type != -1){
238
		n = vtread(zsrc, score, type, buf, VtMaxLumpSize);
239
		if(n < 0)
240
			sysfatal("could not read block: %r");
241
	}else{
242
		for(type=0; type<VtMaxType; type++){
243
			n = vtread(zsrc, score, type, buf, VtMaxLumpSize);
244
			if(n >= 0)
245
				break;
246
		}
247
		if(type == VtMaxType)
248
			sysfatal("could not find block %V of any type", score);
249
	}
250
 
251
	walk(score, type, VtDirType);
252
	if(changes)
253
		print("%s:%V (%d pointers rewritten)\n", prefix, score, changes);
254
 
255
	if(verbose)
256
		print("%d skipped, %d written\n", nskip, nwrite);
257
 
258
	if(vtsync(zdst) < 0)
259
		sysfatal("could not sync dst server: %r");
260
 
261
	exits(0);
262
}