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