Blob


1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
5 #define mkdir plan9mkdir
7 enum{
8 LEN = 8*1024,
9 NFLDS = 6, /* filename, modes, uid, gid, mtime, bytes */
10 };
12 int selected(char*, int, char*[]);
13 void mkdirs(char*, char*);
14 void mkdir(char*, ulong, ulong, char*, char*);
15 void extract(char*, ulong, ulong, char*, char*, uvlong);
16 void seekpast(uvlong);
17 void error(char*, ...);
18 void warn(char*, ...);
19 void usage(void);
20 #pragma varargck argpos warn 1
21 #pragma varargck argpos error 1
23 Biobuf bin;
24 uchar binbuf[2*LEN];
25 char linebuf[LEN];
26 int uflag;
27 int hflag;
28 int vflag;
29 int Tflag;
31 void
32 main(int argc, char **argv)
33 {
34 Biobuf bout;
35 char *fields[NFLDS], name[2*LEN], *p, *namep;
36 char *uid, *gid;
37 ulong mode, mtime;
38 uvlong bytes;
40 quotefmtinstall();
41 namep = name;
42 ARGBEGIN{
43 case 'd':
44 p = ARGF();
45 if(strlen(p) >= LEN)
46 error("destination fs name too long\n");
47 strcpy(name, p);
48 namep = name + strlen(name);
49 break;
50 case 'h':
51 hflag = 1;
52 Binit(&bout, 1, OWRITE);
53 break;
54 case 'u':
55 uflag = 1;
56 Tflag = 1;
57 break;
58 case 'T':
59 Tflag = 1;
60 break;
61 case 'v':
62 vflag = 1;
63 break;
64 default:
65 usage();
66 }ARGEND
68 Binits(&bin, 0, OREAD, binbuf, sizeof binbuf);
69 while(p = Brdline(&bin, '\n')){
70 p[Blinelen(&bin)-1] = '\0';
71 strcpy(linebuf, p);
72 p = linebuf;
73 if(strcmp(p, "end of archive") == 0){
74 Bterm(&bout);
75 fprint(2, "done\n");
76 exits(0);
77 }
78 if (gettokens(p, fields, NFLDS, " \t") != NFLDS){
79 warn("too few fields in file header");
80 continue;
81 }
82 p = unquotestrdup(fields[0]);
83 strcpy(namep, p);
84 free(p);
85 mode = strtoul(fields[1], 0, 8);
86 uid = fields[2];
87 gid = fields[3];
88 mtime = strtoul(fields[4], 0, 10);
89 bytes = strtoull(fields[5], 0, 10);
90 if(argc){
91 if(!selected(namep, argc, argv)){
92 if(bytes)
93 seekpast(bytes);
94 continue;
95 }
96 mkdirs(name, namep);
97 }
98 if(hflag){
99 Bprint(&bout, "%q %luo %q %q %lud %llud\n",
100 name, mode, uid, gid, mtime, bytes);
101 if(bytes)
102 seekpast(bytes);
103 continue;
105 if(mode & DMDIR)
106 mkdir(name, mode, mtime, uid, gid);
107 else
108 extract(name, mode, mtime, uid, gid, bytes);
110 fprint(2, "premature end of archive\n");
111 exits("premature end of archive");
114 int
115 fileprefix(char *prefix, char *s)
117 while(*prefix)
118 if(*prefix++ != *s++)
119 return 0;
120 if(*s && *s != '/')
121 return 0;
122 return 1;
125 int
126 selected(char *s, int argc, char *argv[])
128 int i;
130 for(i=0; i<argc; i++)
131 if(fileprefix(argv[i], s))
132 return 1;
133 return 0;
136 void
137 mkdirs(char *name, char *namep)
139 char buf[2*LEN], *p;
140 int fd;
142 strcpy(buf, name);
143 for(p = &buf[namep - name]; p = utfrune(p, '/'); p++){
144 if(p[1] == '\0')
145 return;
146 *p = 0;
147 fd = create(buf, OREAD, 0775|DMDIR);
148 close(fd);
149 *p = '/';
153 void
154 mkdir(char *name, ulong mode, ulong mtime, char *uid, char *gid)
156 Dir *d, xd;
157 int fd;
158 char *p;
159 char olderr[256];
161 fd = create(name, OREAD, mode);
162 if(fd < 0){
163 rerrstr(olderr, sizeof(olderr));
164 if((d = dirstat(name)) == nil || !(d->mode & DMDIR)){
165 free(d);
166 warn("can't make directory %q, mode %luo: %s", name, mode, olderr);
167 return;
169 free(d);
171 close(fd);
173 d = &xd;
174 nulldir(d);
175 p = utfrrune(name, L'/');
176 if(p)
177 p++;
178 else
179 p = name;
180 d->name = p;
181 if(uflag){
182 d->uid = uid;
183 d->gid = gid;
185 if(Tflag)
186 d->mtime = mtime;
187 d->mode = mode;
188 if(dirwstat(name, d) < 0)
189 warn("can't set modes for %q: %r", name);
191 if(uflag||Tflag){
192 if((d = dirstat(name)) == nil){
193 warn("can't reread modes for %q: %r", name);
194 return;
196 if(Tflag && d->mtime != mtime)
197 warn("%q: time mismatch %lud %lud\n", name, mtime, d->mtime);
198 if(uflag && strcmp(uid, d->uid))
199 warn("%q: uid mismatch %q %q", name, uid, d->uid);
200 if(uflag && strcmp(gid, d->gid))
201 warn("%q: gid mismatch %q %q", name, gid, d->gid);
205 void
206 extract(char *name, ulong mode, ulong mtime, char *uid, char *gid, uvlong bytes)
208 Dir d, *nd;
209 Biobuf *b;
210 char buf[LEN];
211 char *p;
212 ulong n;
213 uvlong tot;
215 if(vflag)
216 print("x %q %llud bytes\n", name, bytes);
218 b = Bopen(name, OWRITE);
219 if(!b){
220 warn("can't make file %q: %r", name);
221 seekpast(bytes);
222 return;
224 for(tot = 0; tot < bytes; tot += n){
225 n = sizeof buf;
226 if(tot + n > bytes)
227 n = bytes - tot;
228 n = Bread(&bin, buf, n);
229 if(n <= 0)
230 error("premature eof reading %q", name);
231 if(Bwrite(b, buf, n) != n)
232 warn("error writing %q: %r", name);
235 nulldir(&d);
236 p = utfrrune(name, '/');
237 if(p)
238 p++;
239 else
240 p = name;
241 d.name = p;
242 if(uflag){
243 d.uid = uid;
244 d.gid = gid;
246 if(Tflag)
247 d.mtime = mtime;
248 d.mode = mode;
249 Bflush(b);
250 if(dirfwstat(Bfildes(b), &d) < 0)
251 warn("can't set modes for %q: %r", name);
252 if(uflag||Tflag){
253 if((nd = dirfstat(Bfildes(b))) == nil)
254 warn("can't reread modes for %q: %r", name);
255 else{
256 if(Tflag && nd->mtime != mtime)
257 warn("%q: time mismatch %lud %lud\n",
258 name, mtime, nd->mtime);
259 if(uflag && strcmp(uid, nd->uid))
260 warn("%q: uid mismatch %q %q",
261 name, uid, nd->uid);
262 if(uflag && strcmp(gid, nd->gid))
263 warn("%q: gid mismatch %q %q",
264 name, gid, nd->gid);
265 free(nd);
268 Bterm(b);
271 void
272 seekpast(uvlong bytes)
274 char buf[LEN];
275 long n;
276 uvlong tot;
278 for(tot = 0; tot < bytes; tot += n){
279 n = sizeof buf;
280 if(tot + n > bytes)
281 n = bytes - tot;
282 n = Bread(&bin, buf, n);
283 if(n < 0)
284 error("premature eof");
288 void
289 error(char *fmt, ...)
291 char buf[1024];
292 va_list arg;
294 sprint(buf, "%q: ", argv0);
295 va_start(arg, fmt);
296 vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg);
297 va_end(arg);
298 fprint(2, "%s\n", buf);
299 exits(0);
302 void
303 warn(char *fmt, ...)
305 char buf[1024];
306 va_list arg;
308 sprint(buf, "%q: ", argv0);
309 va_start(arg, fmt);
310 vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg);
311 va_end(arg);
312 fprint(2, "%s\n", buf);
315 void
316 usage(void)
318 fprint(2, "usage: mkext [-h] [-u] [-v] [-d dest-fs] [file ...]\n");
319 exits("usage");