]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/vac/unvac.c
kbdfs: simplfy
[plan9front.git] / sys / src / cmd / vac / unvac.c
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 }