]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/tar.c
audiohda: fix syntax error
[plan9front.git] / sys / src / cmd / tar.c
1 /*
2  * tar - `tape archiver', actually usable on any medium.
3  *      POSIX "ustar" compliant when extracting, and by default when creating.
4  *      this tar attempts to read and write multiple Tblock-byte blocks
5  *      at once to and from the filesystem, and does not copy blocks
6  *      around internally.
7  */
8
9 #include <u.h>
10 #include <libc.h>
11 #include <ctype.h>
12 #include <fcall.h>              /* for %M */
13 #include <String.h>
14
15 /*
16  * modified versions of those in libc.h; scans only the first arg for
17  * keyletters and options.
18  */
19 #define TARGBEGIN {\
20         (argv0 || (argv0 = *argv)), argv++, argc--;\
21         if (argv[0]) {\
22                 char *_args, *_argt;\
23                 Rune _argc;\
24                 _args = &argv[0][0];\
25                 _argc = 0;\
26                 while(*_args && (_args += chartorune(&_argc, _args)))\
27                         switch(_argc)
28 #define TARGEND SET(_argt); USED(_argt);USED(_argc);USED(_args); \
29         argc--, argv++; } \
30         USED(argv); USED(argc); }
31 #define TARGC() (_argc)
32
33 #define ROUNDUP(a, b)   (((a) + (b) - 1)/(b))
34 #define BYTES2TBLKS(bytes) ROUNDUP(bytes, Tblock)
35
36 /* read big-endian binary integers; args must be (uchar *) */
37 #define G2BEBYTE(x)     (((x)[0]<<8)  |  (x)[1])
38 #define G3BEBYTE(x)     (((x)[0]<<16) | ((x)[1]<<8)  |  (x)[2])
39 #define G4BEBYTE(x)     (((x)[0]<<24) | ((x)[1]<<16) | ((x)[2]<<8) | (x)[3])
40 #define G8BEBYTE(x)     (((vlong)G4BEBYTE(x)<<32) | (u32int)G4BEBYTE((x)+4))
41
42 typedef vlong Off;
43 typedef char *(*Refill)(int ar, char *bufs, int justhdr);
44
45 enum { Stdin, Stdout, Stderr };
46 enum { Rd, Wr };                        /* pipe fd-array indices */
47 enum { Output, Input };
48 enum { None, Toc, Xtract, Replace };
49 enum { Alldata, Justnxthdr };
50 enum {
51         Tblock = 512,
52         Namsiz = 100,
53         Maxpfx = 155,           /* from POSIX */
54         Maxname = Namsiz + 1 + Maxpfx,
55         Maxlongname = 65535,
56         Binsize = 0x80,         /* flag in size[0], from gnu: positive binary size */
57         Binnegsz = 0xff,        /* flag in size[0]: negative binary size */
58
59         Nblock = 40,            /* maximum blocksize */
60         Dblock = 20,            /* default blocksize */
61         Debug = 0,
62 };
63
64 /* POSIX link flags */
65 enum {
66         LF_PLAIN1 =     '\0',
67         LF_PLAIN2 =     '0',
68         LF_LINK =       '1',
69         LF_SYMLINK1 =   '2',
70         LF_SYMLINK2 =   's',            /* 4BSD used this */
71         LF_CHR =        '3',
72         LF_BLK =        '4',
73         LF_DIR =        '5',
74         LF_FIFO =       '6',
75         LF_CONTIG =     '7',
76
77         /* 'A' - 'Z' are reserved for custom implementations */
78
79         LF_LONGNAME =   'L',            /* GNU extenstion */
80         LF_LONGLINK =   'K',
81         LF_PAXHDR =     'x',            /* PAX header */
82         LF_PAXGLOBL =   'g',
83 };
84
85 #define islink(lf)      (isreallink(lf) || issymlink(lf))
86 #define isreallink(lf)  ((lf) == LF_LINK)
87 #define issymlink(lf)   ((lf) == LF_SYMLINK1 || (lf) == LF_SYMLINK2)
88
89 typedef union {
90         uchar   data[Tblock];
91         struct {
92                 char    name[Namsiz];
93                 char    mode[8];
94                 char    uid[8];
95                 char    gid[8];
96                 char    size[12];
97                 char    mtime[12];
98                 char    chksum[8];
99                 char    linkflag;
100                 char    linkname[Namsiz];
101
102                 /* rest are defined by POSIX's ustar format; see p1003.2b */
103                 char    magic[6];       /* "ustar" */
104                 char    version[2];
105                 char    uname[32];
106                 char    gname[32];
107                 char    devmajor[8];
108                 char    devminor[8];
109                 char    prefix[Maxpfx]; /* if non-null, path= prefix "/" name */
110         };
111 } Blk;
112
113 typedef struct {
114         char    *name;
115         char    *uid;
116         char    *gid;
117         ulong   mode;
118         vlong   size;
119         vlong   mtime;
120         vlong   atime;
121 } Hdr;
122
123 typedef struct {
124         char    *comp;
125         char    *decomp;
126         char    *sfx[4];
127 } Compress;
128
129 static Compress comps[] = {
130         "gzip",         "gunzip",       { ".tar.gz", ".tgz" },  /* default */
131         "compress",     "uncompress",   { ".tar.Z",  ".tz" },
132         "bzip2",        "bunzip2",      { ".tar.bz", ".tbz",
133                                           ".tar.bz2",".tbz2" },
134 };
135
136 typedef struct {
137         int     kid;
138         int     fd;     /* original fd */
139         int     rfd;    /* replacement fd */
140         int     input;
141         int     open;
142 } Pushstate;
143
144 #define OTHER(rdwr) ((rdwr) == Rd? Wr: Rd)
145
146 static int fixednblock;
147 static int verb;
148 static int posix = 1;
149 static int docreate;
150 static int aruid;
151 static int argid;
152 static int relative = 1;
153 static int settime;
154 static int verbose;
155 static int docompress;
156 static int keepexisting;
157 static int ignerrs;             /* flag: ignore i/o errors if possible */
158 static Off blkoff;              /* offset of the current archive block (not Tblock) */
159 static Off nexthdr;
160
161 static int nblock = Dblock;
162 static int resync;
163 static char *usefile, *arname = "archive";
164 static char origdir[Maxlongname+1];
165 static Blk *tpblk, *endblk;
166 static Blk *curblk;
167 static Hdr globlhdr;
168
169 static void
170 usage(void)
171 {
172         fprint(2, "usage: %s {crtx}[PRTfgikmpsuvz] [archive] [file1 file2...]\n",
173                 argv0);
174         exits("usage");
175 }
176
177 /* I/O, with error retry or exit */
178
179 static int
180 cope(char *name, int fd, void *buf, long len, Off off)
181 {
182         fprint(2, "%s: %serror reading %s: %r\n", argv0,
183                 (ignerrs? "ignoring ": ""), name);
184         if (!ignerrs)
185                 exits("read error");
186
187         /* pretend we read len bytes of zeroes */
188         memset(buf, 0, len);
189         if (off >= 0)                   /* seekable? */
190                 seek(fd, off + len, 0);
191         return len;
192 }
193
194 static int
195 eread(char *name, int fd, void *buf, long len)
196 {
197         int rd;
198         Off off;
199
200         off = seek(fd, 0, 1);           /* for coping with errors */
201         rd = read(fd, buf, len);
202         if (rd < 0)
203                 rd = cope(name, fd, buf, len, off);
204         return rd;
205 }
206
207 static int
208 ereadn(char *name, int fd, void *buf, long len)
209 {
210         int rd;
211         Off off;
212
213         off = seek(fd, 0, 1);
214         rd = readn(fd, buf, len);
215         if (rd < 0)
216                 rd = cope(name, fd, buf, len, off);
217         return rd;
218 }
219
220 static int
221 ewrite(char *name, int fd, void *buf, long len)
222 {
223         int rd;
224
225         werrstr("");
226         rd = write(fd, buf, len);
227         if (rd != len)
228                 sysfatal("error writing %s: %r", name);
229         return rd;
230 }
231
232 /* compression */
233
234 static Compress *
235 compmethod(char *name)
236 {
237         if (name) {
238                 int i, nmlen, sfxlen;
239                 Compress *cp;
240
241                 nmlen = strlen(name);
242                 for (cp = comps; cp < comps + nelem(comps); cp++) {
243                         for (i = 0; i < nelem(cp->sfx) && cp->sfx[i]; i++) {
244                                 sfxlen = strlen(cp->sfx[i]);
245                                 if (nmlen > sfxlen &&
246                                     strcmp(cp->sfx[i], name + nmlen - sfxlen) == 0)
247                                         return cp;
248                         }
249                 }
250         }
251         return docompress? comps: nil;
252 }
253
254 /*
255  * push a filter, cmd, onto fd.  if input, it's an input descriptor.
256  * returns a descriptor to replace fd, or -1 on error.
257  */
258 static int
259 push(int fd, char *cmd, int input, Pushstate *ps)
260 {
261         int nfd, pifds[2];
262         String *s;
263
264         ps->open = 0;
265         ps->fd = fd;
266         ps->input = input;
267         if (fd < 0 || pipe(pifds) < 0)
268                 return -1;
269         ps->kid = fork();
270         switch (ps->kid) {
271         case -1:
272                 return -1;
273         case 0:
274                 if (input)
275                         dup(pifds[Wr], Stdout);
276                 else
277                         dup(pifds[Rd], Stdin);
278                 close(pifds[input? Rd: Wr]);
279                 dup(fd, (input? Stdin: Stdout));
280                 s = s_new();
281                 if (cmd[0] != '/')
282                         s_append(s, "/bin/");
283                 s_append(s, cmd);
284                 execl(s_to_c(s), cmd, nil);
285                 sysfatal("can't exec %s: %r", cmd);
286         default:
287                 nfd = pifds[input? Rd: Wr];
288                 close(pifds[input? Wr: Rd]);
289                 break;
290         }
291         ps->rfd = nfd;
292         ps->open = 1;
293         return nfd;
294 }
295
296 static char *
297 pushclose(Pushstate *ps)
298 {
299         Waitmsg *wm;
300
301         if (ps->fd < 0 || ps->rfd < 0 || !ps->open)
302                 return "not open";
303         close(ps->rfd);
304         ps->rfd = -1;
305         ps->open = 0;
306         while ((wm = wait()) != nil && wm->pid != ps->kid)
307                 continue;
308         return wm? wm->msg: nil;
309 }
310
311 /*
312  * block-buffer management
313  */
314
315 static void
316 initblks(void)
317 {
318         free(tpblk);
319         tpblk = malloc(Tblock * nblock);
320         assert(tpblk != nil);
321         endblk = tpblk + nblock;
322 }
323
324 /*
325  * (re)fill block buffers from archive.  `justhdr' means we don't care
326  * about the data before the next header block.
327  */
328 static char *
329 refill(int ar, char *bufs, int justhdr)
330 {
331         int i, n;
332         unsigned bytes = Tblock * nblock;
333         static int done, first = 1, seekable;
334
335         if (done)
336                 return nil;
337
338         blkoff = seek(ar, 0, 1);                /* note position for `tar r' */
339         if (first)
340                 seekable = blkoff >= 0;
341         /* try to size non-pipe input at first read */
342         if (first && usefile && !fixednblock) {
343                 n = eread(arname, ar, bufs, bytes);
344                 if (n == 0)
345                         sysfatal("EOF reading archive %s: %r", arname);
346                 i = n;
347                 if (i % Tblock != 0)
348                         sysfatal("%s: archive block size (%d) error", arname, i);
349                 i /= Tblock;
350                 if (i != nblock) {
351                         nblock = i;
352                         fprint(2, "%s: blocking = %d\n", argv0, nblock);
353                         endblk = (Blk *)bufs + nblock;
354                         bytes = n;
355                 }
356         } else if (justhdr && seekable && nexthdr - blkoff >= bytes) {
357                 /* optimisation for huge archive members on seekable media */
358                 if (seek(ar, bytes, 1) < 0)
359                         sysfatal("can't seek on archive %s: %r", arname);
360                 n = bytes;
361         } else
362                 n = ereadn(arname, ar, bufs, bytes);
363         first = 0;
364
365         if (n == 0)
366                 sysfatal("unexpected EOF reading archive %s", arname);
367         if (n % Tblock != 0)
368                 sysfatal("partial block read from archive %s", arname);
369         if (n != bytes) {
370                 done = 1;
371                 memset(bufs + n, 0, bytes - n);
372         }
373         return bufs;
374 }
375
376 static Blk *
377 getblk(int ar, Refill rfp, int justhdr)
378 {
379         if (curblk == nil || curblk >= endblk) {  /* input block exhausted? */
380                 if (rfp != nil && (*rfp)(ar, (char *)tpblk, justhdr) == nil)
381                         return nil;
382                 curblk = tpblk;
383         }
384         return curblk++;
385 }
386
387 static Blk *
388 getblkrd(int ar, int justhdr)
389 {
390         return getblk(ar, refill, justhdr);
391 }
392
393 static Blk *
394 getblke(int ar)
395 {
396         return getblk(ar, nil, Alldata);
397 }
398
399 static Blk *
400 getblkz(int ar)
401 {
402         Blk *bp = getblke(ar);
403
404         if (bp != nil)
405                 memset(bp->data, 0, Tblock);
406         return bp;
407 }
408
409 /*
410  * how many block buffers are available, starting at the address
411  * just returned by getblk*?
412  */
413 static int
414 gothowmany(int max)
415 {
416         int n = endblk - (curblk - 1);
417
418         return n > max? max: n;
419 }
420
421 /*
422  * indicate that one is done with the last block obtained from getblke
423  * and it is now available to be written into the archive.
424  */
425 static void
426 putlastblk(int ar)
427 {
428         unsigned bytes = Tblock * nblock;
429
430         /* if writing end-of-archive, aid compression (good hygiene too) */
431         if (curblk < endblk)
432                 memset(curblk, 0, (char *)endblk - (char *)curblk);
433         ewrite(arname, ar, tpblk, bytes);
434 }
435
436 static void
437 putblk(int ar)
438 {
439         if (curblk >= endblk)
440                 putlastblk(ar);
441 }
442
443 static void
444 putbackblk(int ar)
445 {
446         curblk--;
447         USED(ar);
448 }
449
450 static void
451 putreadblks(int ar, int blks)
452 {
453         curblk += blks - 1;
454         USED(ar);
455 }
456
457 static void
458 putblkmany(int ar, int blks)
459 {
460         assert(blks > 0);
461         curblk += blks - 1;
462         putblk(ar);
463 }
464
465 /*
466  * common routines
467  */
468
469 /*
470  * modifies hp->chksum but restores it; important for the last block of the
471  * old archive when updating with `tar rf archive'
472  */
473 static long
474 chksum(Blk *bp)
475 {
476         int n = Tblock;
477         long i = 0;
478         uchar *cp = bp->data;
479         char oldsum[sizeof bp->chksum];
480
481         memmove(oldsum, bp->chksum, sizeof oldsum);
482         memset(bp->chksum, ' ', sizeof bp->chksum);
483         while (n-- > 0)
484                 i += *cp++;
485         memmove(bp->chksum, oldsum, sizeof oldsum);
486         return i;
487 }
488
489 static int
490 isustar(Blk *bp)
491 {
492         return strcmp(bp->magic, "ustar") == 0;
493 }
494
495 /*
496  * s is at most n bytes long, but need not be NUL-terminated.
497  * if shorter than n bytes, all bytes after the first NUL must also
498  * be NUL.
499  */
500 static int
501 strnlen(char *s, int n)
502 {
503         return s[n - 1] != '\0'? n: strlen(s);
504 }
505
506 /* set fullname from header */
507 static char *
508 parsename(Blk *bp, char *buf, int nbuf)
509 {
510         int pfxlen, namlen;
511
512         namlen = strnlen(bp->name, sizeof bp->name);
513         if (bp->prefix[0] == '\0' || !isustar(bp)) {    /* old-style name? */
514                 assert(nbuf > namlen);
515                 memmove(buf, bp->name, namlen);
516                 buf[namlen] = '\0';
517                 return buf;
518         }
519
520         /* name is in two pieces */
521         pfxlen = strnlen(bp->prefix, sizeof bp->prefix);
522         assert(nbuf > pfxlen + 1 + namlen);
523         memmove(buf, bp->prefix, pfxlen);
524         buf[pfxlen] = '/';
525         memmove(buf + pfxlen + 1, bp->name, namlen);
526         buf[pfxlen + 1 + namlen] = '\0';
527         return buf;
528 }
529
530 static int
531 isdir(Blk *bp, char *name)
532 {
533         /* the mode test is ugly but sometimes necessary */
534         return bp->linkflag == LF_DIR ||
535                 strrchr(name, '\0')[-1] == '/' ||
536                 (strtoul(bp->mode, nil, 8)&0170000) == 040000;
537 }
538
539 static int
540 eotar(Blk *bp)
541 {
542         char buf[Maxname + 1];
543         return parsename(bp, buf, sizeof(buf))[0] == '\0';
544 }
545
546 /*
547 static uvlong
548 getbe(uchar *src, int size)
549 {
550         uvlong vl = 0;
551
552         while (size-- > 0) {
553                 vl <<= 8;
554                 vl |= *src++;
555         }
556         return vl;
557 }
558  */
559
560 static void
561 putbe(uchar *dest, uvlong vl, int size)
562 {
563         for (dest += size; size-- > 0; vl >>= 8)
564                 *--dest = vl;
565 }
566
567 /*
568  * cautious parsing of octal numbers as ascii strings in
569  * a tar header block.  this is particularly important for
570  * trusting the checksum when trying to resync.
571  */
572 static uvlong
573 hdrotoull(char *st, char *end, uvlong errval, char *name, char *field)
574 {
575         char *numb;
576
577         for (numb = st; (*numb == ' ' || *numb == '\0') && numb < end; numb++)
578                 ;
579         if (numb < end && isascii(*numb) && isdigit(*numb))
580                 return strtoull(numb, nil, 8);
581         else if (numb >= end)
582                 fprint(2, "%s: %s: empty %s in header\n", argv0, name, field);
583         else
584                 fprint(2, "%s: %s: %s: non-numeric %s in header\n",
585                         argv0, name, numb, field);
586         return errval;
587 }
588
589 /*
590  * return the nominal size from the header block, which is not always the
591  * size in the archive (the archive size may be zero for some file types
592  * regardless of the nominal size).
593  *
594  * gnu and freebsd tars are now recording vlongs as big-endian binary
595  * with a flag in byte 0 to indicate this, which permits file sizes up to
596  * 2^64-1 (actually 2^80-1 but our file sizes are vlongs) rather than 2^33-1.
597  */
598 static Off
599 hdrsize(Blk *bp)
600 {
601         uchar *p;
602         char buf[Maxname + 1];
603
604         if((uchar)bp->size[0] == Binnegsz) {
605                 fprint(2, "%s: %s: negative length, which is insane\n",
606                         argv0, parsename(bp, buf, sizeof(buf)));
607                 return 0;
608         } else if((uchar)bp->size[0] == Binsize) {
609                 p = (uchar *)bp->size + sizeof bp->size - 1 -
610                         sizeof(vlong);          /* -1 for terminating space */
611                 return G8BEBYTE(p);
612         }
613
614         return hdrotoull(bp->size, bp->size + sizeof bp->size, 0,
615                 parsename(bp, buf, sizeof(buf)), "size");
616 }
617
618 /*
619  * return the number of bytes recorded in the archive.
620  */
621 static Off
622 arsize(Blk *bp, char *fname)
623 {
624         if(isdir(bp, fname) || islink(bp->linkflag))
625                 return 0;
626         return hdrsize(bp);
627 }
628
629 static long
630 parsecksum(char *cksum, char *name)
631 {
632         Blk *bp;
633
634         return hdrotoull(cksum, cksum + sizeof bp->chksum, (uvlong)-1LL,
635                 name, "checksum");
636 }
637
638 static Blk *
639 readhdrblk(int ar)
640 {
641         char buf[Maxname + 1];
642         long hdrcksum;
643         Blk *bp;
644
645         bp = getblkrd(ar, Alldata);
646         if (bp == nil)
647                 sysfatal("unexpected EOF instead of archive header in %s",
648                         arname);
649         if (eotar(bp))                  /* end-of-archive block? */
650                 return nil;
651
652         hdrcksum = parsecksum(bp->chksum, parsename(bp, buf, sizeof(buf)));
653         if (hdrcksum == -1 || chksum(bp) != hdrcksum) {
654                 if (!resync)
655                         sysfatal("bad archive header checksum in %s: "
656                                 "name %.100s...; expected %#luo got %#luo",
657                                 arname, bp->name, hdrcksum, chksum(bp));
658                 fprint(2, "%s: skipping past archive header with bad checksum in %s...",
659                         argv0, arname);
660                 do {
661                         bp = getblkrd(ar, Alldata);
662                         if (bp == nil)
663                                 sysfatal("unexpected EOF looking for archive header in %s",
664                                         arname);
665                         hdrcksum = parsecksum(bp->chksum, parsename(bp, buf, sizeof(buf)));
666                 } while (hdrcksum == -1 || chksum(bp) != hdrcksum);
667                 fprint(2, "found %s\n", parsename(bp, buf, sizeof(buf)));
668         }
669         nexthdr += Tblock*(1 + BYTES2TBLKS(hdrsize(bp)));
670
671         return bp;
672 }
673
674 static int
675 getname(int ar, Blk *bp, Hdr *hdr)
676 {
677         char buf[Maxlongname+1];
678         ulong blksleft, blksread;
679         char *p;
680         int n;
681
682         if (bp->linkflag != LF_LONGNAME){
683                 /* PAX attributes take precedence */
684                 if(hdr->name == nil)
685                         hdr->name = strdup(parsename(bp, buf, sizeof(buf)));
686                 return 0;
687         }
688
689         p = buf;
690         for (blksleft = BYTES2TBLKS(hdrsize(bp)); blksleft > 0; blksleft -= blksread) {
691                 bp = getblkrd(ar, Alldata);
692                 if (bp == nil)
693                         sysfatal("unexpected EOF on archive reading from %s", arname);
694                 blksread = gothowmany(blksleft);
695                 n = &buf[Maxlongname] - p;
696                 if(Tblock*blksread < n)
697                         n = Tblock*blksread;
698                 memmove(p, bp->data, n);
699                 p += n;
700         }
701         *p = '\0';
702         hdr->name = strdup(buf);
703         return 1;
704 }
705
706 static char *
707 matchattr(char *kvp, char *k)
708 {
709         if (strncmp(kvp, k, strlen(k)) == 0)
710                 return kvp + strlen(k);
711         return nil;
712 }
713
714 static int
715 parsepax(int ar, Blk *bp, Hdr *hdr, int paxtype)
716 {
717         char *p, *lp, *le, *e, *kvp, *val, lenbuf[16];
718         ulong blksleft;
719         int n, off, len;
720         Blk *b;
721
722         if (!isustar(bp) || bp->linkflag != paxtype)
723                 return 0;
724         off = 0;
725         len = -1;
726         kvp = nil;
727         lp = lenbuf;
728         le = lenbuf + sizeof(lenbuf);
729         for (blksleft = BYTES2TBLKS(hdrsize(bp)); blksleft > 0; ) {
730                 b = getblkrd(ar, Alldata);
731                 if (b == nil)
732                         sysfatal("unexpected EOF on archive reading attr for %s from %s",  bp->name, arname);
733                 p = (char *)b->data;
734                 e = (char *)b->data + sizeof(b->data);
735                 while(p != e) {
736                         if(*p == '\0')
737                                 break;
738                         /*
739                          * Copy out the length prefix. This may span a block boundary, so be
740                          * careful about when we get the next block. The length prefix includes
741                          * both its own length and the trailing newline. We want to trim the
742                          * length prefix, since we already consumed it.
743                          */
744                         if(len == -1){
745                                 while(p != e && *p >= '0' && *p <= '9'){
746                                         if(lp + 1 == le)
747                                                 sysfatal("oversize length prefix in pax header");
748                                         *lp++ = *p++;
749                                 }
750                                 if (p == e && blksleft > 0)
751                                         goto nextblk;
752                                 if (*p++ != ' ')
753                                         sysfatal("invalid delimiter in pax header: %c (%s)\n", *p, p);
754                                 *lp++ = '\0';
755                                 len = atoi(lenbuf) - strlen(lenbuf) - 1;
756                         }
757         
758                         if (kvp == nil && (kvp = malloc(len)) == nil)
759                                 sysfatal("out of memory: %r");
760                         n = (len - off > e - p) ? e - p : len - off;
761                         memcpy(kvp + off, p, n);
762                         kvp[len - 1] = '\0';
763                         off += n;
764                         p += n;
765                         assert(e >= p);
766                         if (len == off) {
767                                 if ((val = matchattr(kvp, "path=")) != nil) {
768                                         free(hdr->name);
769                                         hdr->name = strdup(val);
770                                 } else if ((val = matchattr(kvp, "linkpath=")) != nil) {
771                                         /* Mostly for better error messages. */
772                                         free(hdr->name);
773                                         hdr->name = strdup(val);
774                                 } else if ((val = matchattr(kvp, "uname=")) != nil) {
775                                         free(hdr->uid);
776                                         hdr->uid = strdup(val);
777                                 } else if ((val = matchattr(kvp, "gname=")) != nil) {
778                                         free(hdr->gid);
779                                         hdr->gid = strdup(val);
780                                 } else if ((val = matchattr(kvp, "atime=")) != nil)
781                                         hdr->atime = strtoll(val, nil, 0);
782                                 else if ((val = matchattr(kvp, "mtime=")) != nil)
783                                         hdr->mtime = strtoll(val, nil, 0);
784                                 else if ((val = matchattr(kvp, "size=")) != nil)
785                                         hdr->size = strtoll(val, nil, 0);
786                                 else
787                                         if (matchattr(kvp, "comment=") == nil && matchattr(kvp, "ctime=") == nil)
788                                                 fprint(2, "warning: pax attribute not supported: %s\n", kvp);
789                                 free(kvp);
790                                 kvp = nil;
791                                 lp = lenbuf;
792                                 off = 0;
793                                 len = -1;
794                         }
795                 }
796 nextblk:
797                 blksleft--;
798         }
799         return 1;
800 }
801
802 static int
803 parsehdr(Hdr *hdr, Blk *bp)
804 {
805         int ustar;
806
807         ustar = isustar(bp);
808         if(hdr->mode == -1)
809                 hdr->mode = (strtoul(bp->mode, nil, 8) & 0777);
810         if(hdr->mode == -1)
811                 hdr->mode = globlhdr.mode;
812         if (isdir(bp, hdr->name))
813                 hdr->mode |= DMDIR;
814         if (hdr->atime == -1)
815                 hdr->atime = -1;
816         if (hdr->atime == -1)
817                 hdr->atime = globlhdr.atime;
818         if (hdr->mtime == -1)
819                 hdr->mtime = strtol(bp->mtime, nil, 8);
820         if (hdr->mtime == -1)
821                 hdr->mtime = globlhdr.mtime;
822         if (hdr->size == -1)
823                 hdr->size = arsize(bp, hdr->name);
824         if (ustar && hdr->uid == nil)
825                 hdr->uid = strdup(bp->uname);
826         if (hdr->uid == nil)
827                 hdr->uid = (globlhdr.uid != nil) ? strdup(globlhdr.uid) : nil;
828         if (ustar && hdr->gid == nil)
829                 hdr->gid = strdup(bp->uname);
830         if (hdr->gid == nil)
831                 hdr->gid = (globlhdr.gid != nil) ? strdup(globlhdr.gid) : nil;
832         return 0;
833 }
834
835 static void
836 nullhdr(Hdr *hdr)
837 {
838         hdr->name = nil;
839         hdr->uid = nil;
840         hdr->gid = nil;
841         hdr->mode = -1;
842         hdr->mtime = -1;
843         hdr->atime = -1;
844         hdr->size = -1;
845 }
846
847 static Blk *
848 readhdr(int ar, Hdr *hdr)
849 {
850         Blk *bp;
851
852         nullhdr(hdr);
853 again:
854         if ((bp = readhdrblk(ar)) == nil)
855                 return nil;
856         if (parsepax(ar, bp, hdr, LF_PAXHDR))
857                 goto again;
858         if (parsepax(ar, bp, &globlhdr, LF_PAXGLOBL))
859                 goto again;
860         if (getname(ar, bp, hdr))
861                 goto again;
862         if (parsehdr(hdr, bp) == -1)
863                 sysfatal("could not parse header: %r");
864
865         return bp;
866 }
867
868 void
869 freehdr(Hdr *hdr)
870 {
871         free(hdr->name);
872         free(hdr->uid);
873         free(hdr->gid);
874 }
875
876 /*
877  * if name is longer than Namsiz bytes, try to split it at a slash and fit the
878  * pieces into bp->prefix and bp->name.
879  */
880 static int
881 putfullname(Blk *bp, char *name)
882 {
883         int namlen, pfxlen;
884         char *sl, *osl;
885         String *slname = nil;
886
887         if (isdir(bp, name)) {
888                 slname = s_new();
889                 s_append(slname, name);
890                 s_append(slname, "/");          /* posix requires this */
891                 name = s_to_c(slname);
892         }
893
894         namlen = strlen(name);
895         if (namlen <= Namsiz) {
896                 strncpy(bp->name, name, Namsiz);
897                 bp->prefix[0] = '\0';           /* ustar paranoia */
898                 return 0;
899         }
900
901         if (!posix || namlen > Maxname) {
902                 fprint(2, "%s: name too long for tar header: %s\n",
903                         argv0, name);
904                 return -1;
905         }
906         /*
907          * try various splits until one results in pieces that fit into the
908          * appropriate fields of the header.  look for slashes from right
909          * to left, in the hopes of putting the largest part of the name into
910          * bp->prefix, which is larger than bp->name.
911          */
912         sl = strrchr(name, '/');
913         while (sl != nil) {
914                 pfxlen = sl - name;
915                 if (pfxlen <= sizeof bp->prefix && namlen-1 - pfxlen <= Namsiz)
916                         break;
917                 osl = sl;
918                 *osl = '\0';
919                 sl = strrchr(name, '/');
920                 *osl = '/';
921         }
922         if (sl == nil) {
923                 fprint(2, "%s: name can't be split to fit tar header: %s\n",
924                         argv0, name);
925                 return -1;
926         }
927         *sl = '\0';
928         strncpy(bp->prefix, name, sizeof bp->prefix);
929         *sl++ = '/';
930         strncpy(bp->name, sl, sizeof bp->name);
931         if (slname)
932                 s_free(slname);
933         return 0;
934 }
935
936 static int
937 mkhdr(Blk *bp, Dir *dir, char *file)
938 {
939         int r;
940
941         /*
942          * some of these fields run together, so we format them left-to-right
943          * and don't use snprint.
944          */
945         sprint(bp->mode, "%6lo ", dir->mode & 0777);
946         sprint(bp->uid, "%6o ", aruid);
947         sprint(bp->gid, "%6o ", argid);
948         if (dir->length >= (Off)1<<32) {
949                 static int printed;
950
951                 if (!printed) {
952                         printed = 1;
953                         fprint(2, "%s: storing large sizes in \"base 256\"\n", argv0);
954                 }
955                 bp->size[0] = Binsize;
956                 /* emit so-called `base 256' representation of size */
957                 putbe((uchar *)bp->size+1, dir->length, sizeof bp->size - 2);
958                 bp->size[sizeof bp->size - 1] = ' ';
959         } else
960                 sprint(bp->size, "%11lluo ", dir->length);
961         sprint(bp->mtime, "%11luo ", dir->mtime);
962         bp->linkflag = (dir->mode&DMDIR? LF_DIR: LF_PLAIN1);
963         r = putfullname(bp, file);
964         if (posix) {
965                 strncpy(bp->magic, "ustar", sizeof bp->magic);
966                 strncpy(bp->version, "00", sizeof bp->version);
967                 strncpy(bp->uname, dir->uid, sizeof bp->uname);
968                 strncpy(bp->gname, dir->gid, sizeof bp->gname);
969         }
970         sprint(bp->chksum, "%6luo", chksum(bp));
971         return r;
972 }
973
974 static void addtoar(int ar, char *file, char *shortf);
975
976 static void
977 addtreetoar(int ar, char *file, char *shortf, int fd)
978 {
979         int n;
980         Dir *dent, *dirents;
981         String *name = s_new();
982
983         n = dirreadall(fd, &dirents);
984         if (n < 0)
985                 fprint(2, "%s: dirreadall %s: %r\n", argv0, file);
986         close(fd);
987         if (n <= 0)
988                 return;
989
990         if (chdir(shortf) < 0)
991                 sysfatal("chdir %s: %r", file);
992         if (Debug)
993                 fprint(2, "chdir %s\t# %s\n", shortf, file);
994
995         for (dent = dirents; dent < dirents + n; dent++) {
996                 s_reset(name);
997                 s_append(name, file);
998                 s_append(name, "/");
999                 s_append(name, dent->name);
1000                 addtoar(ar, s_to_c(name), dent->name);
1001         }
1002         s_free(name);
1003         free(dirents);
1004
1005         /*
1006          * this assumes that shortf is just one component, which is true
1007          * during directory descent, but not necessarily true of command-line
1008          * arguments.  Our caller (or addtoar's) must reset the working
1009          * directory if necessary.
1010          */
1011         if (chdir("..") < 0)
1012                 sysfatal("chdir %s/..: %r", file);
1013         if (Debug)
1014                 fprint(2, "chdir ..\n");
1015 }
1016
1017 static void
1018 addtoar(int ar, char *file, char *shortf)
1019 {
1020         int n, fd, isdir;
1021         long bytes, blksread;
1022         ulong blksleft;
1023         Blk *hbp;
1024         Dir *dir;
1025         String *name = nil;
1026
1027         if (shortf[0] == '#') {
1028                 name = s_new();
1029                 s_append(name, "./");
1030                 s_append(name, shortf);
1031                 shortf = s_to_c(name);
1032         }
1033
1034         if (Debug)
1035                 fprint(2, "opening %s   # %s\n", shortf, file);
1036         fd = open(shortf, OREAD);
1037         if (fd < 0) {
1038                 fprint(2, "%s: can't open %s: %r\n", argv0, file);
1039                 if (name)
1040                         s_free(name);
1041                 return;
1042         }
1043         dir = dirfstat(fd);
1044         if (dir == nil)
1045                 sysfatal("can't fstat %s: %r", file);
1046
1047         hbp = getblkz(ar);
1048         isdir = (dir->qid.type & QTDIR) != 0;
1049         if (mkhdr(hbp, dir, file) < 0) {
1050                 putbackblk(ar);
1051                 free(dir);
1052                 close(fd);
1053                 if (name)
1054                         s_free(name);
1055                 return;
1056         }
1057         putblk(ar);
1058
1059         blksleft = BYTES2TBLKS(dir->length);
1060         free(dir);
1061
1062         if (isdir)
1063                 addtreetoar(ar, file, shortf, fd);
1064         else {
1065                 for (; blksleft > 0; blksleft -= blksread) {
1066                         hbp = getblke(ar);
1067                         blksread = gothowmany(blksleft);
1068                         assert(blksread >= 0);
1069                         bytes = blksread * Tblock;
1070                         n = ereadn(file, fd, hbp->data, bytes);
1071                         assert(n >= 0);
1072                         /*
1073                          * ignore EOF.  zero any partial block to aid
1074                          * compression and emergency recovery of data.
1075                          */
1076                         if (n < Tblock)
1077                                 memset(hbp->data + n, 0, bytes - n);
1078                         putblkmany(ar, blksread);
1079                 }
1080                 close(fd);
1081                 if (verbose)
1082                         fprint(2, "%s\n", file);
1083         }
1084         if (name)
1085                 s_free(name);
1086 }
1087
1088 static char *
1089 replace(char **argv)
1090 {
1091         int i, ar;
1092         ulong blksleft, blksread;
1093         Off bytes;
1094         Blk *bp;
1095         Compress *comp = nil;
1096         Pushstate ps;
1097
1098         if (usefile && docreate)
1099                 ar = create(usefile, OWRITE, 0666);
1100         else if (usefile)
1101                 ar = open(usefile, ORDWR);
1102         else
1103                 ar = Stdout;
1104         if (docreate && docompress) {
1105                 comp = compmethod(usefile);
1106                 if (comp)
1107                         ar = push(ar, comp->comp, Output, &ps);
1108         }
1109         if (ar < 0)
1110                 sysfatal("can't open archive %s: %r", usefile);
1111
1112         if (usefile && !docreate) {
1113                 /* skip quickly to the end */
1114                 while ((bp = readhdrblk(ar)) != nil) {
1115                         bytes = hdrsize(bp);
1116                         for (blksleft = BYTES2TBLKS(bytes);
1117                              blksleft > 0 && getblkrd(ar, Justnxthdr) != nil;
1118                              blksleft -= blksread) {
1119                                 blksread = gothowmany(blksleft);
1120                                 putreadblks(ar, blksread);
1121                         }
1122                 }
1123                 /*
1124                  * we have just read the end-of-archive Tblock.
1125                  * now seek back over the (big) archive block containing it,
1126                  * and back up curblk ptr over end-of-archive Tblock in memory.
1127                  */
1128                 if (seek(ar, blkoff, 0) < 0)
1129                         sysfatal("can't seek back over end-of-archive in %s: %r",
1130                                 arname);
1131                 curblk--;
1132         }
1133
1134         for (i = 0; argv[i] != nil; i++) {
1135                 addtoar(ar, argv[i], argv[i]);
1136                 chdir(origdir);         /* for correctness & profiling */
1137         }
1138
1139         /* write end-of-archive marker */
1140         getblkz(ar);
1141         putblk(ar);
1142         getblkz(ar);
1143         putlastblk(ar);
1144
1145         if (comp)
1146                 return pushclose(&ps);
1147         if (ar > Stderr)
1148                 close(ar);
1149         return nil;
1150 }
1151
1152 /*
1153  * tar [xt]
1154  */
1155
1156 /* is pfx a file-name prefix of name? */
1157 static int
1158 prefix(char *name, char *pfx)
1159 {
1160         char clpfx[Maxlongname+1];
1161         int pfxlen = strlen(pfx);
1162
1163         clpfx[Maxlongname] = '\0';
1164         strncpy(clpfx, pfx, Maxlongname);
1165         cleanname(clpfx);
1166         return strncmp(clpfx, name, pfxlen) == 0 &&
1167                 (name[pfxlen] == '\0' || name[pfxlen] == '/');
1168 }
1169
1170 static int
1171 match(char *name, char **argv)
1172 {
1173         char clname[Maxlongname+1];
1174         int i;
1175
1176         if (argv[0] == nil)
1177                 return 1;
1178         clname[Maxlongname] = '\0';
1179         strncpy(clname, name, Maxlongname);
1180         cleanname(clname);
1181         for (i = 0; argv[i] != nil; i++)
1182                 if (prefix(clname, argv[i]))
1183                         return 1;
1184         return 0;
1185 }
1186
1187 static void
1188 cantcreate(char *s, int mode)
1189 {
1190         int len;
1191         static char *last;
1192
1193         /*
1194          * Always print about files.  Only print about directories
1195          * we haven't printed about.  (Assumes archive is ordered
1196          * nicely.)
1197          */
1198         if(mode&DMDIR){
1199                 if(last){
1200                         /* already printed this directory */
1201                         if(strcmp(s, last) == 0)
1202                                 return;
1203                         /* printed a higher directory, so printed this one */
1204                         len = strlen(s);
1205                         if(memcmp(s, last, len) == 0 && last[len] == '/')
1206                                 return;
1207                 }
1208                 /* save */
1209                 free(last);
1210                 last = strdup(s);
1211         }
1212         fprint(2, "%s: can't create %s: %r\n", argv0, s);
1213 }
1214
1215 static int
1216 makedir(char *s)
1217 {
1218         int f;
1219
1220         if (access(s, AEXIST) == 0)
1221                 return -1;
1222         f = create(s, OREAD, DMDIR | 0777);
1223         if (f >= 0)
1224                 close(f);
1225         else
1226                 cantcreate(s, DMDIR);
1227         return f;
1228 }
1229
1230 static int
1231 mkpdirs(char *s)
1232 {
1233         int err;
1234         char *p;
1235
1236         p = s;
1237         err = 0;
1238         while (!err && (p = strchr(p+1, '/')) != nil) {
1239                 *p = '\0';
1240                 err = (access(s, AEXIST) < 0 && makedir(s) < 0);
1241                 *p = '/';
1242         }
1243         return -err;
1244 }
1245
1246 /* Call access but preserve the error string. */
1247 static int
1248 xaccess(char *name, int mode)
1249 {
1250         char err[ERRMAX];
1251         int rv;
1252
1253         err[0] = 0;
1254         errstr(err, sizeof err);
1255         rv = access(name, mode);
1256         errstr(err, sizeof err);
1257         return rv;
1258 }
1259
1260 static int
1261 openfname(Blk *bp, char *fname, int mode)
1262 {
1263         int fd, dir;
1264
1265         fd = -1;
1266         dir = mode & DMDIR;
1267         cleanname(fname);
1268         switch (bp->linkflag) {
1269         case LF_LINK:
1270         case LF_SYMLINK1:
1271         case LF_SYMLINK2:
1272         case LF_LONGLINK:
1273                 fprint(2, "%s: can't make (sym)link %s\n",
1274                         argv0, fname);
1275                 break;
1276         case LF_FIFO:
1277                 fprint(2, "%s: can't make fifo %s\n", argv0, fname);
1278                 break;
1279         default:
1280                 if (!keepexisting || access(fname, AEXIST) < 0) {
1281                         int rw = (dir ? OREAD: OWRITE);
1282
1283                         fd = create(fname, rw, mode);
1284                         if (fd < 0) {
1285                                 mkpdirs(fname);
1286                                 fd = create(fname, rw, mode);
1287                         }
1288                         if (fd < 0 && (!dir || xaccess(fname, AEXIST) < 0))
1289                                 cantcreate(fname, mode);
1290                 }
1291                 if (fd >= 0 && verbose)
1292                         fprint(2, "%s\n", fname);
1293                 break;
1294         }
1295         return fd;
1296 }
1297
1298 /* copy from archive to file system (or nowhere for table-of-contents) */
1299 static void
1300 copyfromar(int ar, int fd, char *fname, ulong blksleft, Off bytes)
1301 {
1302         int wrbytes;
1303         ulong blksread;
1304         Blk *hbp;
1305
1306         if (blksleft == 0 || bytes < 0)
1307                 bytes = 0;
1308         for (; blksleft > 0; blksleft -= blksread) {
1309                 hbp = getblkrd(ar, (fd >= 0? Alldata: Justnxthdr));
1310                 if (hbp == nil)
1311                         sysfatal("unexpected EOF on archive extracting %s from %s",
1312                                 fname, arname);
1313                 blksread = gothowmany(blksleft);
1314                 if (blksread <= 0) {
1315                         fprint(2, "%s: got %ld blocks reading %s!\n",
1316                                 argv0, blksread, fname);
1317                         blksread = 0;
1318                 }
1319                 wrbytes = Tblock*blksread;
1320                 assert(bytes >= 0);
1321                 if(wrbytes > bytes)
1322                         wrbytes = bytes;
1323                 assert(wrbytes >= 0);
1324                 if (fd >= 0)
1325                         ewrite(fname, fd, hbp->data, wrbytes);
1326                 putreadblks(ar, blksread);
1327                 bytes -= wrbytes;
1328                 assert(bytes >= 0);
1329         }
1330         if (bytes > 0)
1331                 fprint(2, "%s: %lld bytes uncopied at EOF on archive %s; "
1332                         "%s not fully extracted\n", argv0, bytes, arname, fname);
1333 }
1334
1335 static void
1336 wrmeta(int fd, Hdr *hdr)                /* update metadata */
1337 {
1338         Dir nd;
1339
1340         nulldir(&nd);
1341         nd.mtime = hdr->mtime;
1342         nd.mode = hdr->mode;
1343         dirfwstat(fd, &nd);
1344         if (hdr->gid) {
1345                 nulldir(&nd);
1346                 nd.gid = hdr->gid;
1347                 dirfwstat(fd, &nd);
1348         }
1349         if (hdr->uid){
1350                 nulldir(&nd);
1351                 nd.uid = hdr->uid;
1352                 dirfwstat(fd, &nd);
1353         }
1354 }
1355
1356 /*
1357  * copy a file from the archive into the filesystem.
1358  * fname is result of getname(), so has two extra bytes at beginning.
1359  */
1360 static void
1361 extract1(int ar, Blk *bp, Hdr *hdr)
1362 {
1363         int fd = -1;
1364         Off bytes = hdr->size;          /* for printing */
1365         uvlong blksleft = BYTES2TBLKS(bytes);
1366         char *path;
1367
1368         /* fiddle name, figure out mode and blocks */
1369         switch (bp->linkflag) {
1370         case LF_LINK:
1371         case LF_SYMLINK1:
1372         case LF_SYMLINK2:
1373         case LF_FIFO:
1374                 blksleft = 0;
1375                 break;
1376         }
1377         if((path = malloc(strlen(hdr->name) + 3)) == nil)
1378                 sysfatal("malloc: %r");
1379         if (relative && hdr->name[0] == '/')
1380                 strcpy(path, ".");
1381         else if(relative && hdr->name[0] == '#')
1382                 strcpy(path, "./");
1383         else
1384                 path[0] = '\0';
1385         strcat(path, hdr->name);
1386
1387         if (verb == Xtract)
1388                 fd = openfname(bp, path, hdr->mode);
1389         else if (verbose) {
1390                 char *cp = ctime(hdr->mtime);
1391
1392                 print("%M %8lld  %-12.12s %-4.4s %s\n",
1393                         hdr->mode, bytes, cp+4, cp+24, path);
1394         } else
1395                 print("%s\n", path);
1396
1397         copyfromar(ar, fd, path, blksleft, hdr->size);
1398
1399         /* touch up meta data and close */
1400         if (fd >= 0) {
1401                 /*
1402                  * directories should be wstated *after* we're done
1403                  * creating files in them, but we don't do that.
1404                  */
1405                 if (settime)
1406                         wrmeta(fd, hdr);
1407                 close(fd);
1408         }
1409         free(path);
1410 }
1411
1412 static void
1413 skip(int ar, Blk *bp, Hdr *hdr)
1414 {
1415         ulong blksleft, blksread;
1416         Blk *hbp;
1417
1418         for (blksleft = BYTES2TBLKS(arsize(bp, hdr->name)); blksleft > 0;
1419              blksleft -= blksread) {
1420                 hbp = getblkrd(ar, Justnxthdr);
1421                 if (hbp == nil)
1422                         sysfatal("unexpected EOF on archive extracting %s from %s",
1423                                 hdr->name, arname);
1424                 blksread = gothowmany(blksleft);
1425                 putreadblks(ar, blksread);
1426         }
1427 }
1428
1429 static char *
1430 extract(char **argv)
1431 {
1432         int ar;
1433         Blk *bp;
1434         Hdr hdr;
1435         Compress *comp;
1436         Pushstate ps;
1437
1438         if (usefile)
1439                 ar = open(usefile, OREAD);
1440         else
1441                 ar = Stdin;
1442         comp = compmethod(usefile);
1443         if (comp)
1444                 ar = push(ar, comp->decomp, Input, &ps);
1445         if (ar < 0)
1446                 sysfatal("can't open archive %s: %r", usefile);
1447
1448         while ((bp = readhdr(ar, &hdr)) != nil) {
1449                 if (match(hdr.name, argv))
1450                         extract1(ar, bp, &hdr);
1451                 else
1452                         skip(ar, bp, &hdr);
1453                 freehdr(&hdr);
1454         }
1455
1456         if (comp)
1457                 return pushclose(&ps);
1458         if (ar > Stderr)
1459                 close(ar);
1460         return nil;
1461 }
1462
1463 void
1464 main(int argc, char *argv[])
1465 {
1466         int errflg = 0;
1467         char *ret = nil;
1468
1469         fmtinstall('M', dirmodefmt);
1470
1471         TARGBEGIN {
1472         case 'c':
1473                 docreate++;
1474                 verb = Replace;
1475                 break;
1476         case 'f':
1477                 usefile = arname = EARGF(usage());
1478                 break;
1479         case 'g':
1480                 argid = strtoul(EARGF(usage()), 0, 0);
1481                 break;
1482         case 'i':
1483                 ignerrs = 1;
1484                 break;
1485         case 'k':
1486                 keepexisting++;
1487                 break;
1488         case 'm':       /* compatibility */
1489                 settime = 0;
1490                 break;
1491         case 'p':
1492                 posix++;
1493                 break;
1494         case 'P':
1495                 posix = 0;
1496                 break;
1497         case 'r':
1498                 verb = Replace;
1499                 break;
1500         case 'R':
1501                 relative = 0;
1502                 break;
1503         case 's':
1504                 resync++;
1505                 break;
1506         case 't':
1507                 verb = Toc;
1508                 break;
1509         case 'T':
1510                 settime++;
1511                 break;
1512         case 'u':
1513                 aruid = strtoul(EARGF(usage()), 0, 0);
1514                 break;
1515         case 'v':
1516                 verbose++;
1517                 break;
1518         case 'x':
1519                 verb = Xtract;
1520                 break;
1521         case 'z':
1522                 docompress++;
1523                 break;
1524         case '-':
1525                 break;
1526         default:
1527                 fprint(2, "tar: unknown letter %C\n", TARGC());
1528                 errflg++;
1529                 break;
1530         } TARGEND
1531
1532         if (argc < 0 || errflg)
1533                 usage();
1534
1535         initblks();
1536         nullhdr(&globlhdr);
1537         switch (verb) {
1538         case Toc:
1539         case Xtract:
1540                 ret = extract(argv);
1541                 break;
1542         case Replace:
1543                 if (getwd(origdir, sizeof origdir) == nil)
1544                         strcpy(origdir, "/tmp");
1545                 ret = replace(argv);
1546                 break;
1547         default:
1548                 usage();
1549                 break;
1550         }
1551         exits(ret);
1552 }