13e12c5d1SDavid du Colombier #include <u.h>
23e12c5d1SDavid du Colombier #include <libc.h>
33e12c5d1SDavid du Colombier #include <bio.h>
43e12c5d1SDavid du Colombier
53e12c5d1SDavid du Colombier enum{
63e12c5d1SDavid du Colombier LEN = 8*1024,
7219b2ee8SDavid du Colombier NFLDS = 6, /* filename, modes, uid, gid, mtime, bytes */
83e12c5d1SDavid du Colombier };
93e12c5d1SDavid du Colombier
103e12c5d1SDavid du Colombier int selected(char*, int, char*[]);
113e12c5d1SDavid du Colombier void mkdirs(char*, char*);
12219b2ee8SDavid du Colombier void mkdir(char*, ulong, ulong, char*, char*);
13603dff34SDavid du Colombier void extract(char*, ulong, ulong, char*, char*, uvlong);
14603dff34SDavid du Colombier void seekpast(uvlong);
153e12c5d1SDavid du Colombier void error(char*, ...);
163e12c5d1SDavid du Colombier void warn(char*, ...);
173e12c5d1SDavid du Colombier void usage(void);
18cd1a0026SDavid du Colombier #pragma varargck argpos warn 1
19cd1a0026SDavid du Colombier #pragma varargck argpos error 1
203e12c5d1SDavid du Colombier
213e12c5d1SDavid du Colombier Biobufhdr bin;
223e12c5d1SDavid du Colombier uchar binbuf[2*LEN];
239a747e4fSDavid du Colombier char linebuf[LEN];
243e12c5d1SDavid du Colombier int uflag;
253e12c5d1SDavid du Colombier int hflag;
26219b2ee8SDavid du Colombier int vflag;
27cd1a0026SDavid du Colombier int Tflag;
283e12c5d1SDavid du Colombier
293e12c5d1SDavid du Colombier void
main(int argc,char ** argv)303e12c5d1SDavid du Colombier main(int argc, char **argv)
313e12c5d1SDavid du Colombier {
323e12c5d1SDavid du Colombier Biobuf bout;
333e12c5d1SDavid du Colombier char *fields[NFLDS], name[2*LEN], *p, *namep;
349a747e4fSDavid du Colombier char *uid, *gid;
35603dff34SDavid du Colombier ulong mode, mtime;
36603dff34SDavid du Colombier uvlong bytes;
373e12c5d1SDavid du Colombier
389a747e4fSDavid du Colombier quotefmtinstall();
393e12c5d1SDavid du Colombier namep = name;
403e12c5d1SDavid du Colombier ARGBEGIN{
413e12c5d1SDavid du Colombier case 'd':
423e12c5d1SDavid du Colombier p = ARGF();
433e12c5d1SDavid du Colombier if(strlen(p) >= LEN)
443e12c5d1SDavid du Colombier error("destination fs name too long\n");
453e12c5d1SDavid du Colombier strcpy(name, p);
463e12c5d1SDavid du Colombier namep = name + strlen(name);
473e12c5d1SDavid du Colombier break;
483e12c5d1SDavid du Colombier case 'h':
493e12c5d1SDavid du Colombier hflag = 1;
503e12c5d1SDavid du Colombier Binit(&bout, 1, OWRITE);
513e12c5d1SDavid du Colombier break;
523e12c5d1SDavid du Colombier case 'u':
533e12c5d1SDavid du Colombier uflag = 1;
54cd1a0026SDavid du Colombier Tflag = 1;
55cd1a0026SDavid du Colombier break;
56cd1a0026SDavid du Colombier case 'T':
57cd1a0026SDavid du Colombier Tflag = 1;
583e12c5d1SDavid du Colombier break;
59219b2ee8SDavid du Colombier case 'v':
60219b2ee8SDavid du Colombier vflag = 1;
61219b2ee8SDavid du Colombier break;
623e12c5d1SDavid du Colombier default:
633e12c5d1SDavid du Colombier usage();
643e12c5d1SDavid du Colombier }ARGEND
653e12c5d1SDavid du Colombier
663e12c5d1SDavid du Colombier Binits(&bin, 0, OREAD, binbuf, sizeof binbuf);
673e12c5d1SDavid du Colombier while(p = Brdline(&bin, '\n')){
683e12c5d1SDavid du Colombier p[Blinelen(&bin)-1] = '\0';
699a747e4fSDavid du Colombier strcpy(linebuf, p);
709a747e4fSDavid du Colombier p = linebuf;
713e12c5d1SDavid du Colombier if(strcmp(p, "end of archive") == 0){
72223a736eSDavid du Colombier Bterm(&bout);
733e12c5d1SDavid du Colombier fprint(2, "done\n");
743e12c5d1SDavid du Colombier exits(0);
753e12c5d1SDavid du Colombier }
7612fd1c83SDavid du Colombier if (gettokens(p, fields, NFLDS, " \t") != NFLDS){
773e12c5d1SDavid du Colombier warn("too few fields in file header");
783e12c5d1SDavid du Colombier continue;
793e12c5d1SDavid du Colombier }
80da79363fSDavid du Colombier p = unquotestrdup(fields[0]);
8112fd1c83SDavid du Colombier strcpy(namep, p);
8212fd1c83SDavid du Colombier free(p);
833e12c5d1SDavid du Colombier mode = strtoul(fields[1], 0, 8);
849a747e4fSDavid du Colombier uid = fields[2];
859a747e4fSDavid du Colombier gid = fields[3];
86219b2ee8SDavid du Colombier mtime = strtoul(fields[4], 0, 10);
87603dff34SDavid du Colombier bytes = strtoull(fields[5], 0, 10);
883e12c5d1SDavid du Colombier if(argc){
893e12c5d1SDavid du Colombier if(!selected(namep, argc, argv)){
903e12c5d1SDavid du Colombier if(bytes)
913e12c5d1SDavid du Colombier seekpast(bytes);
923e12c5d1SDavid du Colombier continue;
933e12c5d1SDavid du Colombier }
943e12c5d1SDavid du Colombier mkdirs(name, namep);
953e12c5d1SDavid du Colombier }
963e12c5d1SDavid du Colombier if(hflag){
97603dff34SDavid du Colombier Bprint(&bout, "%q %luo %q %q %lud %llud\n",
98219b2ee8SDavid du Colombier name, mode, uid, gid, mtime, bytes);
993e12c5d1SDavid du Colombier if(bytes)
1003e12c5d1SDavid du Colombier seekpast(bytes);
1013e12c5d1SDavid du Colombier continue;
1023e12c5d1SDavid du Colombier }
1039a747e4fSDavid du Colombier if(mode & DMDIR)
104219b2ee8SDavid du Colombier mkdir(name, mode, mtime, uid, gid);
1053e12c5d1SDavid du Colombier else
106219b2ee8SDavid du Colombier extract(name, mode, mtime, uid, gid, bytes);
1073e12c5d1SDavid du Colombier }
1083e12c5d1SDavid du Colombier fprint(2, "premature end of archive\n");
1093e12c5d1SDavid du Colombier exits("premature end of archive");
1103e12c5d1SDavid du Colombier }
1113e12c5d1SDavid du Colombier
1123e12c5d1SDavid du Colombier int
fileprefix(char * prefix,char * s)1133e12c5d1SDavid du Colombier fileprefix(char *prefix, char *s)
1143e12c5d1SDavid du Colombier {
1153e12c5d1SDavid du Colombier while(*prefix)
1163e12c5d1SDavid du Colombier if(*prefix++ != *s++)
1173e12c5d1SDavid du Colombier return 0;
1183e12c5d1SDavid du Colombier if(*s && *s != '/')
1193e12c5d1SDavid du Colombier return 0;
1203e12c5d1SDavid du Colombier return 1;
1213e12c5d1SDavid du Colombier }
1223e12c5d1SDavid du Colombier
1233e12c5d1SDavid du Colombier int
selected(char * s,int argc,char * argv[])1243e12c5d1SDavid du Colombier selected(char *s, int argc, char *argv[])
1253e12c5d1SDavid du Colombier {
1263e12c5d1SDavid du Colombier int i;
1273e12c5d1SDavid du Colombier
1283e12c5d1SDavid du Colombier for(i=0; i<argc; i++)
1293e12c5d1SDavid du Colombier if(fileprefix(argv[i], s))
1303e12c5d1SDavid du Colombier return 1;
1313e12c5d1SDavid du Colombier return 0;
1323e12c5d1SDavid du Colombier }
1333e12c5d1SDavid du Colombier
1343e12c5d1SDavid du Colombier void
mkdirs(char * name,char * namep)1353e12c5d1SDavid du Colombier mkdirs(char *name, char *namep)
1363e12c5d1SDavid du Colombier {
1373e12c5d1SDavid du Colombier char buf[2*LEN], *p;
1383e12c5d1SDavid du Colombier int fd;
1393e12c5d1SDavid du Colombier
1403e12c5d1SDavid du Colombier strcpy(buf, name);
1413e12c5d1SDavid du Colombier for(p = &buf[namep - name]; p = utfrune(p, '/'); p++){
1423e12c5d1SDavid du Colombier if(p[1] == '\0')
1433e12c5d1SDavid du Colombier return;
1443e12c5d1SDavid du Colombier *p = 0;
1459a747e4fSDavid du Colombier fd = create(buf, OREAD, 0775|DMDIR);
1463e12c5d1SDavid du Colombier close(fd);
1473e12c5d1SDavid du Colombier *p = '/';
1483e12c5d1SDavid du Colombier }
1493e12c5d1SDavid du Colombier }
1503e12c5d1SDavid du Colombier
1513e12c5d1SDavid du Colombier void
mkdir(char * name,ulong mode,ulong mtime,char * uid,char * gid)152219b2ee8SDavid du Colombier mkdir(char *name, ulong mode, ulong mtime, char *uid, char *gid)
1533e12c5d1SDavid du Colombier {
1549a747e4fSDavid du Colombier Dir *d, xd;
1553e12c5d1SDavid du Colombier int fd;
1563e12c5d1SDavid du Colombier char *p;
157f5736e95SDavid du Colombier char olderr[256];
1583e12c5d1SDavid du Colombier
1593e12c5d1SDavid du Colombier fd = create(name, OREAD, mode);
1603e12c5d1SDavid du Colombier if(fd < 0){
161f5736e95SDavid du Colombier rerrstr(olderr, sizeof(olderr));
1629a747e4fSDavid du Colombier if((d = dirstat(name)) == nil || !(d->mode & DMDIR)){
1639a747e4fSDavid du Colombier free(d);
16440ef9009SDavid du Colombier warn("can't make directory %q, mode %luo: %s", name, mode, olderr);
1653e12c5d1SDavid du Colombier return;
1663e12c5d1SDavid du Colombier }
167fe853e23SDavid du Colombier free(d);
1689a747e4fSDavid du Colombier }
1693e12c5d1SDavid du Colombier close(fd);
1703e12c5d1SDavid du Colombier
1719a747e4fSDavid du Colombier d = &xd;
1729a747e4fSDavid du Colombier nulldir(d);
1733e12c5d1SDavid du Colombier p = utfrrune(name, L'/');
1743e12c5d1SDavid du Colombier if(p)
1753e12c5d1SDavid du Colombier p++;
1763e12c5d1SDavid du Colombier else
1773e12c5d1SDavid du Colombier p = name;
1789a747e4fSDavid du Colombier d->name = p;
1793e12c5d1SDavid du Colombier if(uflag){
1809a747e4fSDavid du Colombier d->uid = uid;
1819a747e4fSDavid du Colombier d->gid = gid;
1823e12c5d1SDavid du Colombier }
183cd1a0026SDavid du Colombier if(Tflag)
184cd1a0026SDavid du Colombier d->mtime = mtime;
1859a747e4fSDavid du Colombier d->mode = mode;
1869a747e4fSDavid du Colombier if(dirwstat(name, d) < 0)
1879a747e4fSDavid du Colombier warn("can't set modes for %q: %r", name);
1889a747e4fSDavid du Colombier
189cd1a0026SDavid du Colombier if(uflag||Tflag){
1909a747e4fSDavid du Colombier if((d = dirstat(name)) == nil){
1919a747e4fSDavid du Colombier warn("can't reread modes for %q: %r", name);
1929a747e4fSDavid du Colombier return;
1933e12c5d1SDavid du Colombier }
194cd1a0026SDavid du Colombier if(Tflag && d->mtime != mtime)
1959a747e4fSDavid du Colombier warn("%q: time mismatch %lud %lud\n", name, mtime, d->mtime);
196cd1a0026SDavid du Colombier if(uflag && strcmp(uid, d->uid))
1979a747e4fSDavid du Colombier warn("%q: uid mismatch %q %q", name, uid, d->uid);
198cd1a0026SDavid du Colombier if(uflag && strcmp(gid, d->gid))
1999a747e4fSDavid du Colombier warn("%q: gid mismatch %q %q", name, gid, d->gid);
2009a747e4fSDavid du Colombier }
2013e12c5d1SDavid du Colombier }
2023e12c5d1SDavid du Colombier
2033e12c5d1SDavid du Colombier void
extract(char * name,ulong mode,ulong mtime,char * uid,char * gid,uvlong bytes)204603dff34SDavid du Colombier extract(char *name, ulong mode, ulong mtime, char *uid, char *gid, uvlong bytes)
2053e12c5d1SDavid du Colombier {
2069a747e4fSDavid du Colombier Dir d, *nd;
2073e12c5d1SDavid du Colombier Biobuf *b;
2083e12c5d1SDavid du Colombier char buf[LEN];
2093e12c5d1SDavid du Colombier char *p;
210603dff34SDavid du Colombier ulong n;
211603dff34SDavid du Colombier uvlong tot;
2123e12c5d1SDavid du Colombier
213219b2ee8SDavid du Colombier if(vflag)
214603dff34SDavid du Colombier print("x %q %llud bytes\n", name, bytes);
215219b2ee8SDavid du Colombier
2163e12c5d1SDavid du Colombier b = Bopen(name, OWRITE);
2173e12c5d1SDavid du Colombier if(!b){
2189a747e4fSDavid du Colombier warn("can't make file %q: %r", name);
2193e12c5d1SDavid du Colombier seekpast(bytes);
2203e12c5d1SDavid du Colombier return;
2213e12c5d1SDavid du Colombier }
2223e12c5d1SDavid du Colombier for(tot = 0; tot < bytes; tot += n){
2233e12c5d1SDavid du Colombier n = sizeof buf;
2243e12c5d1SDavid du Colombier if(tot + n > bytes)
2253e12c5d1SDavid du Colombier n = bytes - tot;
2263e12c5d1SDavid du Colombier n = Bread(&bin, buf, n);
227219b2ee8SDavid du Colombier if(n <= 0)
2289a747e4fSDavid du Colombier error("premature eof reading %q", name);
2293e12c5d1SDavid du Colombier if(Bwrite(b, buf, n) != n)
2309a747e4fSDavid du Colombier warn("error writing %q: %r", name);
2313e12c5d1SDavid du Colombier }
2323e12c5d1SDavid du Colombier
2339a747e4fSDavid du Colombier nulldir(&d);
2343e12c5d1SDavid du Colombier p = utfrrune(name, '/');
2353e12c5d1SDavid du Colombier if(p)
2363e12c5d1SDavid du Colombier p++;
2373e12c5d1SDavid du Colombier else
2383e12c5d1SDavid du Colombier p = name;
2399a747e4fSDavid du Colombier d.name = p;
2403e12c5d1SDavid du Colombier if(uflag){
2419a747e4fSDavid du Colombier d.uid = uid;
2429a747e4fSDavid du Colombier d.gid = gid;
2433e12c5d1SDavid du Colombier }
244cd1a0026SDavid du Colombier if(Tflag)
245cd1a0026SDavid du Colombier d.mtime = mtime;
2463e12c5d1SDavid du Colombier d.mode = mode;
247219b2ee8SDavid du Colombier Bflush(b);
2483e12c5d1SDavid du Colombier if(dirfwstat(Bfildes(b), &d) < 0)
2499a747e4fSDavid du Colombier warn("can't set modes for %q: %r", name);
250cd1a0026SDavid du Colombier if(uflag||Tflag){
2519a747e4fSDavid du Colombier if((nd = dirfstat(Bfildes(b))) == nil)
2529a747e4fSDavid du Colombier warn("can't reread modes for %q: %r", name);
2539a747e4fSDavid du Colombier else{
254cd1a0026SDavid du Colombier if(Tflag && nd->mtime != mtime)
255603dff34SDavid du Colombier warn("%q: time mismatch %lud %lud\n",
256603dff34SDavid du Colombier name, mtime, nd->mtime);
257cd1a0026SDavid du Colombier if(uflag && strcmp(uid, nd->uid))
258603dff34SDavid du Colombier warn("%q: uid mismatch %q %q",
259603dff34SDavid du Colombier name, uid, nd->uid);
260cd1a0026SDavid du Colombier if(uflag && strcmp(gid, nd->gid))
261603dff34SDavid du Colombier warn("%q: gid mismatch %q %q",
262603dff34SDavid du Colombier name, gid, nd->gid);
2639a747e4fSDavid du Colombier free(nd);
2649a747e4fSDavid du Colombier }
2653e12c5d1SDavid du Colombier }
266219b2ee8SDavid du Colombier Bterm(b);
2673e12c5d1SDavid du Colombier }
2683e12c5d1SDavid du Colombier
2693e12c5d1SDavid du Colombier void
seekpast(uvlong bytes)270603dff34SDavid du Colombier seekpast(uvlong bytes)
2713e12c5d1SDavid du Colombier {
2723e12c5d1SDavid du Colombier char buf[LEN];
273*c93608ccSDavid du Colombier long n;
274603dff34SDavid du Colombier uvlong tot;
2753e12c5d1SDavid du Colombier
2763e12c5d1SDavid du Colombier for(tot = 0; tot < bytes; tot += n){
2773e12c5d1SDavid du Colombier n = sizeof buf;
2783e12c5d1SDavid du Colombier if(tot + n > bytes)
2793e12c5d1SDavid du Colombier n = bytes - tot;
2803e12c5d1SDavid du Colombier n = Bread(&bin, buf, n);
2813e12c5d1SDavid du Colombier if(n < 0)
2823e12c5d1SDavid du Colombier error("premature eof");
2833e12c5d1SDavid du Colombier }
2843e12c5d1SDavid du Colombier }
2853e12c5d1SDavid du Colombier
2863e12c5d1SDavid du Colombier void
error(char * fmt,...)2873e12c5d1SDavid du Colombier error(char *fmt, ...)
2883e12c5d1SDavid du Colombier {
2893e12c5d1SDavid du Colombier char buf[1024];
2907dd7cddfSDavid du Colombier va_list arg;
2913e12c5d1SDavid du Colombier
2929a747e4fSDavid du Colombier sprint(buf, "%q: ", argv0);
2937dd7cddfSDavid du Colombier va_start(arg, fmt);
2949a747e4fSDavid du Colombier vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg);
2957dd7cddfSDavid du Colombier va_end(arg);
2963e12c5d1SDavid du Colombier fprint(2, "%s\n", buf);
2973e12c5d1SDavid du Colombier exits(0);
2983e12c5d1SDavid du Colombier }
2993e12c5d1SDavid du Colombier
3003e12c5d1SDavid du Colombier void
warn(char * fmt,...)3013e12c5d1SDavid du Colombier warn(char *fmt, ...)
3023e12c5d1SDavid du Colombier {
3033e12c5d1SDavid du Colombier char buf[1024];
3047dd7cddfSDavid du Colombier va_list arg;
3053e12c5d1SDavid du Colombier
3069a747e4fSDavid du Colombier sprint(buf, "%q: ", argv0);
3077dd7cddfSDavid du Colombier va_start(arg, fmt);
3089a747e4fSDavid du Colombier vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg);
3097dd7cddfSDavid du Colombier va_end(arg);
3103e12c5d1SDavid du Colombier fprint(2, "%s\n", buf);
3113e12c5d1SDavid du Colombier }
3123e12c5d1SDavid du Colombier
3133e12c5d1SDavid du Colombier void
usage(void)3143e12c5d1SDavid du Colombier usage(void)
3153e12c5d1SDavid du Colombier {
316219b2ee8SDavid du Colombier fprint(2, "usage: mkext [-h] [-u] [-v] [-d dest-fs] [file ...]\n");
3177dd7cddfSDavid du Colombier exits("usage");
3183e12c5d1SDavid du Colombier }
319