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 "stdinc.h"
2
#include <fcall.h>	/* dirmodefmt */
3
#include "vac.h"
4
 
5
#pragma varargck type "t" ulong
6
 
7
VacFs *fs;
8
int tostdout;
9
int diff;
10
int nwant;
11
char **want;
12
int *found;
13
int chatty;
14
VtConn *conn;
15
int errors;
16
int settimes;
17
int table;
18
 
19
int mtimefmt(Fmt*);
20
void unvac(VacFile*, char*, VacDir*);
21
 
22
void
23
usage(void)
24
{
25
	fprint(2, "usage: unvac [-TVcdtv] [-h host] file.vac [file ...]\n");
26
	threadexitsall("usage");
27
}
28
 
29
struct
30
{
31
	vlong data;
32
	vlong skipdata;
33
} stats;
34
 
35
void
36
threadmain(int argc, char *argv[])
37
{
38
	int i, printstats;
39
	char *host;
40
	VacFile *f;
41
 
42
	fmtinstall('H', encodefmt);
43
	fmtinstall('V', vtscorefmt);
44
	fmtinstall('F', vtfcallfmt);
45
	fmtinstall('t', mtimefmt);
46
	fmtinstall('M', dirmodefmt);
47
 
48
	host = nil;
49
	printstats = 0;
50
 
51
	ARGBEGIN{
52
	case 'T':
53
		settimes = 1;
54
		break;
55
	case 'V':
56
		chattyventi = 1;
57
		break;
58
	case 'c':
59
		tostdout++;
60
		break;
61
	case 'd':
62
		diff++;
63
		break;
64
	case 'h':
65
		host = EARGF(usage());
66
		break;
67
	case 's':
68
		printstats++;
69
		break;
70
	case 't':
71
		table++;
72
		break;
73
	case 'v':
74
		chatty++;
75
		break;
76
	default:
77
		usage();
78
	}ARGEND
79
 
80
	if(argc < 1)
81
		usage();
82
 
83
	if(tostdout && diff){
84
		fprint(2, "cannot use -c with -d\n");
85
		usage();
86
	}
87
 
88
	conn = vtdial(host);
89
	if(conn == nil)
90
		sysfatal("could not connect to server: %r");
91
 
92
	if(vtconnect(conn) < 0)
93
		sysfatal("vtconnect: %r");
94
 
95
	fs = vacfsopen(conn, argv[0], VtOREAD, 128);
96
	if(fs == nil)
97
		sysfatal("vacfsopen: %r");
98
 
99
	nwant = argc-1;
100
	want = argv+1;
101
	found = vtmallocz(nwant*sizeof found[0]);
102
 
103
	if((f = vacfsgetroot(fs)) == nil)
104
		sysfatal("vacfsgetroot: %r");
105
 
106
	unvac(f, nil, nil);
107
	for(i=0; i<nwant; i++){
108
		if(want[i] && !found[i]){
109
			fprint(2, "warning: didn't find %s\n", want[i]);
110
			errors++;
111
		}
112
	}
113
	if(errors)
114
		threadexitsall("errors");
115
	if(printstats)
116
		fprint(2, "%lld bytes read, %lld bytes skipped\n",
117
			stats.data, stats.skipdata);
118
	threadexitsall(0);
119
}
120
 
121
int
122
writen(int fd, char *buf, int n)
123
{
124
	int m;
125
	int oldn;
126
 
127
	oldn = n;
128
	while(n > 0){
129
		m = write(fd, buf, n);
130
		if(m <= 0)
131
			return -1;
132
		buf += m;
133
		n -= m;
134
	}
135
	return oldn;
136
}
137
 
138
int
139
wantfile(char *name)
140
{
141
	int i, namelen, n;
142
 
143
	if(nwant == 0)
144
		return 1;
145
 
146
	namelen = strlen(name);
147
	for(i=0; i<nwant; i++){
148
		if(want[i] == nil)
149
			continue;
150
		n = strlen(want[i]);
151
		if(n < namelen && name[n] == '/' && memcmp(name, want[i], n) == 0)
152
			return 1;
153
		if(namelen < n && want[i][namelen] == '/' && memcmp(want[i], name, namelen) == 0)
154
			return 1;
155
		if(n == namelen && memcmp(name, want[i], n) == 0){
156
			found[i] = 1;
157
			return 1;
158
		}
159
	}
160
	return 0;
161
}
162
 
163
void
164
unvac(VacFile *f, char *name, VacDir *vdir)
165
{
166
	static char buf[65536];
167
	int fd, n, m,  bsize;
168
	ulong mode, mode9;
169
	char *newname;
170
	char *what;
171
	vlong off;
172
	Dir d, *dp;
173
	VacDirEnum *vde;
174
	VacDir newvdir;
175
	VacFile *newf;
176
 
177
	if(vdir)
178
		mode = vdir->mode;
179
	else
180
		mode = vacfilegetmode(f);
181
 
182
	if(vdir){
183
		if(table){
184
			if(chatty){
185
				mode9 = vdir->mode&0777;
186
				if(mode&ModeDir)
187
					mode9 |= DMDIR;
188
				if(mode&ModeAppend)
189
					mode9 |= DMAPPEND;
190
				if(mode&ModeExclusive)
191
					mode9 |= DMEXCL;
192
				print("%M %-10s %-10s %11lld %t %s\n",
193
					mode9, vdir->uid, vdir->gid, vdir->size,
194
					vdir->mtime, name);
195
			}else
196
				print("%s%s\n", name, (mode&ModeDir) ? "/" : "");
197
		}
198
		else if(chatty)
199
			fprint(2, "%s%s\n", name, (mode&ModeDir) ? "/" : "");
200
	}
201
 
202
	if(mode&(ModeDevice|ModeLink|ModeNamedPipe|ModeExclusive)){
203
		if(table)
204
			return;
205
		if(mode&ModeDevice)
206
			what = "device";
207
		else if(mode&ModeLink)
208
			what = "link";
209
		else if(mode&ModeNamedPipe)
210
			what = "named pipe";
211
		else if(mode&ModeExclusive)
212
			what = "lock";
213
		else
214
			what = "unknown type of file";
215
		fprint(2, "warning: ignoring %s %s\n", what, name);
216
		return;
217
	}
218
 
219
	if(mode&ModeDir){
220
		if((vde = vdeopen(f)) == nil){
221
			fprint(2, "vdeopen %s: %r", name);
222
			errors++;
223
			return;
224
		}
225
		if(!table && !tostdout && vdir){
226
			// create directory
227
			if((dp = dirstat(name)) == nil){
228
				if((fd = create(name, OREAD, DMDIR|(mode&0777))) < 0){
229
					fprint(2, "mkdir %s: %r\n", name);
230
					vdeclose(vde);
231
				}
232
				close(fd);
233
			}else{
234
				if(!(dp->mode&DMDIR)){
235
					fprint(2, "%s already exists and is not a directory\n", name);
236
					errors++;
237
					free(dp);
238
					vdeclose(vde);
239
					return;
240
				}
241
				free(dp);
242
			}
243
		}
244
		while(vderead(vde, &newvdir) > 0){
245
			if(name == nil)
246
				newname = newvdir.elem;
247
			else
248
				newname = smprint("%s/%s", name, newvdir.elem);
249
			if(wantfile(newname)){
250
				if((newf = vacfilewalk(f, newvdir.elem)) == nil){
251
					fprint(2, "walk %s: %r\n", name);
252
					errors++;
253
				}else if(newf == f){
254
					fprint(2, "walk loop: %s\n", newname);
255
					vacfiledecref(newf);
256
				}else{
257
					unvac(newf, newname, &newvdir);
258
					vacfiledecref(newf);
259
				}
260
			}
261
			if(newname != newvdir.elem)
262
				free(newname);
263
			vdcleanup(&newvdir);
264
		}
265
		vdeclose(vde);
266
	}else{
267
		if(!table){
268
			off = 0;
269
			if(tostdout)
270
				fd = dup(1, -1);
271
			else if(diff && (fd = open(name, ORDWR)) >= 0){
272
				bsize = vacfiledsize(f);
273
				while((n = readn(fd, buf, bsize)) > 0){
274
					if(sha1matches(f, off/bsize, (uchar*)buf, n)){
275
						off += n;
276
						stats.skipdata += n;
277
						continue;
278
					}
279
					seek(fd, off, 0);
280
					if((m = vacfileread(f, buf, n, off)) < 0)
281
						break;
282
					if(writen(fd, buf, m) != m){
283
						fprint(2, "write %s: %r\n", name);
284
						goto Err;
285
					}
286
					off += m;
287
					stats.data += m;
288
					if(m < n){
289
						nulldir(&d);
290
						d.length = off;
291
						if(dirfwstat(fd, &d) < 0){
292
							fprint(2, "dirfwstat %s: %r\n", name);
293
							goto Err;
294
						}
295
						break;
296
					}
297
				}
298
			}
299
			else if((fd = create(name, OWRITE, mode&0777)) < 0){
300
				fprint(2, "create %s: %r\n", name);
301
				errors++;
302
				return;
303
			}
304
			while((n = vacfileread(f, buf, sizeof buf, off)) > 0){
305
				if(writen(fd, buf, n) != n){
306
					fprint(2, "write %s: %r\n", name);
307
				Err:
308
					errors++;
309
					close(fd);
310
					remove(name);
311
					return;
312
				}
313
				off += n;
314
				stats.data += n;
315
			}
316
			close(fd);
317
		}
318
	}
319
	if(vdir && settimes && !tostdout){
320
		nulldir(&d);
321
		d.mtime = vdir->mtime;
322
		if(dirwstat(name, &d) < 0)
323
			fprint(2, "warning: setting mtime on %s: %r", name);
324
	}
325
}
326
 
327
int
328
mtimefmt(Fmt *f)
329
{
330
	Tm *tm;
331
 
332
	tm = localtime(va_arg(f->args, ulong));
333
	fmtprint(f, "%04d-%02d-%02d %02d:%02d",
334
		tm->year+1900, tm->mon+1, tm->mday,
335
		tm->hour, tm->min);
336
	return 0;
337
}