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