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