Blob


1 #include "stdinc.h"
2 #include <fcall.h> /* dirmodefmt */
3 #include "vac.h"
5 #ifndef PLAN9PORT
6 #pragma varargck type "t" ulong
7 #endif
9 VacFs *fs;
10 int tostdout;
11 int nwant;
12 char **want;
13 int *found;
14 int chatty;
15 VtConn *conn;
16 int errors;
17 int settimes;
18 int table;
20 int mtimefmt(Fmt*);
21 void unvac(VacFile*, char*, VacDir*);
23 void
24 usage(void)
25 {
26 fprint(2, "usage: unvac [-TVctv] [-h host] file.vac [file ...]\n");
27 threadexitsall("usage");
28 }
30 void
31 threadmain(int argc, char *argv[])
32 {
33 int i;
34 char *host;
35 VacFile *f;
37 fmtinstall('H', encodefmt);
38 fmtinstall('V', vtscorefmt);
39 fmtinstall('F', vtfcallfmt);
40 fmtinstall('t', mtimefmt);
41 fmtinstall('M', dirmodefmt);
43 host = nil;
44 ARGBEGIN{
45 case 'T':
46 settimes = 1;
47 break;
48 case 'V':
49 chattyventi = 1;
50 break;
51 case 'c':
52 tostdout++;
53 break;
54 case 'h':
55 host = EARGF(usage());
56 break;
57 case 't':
58 table++;
59 break;
60 case 'v':
61 chatty++;
62 break;
63 default:
64 usage();
65 }ARGEND
67 if(argc < 1)
68 usage();
70 conn = vtdial(host);
71 if(conn == nil)
72 sysfatal("could not connect to server: %r");
74 if(vtconnect(conn) < 0)
75 sysfatal("vtconnect: %r");
77 fs = vacfsopen(conn, argv[0], VtOREAD, 128);
78 if(fs == nil)
79 sysfatal("vacfsopen: %r");
81 nwant = argc-1;
82 want = argv+1;
83 found = vtmallocz(nwant*sizeof found[0]);
85 if((f = vacfsgetroot(fs)) == nil)
86 sysfatal("vacfsgetroot: %r");
88 unvac(f, nil, nil);
89 for(i=0; i<nwant; i++){
90 if(want[i] && !found[i]){
91 fprint(2, "warning: didn't find %s\n", want[i]);
92 errors++;
93 }
94 }
95 if(errors)
96 threadexitsall("errors");
97 threadexitsall(0);
98 }
100 int
101 writen(int fd, char *buf, int n)
103 int m;
104 int oldn;
106 oldn = n;
107 while(n > 0){
108 m = write(fd, buf, n);
109 if(m <= 0)
110 return -1;
111 buf += m;
112 n -= m;
114 return oldn;
117 int
118 wantfile(char *name)
120 int i, namelen, n;
122 if(nwant == 0)
123 return 1;
125 namelen = strlen(name);
126 for(i=0; i<nwant; i++){
127 if(want[i] == nil)
128 continue;
129 n = strlen(want[i]);
130 if(n < namelen && name[n] == '/' && memcmp(name, want[i], n) == 0)
131 return 1;
132 if(namelen < n && want[i][namelen] == '/' && memcmp(want[i], name, n) == 0)
133 return 1;
134 if(n == namelen && memcmp(name, want[i], n) == 0){
135 found[i] = 1;
136 return 1;
139 return 0;
142 void
143 unvac(VacFile *f, char *name, VacDir *vdir)
145 static char buf[65536];
146 int fd, n;
147 ulong mode, mode9;
148 char *newname;
149 char *what;
150 vlong off;
151 Dir d, *dp;
152 VacDirEnum *vde;
153 VacDir newvdir;
154 VacFile *newf;
156 if(vdir)
157 mode = vdir->mode;
158 else
159 mode = vacfilegetmode(f);
161 if(vdir){
162 if(table){
163 if(chatty){
164 mode9 = vdir->mode&0777;
165 if(mode&ModeDir)
166 mode9 |= DMDIR;
167 if(mode&ModeAppend)
168 mode9 |= DMAPPEND;
169 if(mode&ModeExclusive)
170 mode9 |= DMEXCL;
171 #ifdef PLAN9PORT
172 if(mode&ModeLink)
173 mode9 |= DMSYMLINK;
174 if(mode&ModeNamedPipe)
175 mode9 |= DMNAMEDPIPE;
176 if(mode&ModeSetUid)
177 mode9 |= DMSETUID;
178 if(mode&ModeSetGid)
179 mode9 |= DMSETGID;
180 if(mode&ModeDevice)
181 mode9 |= DMDEVICE;
182 #endif
183 print("%M %-10s %-10s %11lld %t %s\n",
184 mode9, vdir->uid, vdir->gid, vdir->size,
185 vdir->mtime, name);
186 }else
187 print("%s%s\n", name, (mode&ModeDir) ? "/" : "");
189 else if(chatty)
190 fprint(2, "%s%s\n", name, (mode&ModeDir) ? "/" : "");
193 if(mode&(ModeDevice|ModeLink|ModeNamedPipe|ModeExclusive)){
194 if(table)
195 return;
196 if(mode&ModeDevice)
197 what = "device";
198 else if(mode&ModeLink)
199 what = "link";
200 else if(mode&ModeNamedPipe)
201 what = "named pipe";
202 else if(mode&ModeExclusive)
203 what = "lock";
204 else
205 what = "unknown type of file";
206 fprint(2, "warning: ignoring %s %s\n", what, name);
207 return;
210 if(mode&ModeDir){
211 if((vde = vdeopen(f)) == nil){
212 fprint(2, "vdeopen %s: %r", name);
213 errors++;
214 return;
216 if(!table && !tostdout && vdir){
217 // create directory
218 if((dp = dirstat(name)) == nil){
219 if((fd = create(name, OREAD, DMDIR|(mode&0777))) < 0){
220 fprint(2, "mkdir %s: %r\n", name);
221 vdeclose(vde);
223 close(fd);
224 }else{
225 if(!(dp->mode&DMDIR)){
226 fprint(2, "%s already exists and is not a directory\n", name);
227 errors++;
228 free(dp);
229 vdeclose(vde);
230 return;
232 free(dp);
235 while(vderead(vde, &newvdir) > 0){
236 if(name == nil)
237 newname = newvdir.elem;
238 else
239 newname = smprint("%s/%s", name, newvdir.elem);
240 if(wantfile(newname)){
241 if((newf = vacfilewalk(f, newvdir.elem)) == nil){
242 fprint(2, "walk %s: %r\n", name);
243 errors++;
244 }else if(newf == f){
245 fprint(2, "walk loop: %s\n", newname);
246 vacfiledecref(newf);
247 }else{
248 unvac(newf, newname, &newvdir);
249 vacfiledecref(newf);
252 if(newname != newvdir.elem)
253 free(newname);
254 vdcleanup(&newvdir);
256 vdeclose(vde);
257 }else{
258 if(!table){
259 if(tostdout)
260 fd = dup(1, -1);
261 else if((fd = create(name, OWRITE, mode&0777)) < 0){
262 fprint(2, "create %s: %r\n", name);
263 errors++;
264 return;
266 off = 0;
267 while((n = vacfileread(f, buf, sizeof buf, off)) > 0){
268 if(writen(fd, buf, n) != n){
269 fprint(2, "write %s: %r\n", name);
270 errors++;
271 close(fd);
272 remove(name);
273 return;
275 off += n;
277 close(fd);
280 if(vdir && settimes && !tostdout){
281 nulldir(&d);
282 d.mtime = vdir->mtime;
283 if(dirwstat(name, &d) < 0)
284 fprint(2, "warning: setting mtime on %s: %r", name);
288 int
289 mtimefmt(Fmt *f)
291 Tm *tm;
293 tm = localtime(va_arg(f->args, ulong));
294 fmtprint(f, "%04d-%02d-%02d %02d:%02d",
295 tm->year+1900, tm->mon+1, tm->mday,
296 tm->hour, tm->min);
297 return 0;