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