1
2
3/* taken from: https://github.com/michaelforney/pax */
4#ifndef _GNU_SOURCE
5#define _GNU_SOURCE /* needed for major/minor (non-posix) */
6#endif
7
8#include "arg.h"
9
10#include <assert.h>
11#include <cpio.h>
12#include <ctype.h>
13#include <dirent.h>
14#include <errno.h>
15#include <fcntl.h>
16#include <fnmatch.h>
17#include <grp.h>
18#include <limits.h>
19#include <pwd.h>
20#include <regex.h>
21#include <spawn.h>
22#include <stdarg.h>
23#include <stdint.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <sys/stat.h>
28#include <sys/sysmacros.h>
29#include <sys/types.h>
30#include <sys/uio.h>
31#include <sys/wait.h>
32#include <tar.h>
33#include <time.h>
34#include <unistd.h>
35
36#ifndef O_SEARCH /* not present on some bsds */
37#define O_SEARCH 0
38#endif
39
40#if __APPLE__ /* macos lacks st_*tim from posix.1-2008 */
41#define st_atim st_atimespec
42#define st_ctim st_ctimespec
43#define st_mtim st_mtimespec
44#endif
45
46#ifndef HAVE_REALLOCARRAY
47static void *
48pax_reallocarray(void *p, size_t n, size_t m)
49{
50 if (m && n > SIZE_MAX / m) {
51 errno = ENOMEM;
52 return NULL;
53 }
54 return realloc(p, n * m);
55}
56#undef reallocarray
57#define reallocarray pax_reallocarray
58#endif
59
60#ifndef HAVE_PIPE2
61static int
62pax_pipe2(int fd[2], int flag)
63{
64 assert((flag | O_CLOEXEC) == O_CLOEXEC);
65 if (pipe(fd) != 0)
66 return -1;
67 if (flag & O_CLOEXEC
68 && (fcntl(fd[0], F_SETFD, FD_CLOEXEC) != 0 || fcntl(fd[1], F_SETFD, FD_CLOEXEC) != 0))
69 return -1;
70 return 0;
71}
72#undef pipe2
73#define pipe2 pax_pipe2
74#endif
75
76#define LEN(a) (sizeof(a) / sizeof *(a))
77#define ROUNDUP(x, a) (((x) + ((a) - 1)) & ~((a) - 1))
78#define MAXTIME 077777777777
79#define MAXSIZE 077777777777
80#define MAXUGID 07777777
81
82enum mode {
83 LIST,
84 READ,
85 WRITE,
86 COPY,
87};
88
89enum format {
90 CPIO,
91 PAX,
92 USTAR,
93 GNUTAR,
94 V7,
95};
96
97enum field {
98 ATIME = 1 << 0,
99 CTIME = 1 << 1,
100 GID = 1 << 2,
101 GNAME = 1 << 3,
102 LINKPATH = 1 << 4,
103 MODE = 1 << 5,
104 MTIME = 1 << 6,
105 PATH = 1 << 7,
106 SIZE = 1 << 8,
107 UID = 1 << 9,
108 UNAME = 1 << 10,
109};
110
111struct keyword {
112 const char *name;
113 enum field field;
114};
115
116struct strbuf {
117 char *str;
118 size_t len, cap;
119};
120
121struct header {
122 /* keywords present in this header */
123 enum field fields;
124 /* keywords ignored because they were overridden by an option */
125 enum field delete;
126
127 char type;
128
129 char *path;
130 size_t pathlen;
131 dev_t dev;
132 ino_t ino;
133 mode_t mode;
134 uid_t uid;
135 gid_t gid;
136 nlink_t nlink;
137 dev_t rdev;
138 off_t size;
139 struct timespec atime, mtime, ctime;
140 char *link;
141 size_t linklen;
142 char *uname;
143 char *gname;
144
145 struct strbuf pathbuf;
146 struct strbuf linkbuf;
147 struct strbuf unamebuf;
148 struct strbuf gnamebuf;
149
150 /* tar-specific, pre-calculated split point between name and prefix */
151 char *slash;
152 /* read this data instead of stdin */
153 char *data;
154 /* source file path and flags for hard link (-l flag) */
155 char *file;
156 struct timespec fileatime;
157 int flag;
158};
159
160struct account {
161 char *name;
162 enum field type;
163 uid_t uid;
164 gid_t gid;
165};
166
167struct bufio {
168 int fd, err;
169 off_t off;
170 char buf[64 * 1024];
171 char *pos, *end;
172};
173
174struct replstr {
175 regex_t old;
176 char *new;
177 int global;
178 int print;
179 int symlink;
180 struct replstr *next;
181};
182
183struct file {
184 size_t namelen;
185 size_t pathlen;
186 dev_t dev;
187 struct file *next;
188 char name[];
189};
190
191struct filelist {
192 FILE *input;
193 struct file *pending;
194};
195
196typedef int readfn(struct bufio *, struct header *);
197typedef void writefn(FILE *, struct header *);
198
199static int exitstatus;
200static int aflag;
201static int cflag;
202static int dflag;
203static int iflag;
204static int kflag;
205static int lflag;
206static int nflag;
207static int tflag;
208static int uflag;
209static int vflag;
210static int Xflag;
211static int follow;
212static int preserve = ATIME | MTIME;
213static const struct keyword keywords[] = {
214 {"atime", ATIME},
215 {"ctime", CTIME},
216 {"gid", GID},
217 {"gname", GNAME},
218 {"linkpath", LINKPATH},
219 {"mtime", MTIME},
220 {"path", PATH},
221 {"size", SIZE},
222 {"uid", UID},
223 {"uname", UNAME},
224};
225static struct {
226 enum field delete;
227 int linkdata;
228 const char *listopt;
229 const char *exthdrname;
230 const char *globexthdrname;
231 const char *invalid;
232 int times;
233} opt;
234static struct header exthdr, globexthdr;
235static struct replstr *replstr;
236static time_t curtime;
237static char **pats;
238static size_t patslen;
239static int *patsused;
240static struct filelist files;
241static struct bufio bioin;
242static char *dest = "";
243static int destfd = AT_FDCWD;
244
245static void
246fatal(const char *fmt, ...)
247{
248 va_list ap;
249
250 if (fmt) {
251 va_start(ap, fmt);
252 vfprintf(stderr, fmt, ap);
253 va_end(ap);
254 if (fmt[0] && fmt[strlen(fmt) - 1] == ':') {
255 fputc(' ', stderr);
256 perror(NULL);
257 } else {
258 fputc('\n', stderr);
259 }
260 } else {
261 perror(NULL);
262 }
263 exit(1);
264}
265
266static char *
267sbufalloc(struct strbuf *b, size_t n, size_t a)
268{
269 char *s;
270
271 if (n > b->cap - b->len) {
272 if (n > SIZE_MAX - a || n + a > SIZE_MAX - b->len)
273 fatal("path is too long");
274 b->cap = ROUNDUP(n, a);
275 s = malloc(b->cap);
276 if (!s)
277 fatal(NULL);
278 if (b->len)
279 memcpy(s, b->str, b->len);
280 free(b->str);
281 b->str = s;
282 }
283 return b->str + b->len;
284}
285
286static int
287sbuffmtv(struct strbuf *b, size_t a, const char *fmt, va_list ap)
288{
289 va_list aptmp;
290 int n;
291
292 va_copy(aptmp, ap);
293 n = vsnprintf(b->str ? b->str + b->len : NULL, b->cap - b->len, fmt, aptmp);
294 va_end(aptmp);
295 if (n < 0)
296 fatal("vsnprintf:");
297 if ((size_t)n >= b->cap - b->len) {
298 sbufalloc(b, (size_t)n + 1, a);
299 n = vsnprintf(b->str + b->len, b->cap - b->len, fmt, ap);
300 if (n < 0)
301 fatal("vsnprintf:");
302 if ((size_t)n >= b->cap - b->len)
303 fatal("vsnprintf: formatted size changed");
304 }
305 b->len += n;
306 return n;
307}
308
309static int
310sbuffmt(struct strbuf *b, size_t a, const char *fmt, ...)
311{
312 va_list ap;
313 int n;
314
315 va_start(ap, fmt);
316 n = sbuffmtv(b, a, fmt, ap);
317 va_end(ap);
318 return n;
319}
320
321static void
322sbufcat(struct strbuf *b, const char *s, size_t n, size_t a)
323{
324 char *d;
325
326 d = sbufalloc(b, n + 1, a);
327 memcpy(d, s, n);
328 d[n] = 0;
329 b->len += n;
330}
331
332static void
333bioinit(struct bufio *f, int fd)
334{
335 f->fd = fd;
336 f->pos = f->end = f->buf;
337 f->off = 0;
338}
339
340static size_t
341bioread(struct bufio *f, void *p, size_t n)
342{
343 size_t l;
344 unsigned char *d;
345 struct iovec iov[2];
346 ssize_t r;
347
348 d = p;
349 if (f->pos != f->end) {
350 l = f->end - f->pos;
351 if (n < l)
352 l = n;
353 memcpy(d, f->pos, l);
354 f->pos += l;
355 n -= l;
356 d += l;
357 }
358 iov[1].iov_base = f->buf;
359 iov[1].iov_len = sizeof f->buf;
360 for (; n > 0; n -= r, d += r) {
361 iov[0].iov_base = d;
362 iov[0].iov_len = n;
363 r = readv(f->fd, iov, 2);
364 if (r < 0)
365 f->err = errno;
366 if (r <= 0)
367 break;
368 if ((size_t)r >= n) {
369 f->pos = f->buf;
370 f->end = f->buf + (r - n);
371 r = n;
372 }
373 }
374 l = d - (unsigned char *)p;
375 f->off += l;
376 return l;
377}
378
379static int
380bioskip(struct bufio *f, off_t n)
381{
382 static int seekfail;
383 size_t l;
384 ssize_t r;
385
386 if (f->pos != f->end) {
387 l = f->end - f->pos;
388 if (n < (off_t)l) {
389 f->pos += n;
390 return 0;
391 }
392 n -= l;
393 f->pos = f->end = f->buf;
394 }
395 if (!seekfail) {
396 if (n == 0 || lseek(f->fd, n, SEEK_CUR) >= 0)
397 return 0;
398 seekfail = 1;
399 }
400 for (; n > 0; n -= r) {
401 l = sizeof f->buf;
402 if (n < (off_t)l)
403 l = n;
404 r = read(f->fd, f->buf, l);
405 if (r <= 0)
406 return -1;
407 }
408 return 0;
409}
410
411static void
412copyblock(char *b, struct bufio *r, size_t nr, FILE *w, size_t nw)
413{
414 if (bioread(r, b, nr) != nr) {
415 if (r->err)
416 fatal("read: %s", strerror(r->err));
417 fatal("archive truncated");
418 }
419 if (nw > nr)
420 memset(b + nr, 0, nw - nr);
421 if (nw && fwrite(b, 1, nw, w) != nw)
422 fatal("write:");
423}
424
425/* nr and nw must differ by at most 8192 */
426static void
427copy(struct bufio *r, off_t nr, FILE *w, off_t nw)
428{
429 char b[8192];
430
431 assert(nr - nw <= (off_t)sizeof b || nw - nr <= (off_t)sizeof b);
432 for (; nr > (off_t)sizeof b && nw > (off_t)sizeof b; nr -= (off_t)sizeof b, nw -= (off_t)sizeof b)
433 copyblock(b, r, sizeof b, w, sizeof b);
434 copyblock(b, r, nr, w, nw);
435}
436
437static struct account *
438findaccount(const char *name, uid_t uid, gid_t gid)
439{
440 static struct account *accts;
441 static size_t acctslen;
442 struct account *a;
443
444 for (a = accts; a < accts + acctslen; ++a) {
445 if ((uid == (uid_t)-1 || uid == a->uid) && (gid == (gid_t)-1 || gid == a->gid)
446 && (!name || (a->name && strcmp(a->name, name) == 0)))
447 return a;
448 }
449 if ((acctslen & (acctslen - 1)) == 0) {
450 accts = reallocarray(accts, acctslen ? acctslen * 2 : 16, sizeof *accts);
451 if (!accts)
452 fatal(NULL);
453 }
454 a = &accts[acctslen++];
455 a->name = NULL;
456 a->type = 0;
457 a->uid = -1;
458 a->gid = -1;
459 if (name) {
460 a->name = strdup(name);
461 if (!a->name)
462 fatal(NULL);
463 }
464 return a;
465}
466
467static uid_t
468unametouid(const char *uname, uid_t fallback)
469{
470 struct account *a;
471 struct passwd *pw;
472
473 if (!*uname)
474 return fallback;
475 a = findaccount(uname, (uid_t)-1, (gid_t)-1);
476 if (~a->type & UID) {
477 a->type |= UID;
478 pw = getpwnam(uname);
479 a->uid = pw ? pw->pw_uid : (uid_t)-1;
480 }
481 return a->uid != (uid_t)-1 ? a->uid : fallback;
482}
483
484static gid_t
485gnametogid(const char *gname, gid_t fallback)
486{
487 struct account *a;
488 struct group *gr;
489
490 if (!*gname)
491 return fallback;
492 a = findaccount(gname, (uid_t)-1, (gid_t)-1);
493 if (~a->type & GID) {
494 a->type |= GID;
495 gr = getgrnam(gname);
496 a->gid = gr ? gr->gr_gid : (gid_t)-1;
497 }
498 return a->gid != (gid_t)-1 ? a->gid : fallback;
499}
500
501static char *
502uidtouname(uid_t uid, char *fallback)
503{
504 struct account *a;
505 struct passwd *pw;
506
507 a = findaccount(NULL, uid, (gid_t)-1);
508 if (~a->type & UID) {
509 a->type |= UID;
510 a->uid = uid;
511 assert(!a->name);
512 pw = getpwuid(uid);
513 if (pw) {
514 a->name = strdup(pw->pw_name);
515 if (!a->name)
516 fatal(NULL);
517 }
518 }
519 return a->name ? a->name : fallback;
520}
521
522static char *
523gidtogname(gid_t gid, char *fallback)
524{
525 struct account *a;
526 struct group *gr;
527
528 a = findaccount(NULL, (uid_t)-1, gid);
529 if (~a->type & GID) {
530 a->type |= GID;
531 a->gid = gid;
532 assert(!a->name);
533 gr = getgrgid(gid);
534 if (gr) {
535 a->name = strdup(gr->gr_name);
536 if (!a->name)
537 fatal(NULL);
538 }
539 }
540 return a->name ? a->name : fallback;
541}
542
543static unsigned long long
544octnum(const char *str, size_t len)
545{
546 const char *end;
547 unsigned c;
548 unsigned long long n;
549
550 n = 0;
551 end = str + len;
552 /* some archives have leading spaces, so skip them */
553 for (; str != end && *str == ' '; ++str)
554 ;
555 for (; str != end; ++str) {
556 c = *str;
557 if (c == ' ' || c == '\0')
558 break;
559 c -= '0';
560 if (c > 7)
561 fatal("invalid number field");
562 n = n * 8 + c;
563 }
564 return n;
565}
566
567static unsigned long long
568decnum(const char *str, size_t len, char **pos)
569{
570 const char *end;
571 unsigned c;
572 unsigned long long n;
573
574 n = 0;
575 end = str + len;
576 for (; str != end; ++str) {
577 c = *str - '0';
578 if (c > 9)
579 break;
580 n = n * 10 + c;
581 }
582 if (pos)
583 *pos = (char *)str;
584 return n;
585}
586
587static int
588readustar(struct bufio *f, struct header *h)
589{
590 static char buf[512];
591 static off_t end;
592 size_t namelen, prefixlen, linklen;
593 unsigned long sum;
594 int i;
595 enum format format;
596
597 assert(bioin.off <= end);
598 if (bioskip(f, end - bioin.off) != 0 || bioread(f, buf, sizeof buf) != sizeof buf) {
599 if (f->err)
600 fatal("read: %s", strerror(f->err));
601 fatal("archive truncated");
602 }
603 sum = 0;
604 for (i = 0; i < 512; ++i)
605 sum += ((unsigned char *)buf)[i];
606 if (sum == 0)
607 return 0;
608 for (i = 148; i < 156; ++i)
609 sum += ' ' - ((unsigned char *)buf)[i];
610 if (sum != octnum(buf + 148, 8))
611 fatal("invalid tar header: bad checksum");
612 if (memcmp(
613 buf + 257,
614 "ustar\0"
615 "00",
616 8
617 )
618 == 0)
619 format = USTAR;
620 else if (memcmp(buf + 257, "ustar ", 8) == 0)
621 format = GNUTAR;
622 else
623 format = V7;
624 h->fields = PATH | UID | GID | SIZE;
625 namelen = strnlen(buf, 100);
626 prefixlen = format == USTAR ? strnlen(buf + 345, 155) : 0;
627 if (namelen == 100 || prefixlen > 0) {
628 h->pathbuf.len = 0;
629 if (prefixlen > 0) {
630 sbufcat(&h->pathbuf, buf + 345, prefixlen, 1024);
631 sbufcat(&h->pathbuf, "/", 1, 1024);
632 }
633 sbufcat(&h->pathbuf, buf, namelen, 1024);
634 h->path = h->pathbuf.str;
635 h->pathlen = h->pathbuf.len;
636 } else {
637 h->path = buf;
638 h->pathlen = namelen;
639 }
640 h->dev = 0;
641 h->ino = 0;
642 h->mode = octnum(buf + 100, 8);
643 h->uid = octnum(buf + 108, 8);
644 h->gid = octnum(buf + 116, 8);
645 h->nlink = 1;
646 h->size = octnum(buf + 124, 12);
647 end = bioin.off + ROUNDUP(h->size, 512);
648 h->mtime = (struct timespec){.tv_sec = octnum(buf + 136, 12)};
649 if (format == GNUTAR) {
650 h->fields |= ATIME | CTIME;
651 h->atime = (struct timespec){.tv_sec = octnum(buf + 345, 12)};
652 h->ctime = (struct timespec){.tv_sec = octnum(buf + 357, 12)};
653 }
654 h->type = buf[156];
655 if (h->type == AREGTYPE)
656 h->type = REGTYPE;
657
658 linklen = strnlen(buf + 157, 100);
659 if (linklen > 0)
660 h->fields |= LINKPATH;
661 if (linklen == 100) {
662 h->linkbuf.len = 0;
663 sbufcat(&h->linkbuf, buf + 157, 100, 1024);
664 h->link = h->linkbuf.str;
665 h->linklen = h->linkbuf.len;
666 } else {
667 h->link = buf + 157;
668 }
669 h->linklen = linklen;
670 if (format == V7) {
671 h->uname = "";
672 h->gname = "";
673 } else {
674 h->fields |= UNAME | GNAME;
675 h->uname = buf + 265;
676 if (!memchr(h->uname, '\0', 32))
677 fatal("uname is not NUL-terminated");
678 h->gname = buf + 297;
679 if (!memchr(h->gname, '\0', 32))
680 fatal("gname is not NUL-terminated");
681 if (h->type == CHRTYPE || h->type == BLKTYPE) {
682 unsigned major, minor;
683
684 major = octnum(buf + 329, 8);
685 minor = octnum(buf + 337, 8);
686 h->rdev = makedev(major, minor);
687 }
688 }
689 return 1;
690}
691
692static void
693parsetime(struct timespec *ts, const char *field, const char *str, size_t len)
694{
695 const char *end = str + len;
696 char *pos;
697 unsigned long long subsec;
698 size_t sublen;
699
700 ts->tv_sec = decnum(str, len, &pos);
701 if (*pos == '.') {
702 str = ++pos;
703 subsec = decnum(str, end - str, &pos);
704 for (sublen = pos - str; sublen < 9; ++sublen)
705 subsec *= 10;
706 ts->tv_nsec = subsec % 1000000000;
707 }
708 if (pos != end)
709 fatal("invalid extended header: bad %s", field);
710}
711
712static void
713extkeyval(struct header *h, const char *key, const char *val, size_t vallen)
714{
715 enum field field;
716 char *end;
717 const struct keyword *kw;
718
719 field = 0;
720 for (kw = keywords; kw != keywords + LEN(keywords); ++kw) {
721 if (strcmp(key, kw->name) == 0) {
722 field = kw->field;
723 break;
724 }
725 }
726 if (!field) {
727 if (strcmp(key, "charset") == 0) {
728 } else if (strcmp(key, "comment") == 0) {
729 /* ignore */
730 } else if (strcmp(key, "hdrcharset") == 0) {
731 } else if (strncmp(key, "realtime.", 9) == 0) {
732 } else if (strncmp(key, "security.", 9) == 0) {
733 } else {
734 fprintf(stderr, "ignoring unknown keyword '%s'\n", key);
735 }
736 return;
737 }
738 if ((h->delete | opt.delete) & field)
739 return;
740
741 switch (field) {
742 case ATIME:
743 parsetime(&h->atime, "atime", val, vallen);
744 break;
745 case CTIME:
746 parsetime(&h->ctime, "ctime", val, vallen);
747 break;
748 case GID:
749 h->gid = decnum(val, vallen, &end);
750 if (end != val + vallen)
751 fatal("invalid extended header: bad gid");
752 break;
753 case GNAME:
754 h->gnamebuf.len = 0;
755 sbufcat(&h->gnamebuf, val, vallen, 256);
756 h->gname = h->gnamebuf.str;
757 break;
758 case LINKPATH:
759 h->linkbuf.len = 0;
760 sbufcat(&h->linkbuf, val, vallen, 1024);
761 h->link = h->linkbuf.str;
762 h->linklen = h->linkbuf.len;
763 break;
764 case MTIME:
765 parsetime(&h->mtime, "mtime", val, vallen);
766 break;
767 case PATH:
768 h->pathbuf.len = 0;
769 sbufcat(&h->pathbuf, val, vallen, 1024);
770 h->path = h->pathbuf.str;
771 h->pathlen = h->pathbuf.len;
772 break;
773 case SIZE:
774 h->size = decnum(val, vallen, &end);
775 if (end != val + vallen)
776 fatal("invalid extended header: bad size");
777 break;
778 case UID:
779 h->uid = decnum(val, vallen, &end);
780 if (end != val + vallen)
781 fatal("invalid extended header: bad uid");
782 break;
783 case UNAME:
784 h->unamebuf.len = 0;
785 sbufcat(&h->unamebuf, val, vallen, 256);
786 h->uname = h->unamebuf.str;
787 break;
788 default:
789 return;
790 }
791 h->fields |= field;
792}
793
794static void
795readexthdr(struct bufio *f, struct header *h, off_t len)
796{
797 static struct strbuf buf;
798 size_t reclen, vallen;
799 char *rec, *end, *key, *val;
800
801 if (len > (off_t)SIZE_MAX)
802 fatal("extended header is too large");
803 buf.len = 0;
804 sbufalloc(&buf, (size_t)len, 8192);
805 if (bioread(f, buf.str, (size_t)len) != (size_t)len) {
806 if (f->err)
807 fatal("read: %s", strerror(f->err));
808 fatal("archive truncated");
809 }
810 rec = buf.str;
811 while (len > 0) {
812 end = memchr(rec, '\n', len);
813 if (!end)
814 fatal(
815 "invalid extended header: record is missing "
816 "newline"
817 );
818 *end = '\0';
819 reclen = decnum(rec, (size_t)(end - rec), &key);
820 if (*key != ' ' || reclen != (unsigned long long)(end - rec + 1))
821 fatal("invalid extended header: invalid record");
822 ++key;
823 val = strchr(key, '=');
824 if (!val)
825 fatal("invalid extended header: record has no '='");
826 *val++ = '\0';
827 vallen = end - val;
828 extkeyval(h, key, val, vallen);
829 len -= reclen;
830 rec += reclen;
831 }
832}
833
834static void
835readgnuhdr(struct bufio *f, struct strbuf *b, off_t len)
836{
837 if (len > (off_t)(SIZE_MAX - 1))
838 fatal("GNU header is too large");
839 b->len = 0;
840 sbufalloc(b, (size_t)(len + 1), 1024);
841 if (bioread(f, b->str, (size_t)len) != (size_t)len) {
842 if (f->err)
843 fatal("read: %s", strerror(f->err));
844 fatal("archive truncated");
845 }
846 b->str[len] = '\0';
847 b->len = len;
848}
849
850static int
851readpax(struct bufio *f, struct header *h)
852{
853 exthdr.fields = exthdr.delete;
854 while (readustar(f, h)) {
855 switch (h->type) {
856 case 'g':
857 readexthdr(f, &globexthdr, h->size);
858 break;
859 // ?man -x: hex format or match whole lines
860 case 'x':
861 readexthdr(f, &exthdr, h->size);
862 break;
863 // ?man -L: specify option flag
864 case 'L':
865 if ((exthdr.delete | opt.delete) & PATH)
866 break;
867 readgnuhdr(f, &exthdr.pathbuf, h->size);
868 exthdr.path = exthdr.pathbuf.str;
869 exthdr.pathlen = exthdr.pathbuf.len;
870 exthdr.fields |= PATH;
871 break;
872 case 'K':
873 if ((exthdr.delete | opt.delete) & LINKPATH)
874 break;
875 readgnuhdr(f, &exthdr.linkbuf, h->size);
876 exthdr.link = exthdr.linkbuf.str;
877 exthdr.linklen = exthdr.linkbuf.len;
878 exthdr.fields |= LINKPATH;
879 break;
880 default:
881 return 1;
882 }
883 }
884 return 0;
885}
886
887static int
888readcpio(struct bufio *f, struct header *h)
889{
890 static off_t end;
891 unsigned long type;
892 char buf[76];
893
894 if (bioskip(f, end - bioin.off) != 0 || bioread(f, buf, sizeof buf) != sizeof buf) {
895 if (f->err)
896 fatal("read: %s", strerror(f->err));
897 fatal("archive truncated");
898 }
899 if (memcmp(buf, "070707", 6) != 0)
900 fatal("invalid cpio header: bad magic");
901 h->pathlen = octnum(buf + 59, 6);
902 if (h->pathlen == 0)
903 fatal("invalid cpio header: c_namesize is 0");
904 h->pathbuf.len = 0;
905 sbufalloc(&h->pathbuf, h->pathlen, 1024);
906 h->path = h->pathbuf.str;
907 if (bioread(f, h->path, h->pathlen) != h->pathlen) {
908 if (f->err)
909 fatal("read: %s", strerror(f->err));
910 fatal("archive truncated");
911 }
912 if (h->path[--h->pathlen] != '\0')
913 fatal("invalid cpio header: name is not NUL-terminated");
914 if (strcmp(h->path, "TRAILER!!!") == 0)
915 return 0;
916
917 h->fields = PATH | MODE | UID | GID | MTIME | SIZE;
918 h->dev = octnum(buf + 6, 6);
919 h->ino = octnum(buf + 12, 6);
920 type = octnum(buf + 18, 6);
921 h->mode = type & 07777;
922 type &= ~07777;
923 switch (type) {
924 case C_ISDIR:
925 h->type = DIRTYPE;
926 break;
927 case C_ISFIFO:
928 h->type = FIFOTYPE;
929 break;
930 case C_ISREG:
931 h->type = REGTYPE;
932 break;
933 case C_ISLNK:
934 h->type = SYMTYPE;
935 break;
936 case C_ISBLK:
937 h->type = BLKTYPE;
938 break;
939 case C_ISCHR:
940 h->type = CHRTYPE;
941 break;
942 default:
943 fatal(
944 "invalid cpio header: invalid or unsupported file type: "
945 "%#o",
946 type
947 );
948 }
949 h->uid = octnum(buf + 24, 6);
950 h->gid = octnum(buf + 30, 6);
951 h->nlink = octnum(buf + 36, 6);
952 h->rdev = octnum(buf + 42, 6);
953 h->mtime = (struct timespec){.tv_sec = octnum(buf + 48, 11)};
954 h->size = octnum(buf + 65, 11);
955 h->uname = "";
956 h->gname = "";
957 if (h->type == SYMTYPE) {
958 if (h->size > (off_t)(SIZE_MAX - 1))
959 fatal("symlink target is too long");
960 h->linklen = h->size;
961 h->linkbuf.len = 0;
962 h->link = sbufalloc(&h->linkbuf, h->linklen + 1, 1024);
963 if (bioread(f, h->link, h->linklen) != h->linklen) {
964 if (f->err)
965 fatal("read: %s", strerror(f->err));
966 fatal("archive truncated");
967 }
968 h->link[h->linklen] = '\0';
969 h->size = 0;
970 h->fields |= LINKPATH;
971 } else {
972 h->link = "";
973 h->linklen = 0;
974 }
975 end = bioin.off + h->size;
976 return 1;
977}
978
979static int
980decompress(const char *algo, int fd, pid_t *pid)
981{
982 extern char **environ;
983 posix_spawn_file_actions_t fa;
984 int p[2], err;
985 char *argv[3];
986
987 if (!algo)
988 return fd;
989 argv[0] = (char *)algo;
990 argv[1] = "-dc";
991 argv[2] = NULL;
992 if (pipe2(p, O_CLOEXEC) != 0)
993 fatal("pipe2:");
994 err = posix_spawn_file_actions_init(&fa);
995 if (err)
996 fatal("posix_spawn_file_actions_init: %s", strerror(errno));
997 err = posix_spawn_file_actions_adddup2(&fa, fd, 0);
998 if (err)
999 fatal("posix_spawn_file_actions_adddup2: %s", strerror(errno));
1000 err = posix_spawn_file_actions_adddup2(&fa, p[1], 1);
1001 if (err)
1002 fatal("posix_spawn_file_actions_adddup2: %s", strerror(errno));
1003 err = posix_spawnp(pid, algo, &fa, NULL, argv, environ);
1004 if (err)
1005 fatal("posix_spawnp %s: %s", algo, strerror(errno));
1006 close(p[1]);
1007 return p[0];
1008}
1009
1010static readfn *
1011detectformat(struct bufio *f, const char *algo, pid_t *pid)
1012{
1013 size_t l, i;
1014 ssize_t n;
1015 unsigned char *b;
1016
1017again:
1018 f->fd = decompress(algo, f->fd, pid);
1019 b = (unsigned char *)f->buf;
1020 for (l = 0; l < 512; l += n) {
1021 n = read(f->fd, b + l, 512 - l);
1022 if (n < 0)
1023 fatal("read:");
1024 if (n == 0)
1025 break;
1026 }
1027 f->pos = f->buf;
1028 f->end = f->buf + l;
1029 if (l == 512) {
1030 unsigned long sum, hdrsum;
1031
1032 sum = 0;
1033 for (i = 0; i < 512; ++i)
1034 sum += b[i];
1035 if (sum == 0)
1036 return readpax;
1037 hdrsum = 0;
1038 for (i = 148; i < 156; ++i) {
1039 sum += ' ' - b[i];
1040 if (b[i] >= '0' && b[i] <= '9')
1041 hdrsum = hdrsum * 8 + (b[i] - '0');
1042 }
1043 if (sum == hdrsum)
1044 return readpax;
1045 }
1046 if (l >= 76) {
1047 if (memcmp(b, "070707", 6) == 0)
1048 return readcpio;
1049 }
1050 if (!algo) {
1051 static const struct command {
1052 char algo[6];
1053 unsigned char magiclen;
1054 unsigned char magic[6];
1055 } cmds[] = {
1056 {"gzip", 2, {0x1F, 0x8B}},
1057 {"bzip2", 2, {'B', 'Z'}},
1058 {"xz", 6, {0xFD, '7', 'z', 'X', 'Z', 0x00}},
1059 {"zstd", 4, {0x28, 0xB5, 0x2F, 0xFD}},
1060 {"lzip", 4, {'L', 'Z', 'I', 'P'}},
1061 };
1062 const struct command *c;
1063
1064 for (c = cmds; c < cmds + LEN(cmds); ++c) {
1065 if (l >= c->magiclen && memcmp(b, c->magic, c->magiclen) == 0) {
1066 if (lseek(f->fd, 0, SEEK_SET) != 0)
1067 fatal(
1068 "compression detection requires "
1069 "seekable input"
1070 );
1071 algo = c->algo;
1072 goto again;
1073 }
1074 }
1075 }
1076 return NULL;
1077}
1078
1079static FILE *
1080compress(const char *algo, const char *name, pid_t *pid)
1081{
1082 extern char **environ;
1083 FILE *f;
1084 int fd, p[2], err;
1085 posix_spawn_file_actions_t fa;
1086 char *argv[3];
1087
1088 if (!algo) {
1089 if (name && !freopen(name, aflag ? "r+" : "w", stdout))
1090 fatal("open %s:");
1091 if (aflag && name) {
1092 if (fseek(stdout, 0, SEEK_END) != 0)
1093 fatal("fseek %s:");
1094 }
1095 return stdout;
1096 }
1097 argv[0] = (char *)algo;
1098 argv[1] = "-c";
1099 argv[2] = NULL;
1100 if (name) {
1101 fd = open(name, O_WRONLY | O_CREAT, 0666);
1102 if (fd < 0)
1103 fatal("open %s:");
1104 } else {
1105 fd = 1;
1106 }
1107 if (pipe2(p, O_CLOEXEC) != 0)
1108 fatal("pipe2:");
1109 f = fdopen(p[1], "w");
1110 if (!f)
1111 fatal("fdopen:");
1112 err = posix_spawn_file_actions_init(&fa);
1113 if (err)
1114 fatal("posix_spawn_file_actions_init: %s", strerror(errno));
1115 err = posix_spawn_file_actions_adddup2(&fa, p[0], 0);
1116 if (err)
1117 fatal("posix_spawn_file_actions_adddup2: %s", strerror(errno));
1118 err = posix_spawn_file_actions_adddup2(&fa, fd, 1);
1119 if (err)
1120 fatal("posix_spawn_file_actions_adddup2: %s", strerror(errno));
1121 err = posix_spawnp(pid, algo, &fa, NULL, argv, environ);
1122 if (err)
1123 fatal("posix_spawnp %s: %s", algo, strerror(errno));
1124 close(fd);
1125 close(p[0]);
1126 return f;
1127}
1128
1129static char *
1130splitname(char *name, size_t namelen)
1131{
1132 char *slash;
1133
1134 if (namelen > 256)
1135 return NULL;
1136 slash = memchr(name + namelen - 100, '/', 100);
1137 if (!slash || slash - name > 155)
1138 return NULL;
1139 return slash;
1140}
1141
1142static void
1143openfile(struct header *h)
1144{
1145 int fd;
1146
1147 if (h->file) {
1148 fd = open(h->file, O_RDONLY);
1149 if (fd < 0)
1150 fatal("open %s:", h->file);
1151 bioinit(&bioin, fd);
1152 }
1153}
1154
1155static void
1156closefile(struct header *h)
1157{
1158 if (h->file) {
1159 if (tflag)
1160 futimens(bioin.fd, (struct timespec[2]){h->fileatime, {.tv_nsec = UTIME_OMIT}});
1161 close(bioin.fd);
1162 }
1163}
1164
1165static void
1166closeustar(FILE *f)
1167{
1168 char pad[512];
1169
1170 memset(pad, 0, 512);
1171 if (fwrite(pad, 512, 1, f) != 1)
1172 fatal("write:");
1173 if (fwrite(pad, 512, 1, f) != 1)
1174 fatal("write:");
1175}
1176
1177static void
1178writeustar(FILE *f, struct header *h)
1179{
1180 char buf[512], *slash, tmp[32];
1181 unsigned long sum;
1182 int i;
1183
1184 if (!h) {
1185 closeustar(f);
1186 return;
1187 }
1188 slash = h->slash;
1189 if (!slash && h->pathlen > 100) {
1190 slash = splitname(h->path, h->pathlen);
1191 if (!slash)
1192 fatal("path is too long: %s\n", h->path);
1193 }
1194 if (slash) {
1195 size_t len;
1196
1197 strncpy(buf, slash + 1, 100);
1198 len = slash - h->path;
1199 memcpy(buf + 345, h->path, len);
1200 memset(buf + 345 + len, 0, 155 - len);
1201 } else {
1202 strncpy(buf, h->path, 100);
1203 memset(buf + 345, 0, 155);
1204 }
1205 if (h->mode > 07777777)
1206 fatal("mode is too large: %ju", (uintmax_t)h->mode);
1207 snprintf(tmp, sizeof(tmp), "%.7lo", (unsigned long)h->mode & 07777777);
1208 memcpy(buf + 100, tmp, 8);
1209 if (h->uid > MAXUGID)
1210 fatal("uid is too large: %ju", (uintmax_t)h->uid);
1211 snprintf(tmp, sizeof(tmp), "%.7lo", (unsigned long)h->uid & 07777777);
1212 memcpy(buf + 108, tmp, 8);
1213 if (h->gid > MAXUGID)
1214 fatal("gid is too large: %ju", (uintmax_t)h->gid);
1215 snprintf(tmp, sizeof(tmp), "%.7lo", (unsigned long)h->gid & 07777777);
1216 memcpy(buf + 116, tmp, 8);
1217 if (h->size < 0 || h->size > MAXSIZE)
1218 fatal("size is too large: %ju", (uintmax_t)h->size);
1219 snprintf(buf + 124, 12, "%.11llo", (unsigned long long)h->size);
1220 if (h->mtime.tv_sec < 0 || h->mtime.tv_sec > MAXTIME)
1221 fatal("mtime is too large: %ju", (uintmax_t)h->mtime.tv_sec);
1222 snprintf(buf + 136, 12, "%.11llo", (unsigned long long)h->mtime.tv_sec);
1223 memset(buf + 148, ' ', 8);
1224 buf[156] = h->type;
1225 if (h->linklen > 100)
1226 fatal("link name is too long: %s\n", h->link);
1227 strncpy(buf + 157, h->link, 100);
1228 memcpy(buf + 257, "ustar", 6);
1229 memcpy(buf + 263, "00", 2);
1230 if (strlen(h->uname) > 31)
1231 fatal("user name is too long: %s\n", h->uname);
1232 strncpy(buf + 265, h->uname, 32);
1233 if (strlen(h->gname) > 31)
1234 fatal("group name is too long: %s\n", h->gname);
1235 strncpy(buf + 297, h->gname, 32);
1236 if (major(h->rdev) > 07777777)
1237 fatal("device major is too large: %ju\n", (uintmax_t)major(h->rdev));
1238 snprintf(tmp, sizeof(tmp), "%.7lo", (unsigned long)major(h->rdev) & 07777777);
1239 memcpy(buf + 329, tmp, 8);
1240 if (minor(h->rdev) > 07777777)
1241 fatal("device minor is too large: %ju\n", (uintmax_t)minor(h->rdev));
1242 snprintf(tmp, sizeof(tmp), "%.7lo", (unsigned long)minor(h->rdev) & 07777777);
1243 memcpy(buf + 337, tmp, 8);
1244 memset(buf + 500, 0, 12);
1245 sum = 0;
1246 for (i = 0; i < 512; ++i)
1247 sum += ((unsigned char *)buf)[i];
1248 snprintf(tmp, sizeof(tmp), "%.7lo", sum & 07777777);
1249 memcpy(buf + 148, tmp, 8);
1250 if (fwrite(buf, 512, 1, f) != 1)
1251 fatal("write:");
1252 if (h->data) {
1253 size_t pad;
1254
1255 if (fwrite(h->data, 1, (size_t)h->size, f) != (size_t)h->size)
1256 fatal("write:");
1257 pad = (size_t)(ROUNDUP(h->size, 512) - h->size);
1258 memset(bioin.buf, 0, pad);
1259 if (fwrite(bioin.buf, 1, pad, f) != pad)
1260 fatal("write:");
1261 } else if (h->size > 0) {
1262 openfile(h);
1263 copy(&bioin, h->size, f, ROUNDUP(h->size, 512));
1264 closefile(h);
1265 }
1266}
1267
1268static void
1269writerec(struct strbuf *ext, const char *fmt, ...)
1270{
1271 static struct strbuf buf;
1272 va_list ap;
1273 int d, n, m, l;
1274
1275 buf.len = 0;
1276 va_start(ap, fmt);
1277 l = sbuffmtv(&buf, 256, fmt, ap);
1278 va_end(ap);
1279
1280 d = 0;
1281 m = 1;
1282 for (n = l; n > 0; n /= 10) {
1283 m *= 10;
1284 ++d;
1285 }
1286 n = d + 1 + l + 1;
1287 if (n >= m)
1288 ++n;
1289 sbuffmt(ext, 256, "%d %.*s\n", n, l, buf.str);
1290}
1291
1292static void
1293writetimerec(struct strbuf *ext, char *kw, struct timespec *ts)
1294{
1295 if (ts->tv_nsec != 0)
1296 writerec(ext, "%s=%ju.%.9ld", kw, (uintmax_t)ts->tv_sec, ts->tv_nsec % 1000000000);
1297 else
1298 writerec(ext, "%s=%ju", kw, (uintmax_t)ts->tv_sec);
1299}
1300
1301static void
1302writeexthdr(FILE *f, int type, struct header *h)
1303{
1304 static struct strbuf ext;
1305 struct header exthdr;
1306
1307 ext.len = 0;
1308 if (h->fields & PATH)
1309 writerec(&ext, "path=%s", h->path);
1310 if (h->fields & UID)
1311 writerec(&ext, "uid=%ju", (uintmax_t)h->uid);
1312 if (h->fields & GID)
1313 writerec(&ext, "gid=%ju", (uintmax_t)h->gid);
1314 if (h->fields & SIZE)
1315 writerec(&ext, "size=%ju", (uintmax_t)h->size);
1316 if (h->fields & MTIME)
1317 writetimerec(&ext, "mtime", &h->mtime);
1318 if (h->fields & ATIME)
1319 writetimerec(&ext, "atime", &h->atime);
1320 if (h->fields & CTIME)
1321 writetimerec(&ext, "ctime", &h->ctime);
1322 if (h->fields & UNAME)
1323 writerec(&ext, "uname=%s", h->uname);
1324 if (h->fields & GNAME)
1325 writerec(&ext, "gname=%s", h->gname);
1326 if (ext.len > 0) {
1327 memset(&exthdr, 0, sizeof exthdr);
1328 exthdr.path = "pax_extended_header";
1329 exthdr.pathlen = 20;
1330 exthdr.mode = 0600;
1331 exthdr.link = "";
1332 exthdr.uname = "";
1333 exthdr.gname = "";
1334 exthdr.size = ext.len;
1335 exthdr.type = type;
1336 exthdr.data = ext.str;
1337 writeustar(f, &exthdr);
1338 }
1339}
1340
1341static void
1342mergehdr(struct header *dst, struct header *src, enum field fields)
1343{
1344 fields &= src->fields;
1345 if (fields & PATH) {
1346 dst->path = src->path;
1347 dst->pathlen = src->pathlen;
1348 }
1349 if (fields & UID)
1350 dst->uid = src->uid;
1351 if (fields & GID)
1352 dst->gid = src->gid;
1353 if (fields & SIZE)
1354 dst->size = src->size;
1355 if (fields & MTIME)
1356 dst->mtime = src->mtime;
1357 if (fields & ATIME)
1358 dst->atime = src->atime;
1359 if (fields & CTIME)
1360 dst->ctime = src->ctime;
1361 if (fields & UNAME)
1362 dst->uname = src->uname;
1363 if (fields & GNAME)
1364 dst->gname = src->gname;
1365 if (fields & LINKPATH) {
1366 dst->link = src->link;
1367 dst->linklen = src->linklen;
1368 }
1369 dst->fields |= fields;
1370}
1371
1372static void
1373writepax(FILE *f, struct header *h)
1374{
1375 enum field fields;
1376
1377 if (!h) {
1378 closeustar(f);
1379 return;
1380 }
1381 if (vflag)
1382 fprintf(stderr, "%s\n", h->path);
1383 fields = 0;
1384 if (h->pathlen > 100) {
1385 h->slash = splitname(h->path, h->pathlen);
1386 if (!h->slash)
1387 fields |= PATH;
1388 }
1389 if (h->uid > MAXUGID)
1390 fields |= UID;
1391 if (h->gid > MAXUGID)
1392 fields |= GID;
1393 if (h->size > MAXSIZE)
1394 fields |= SIZE;
1395 if (h->mtime.tv_sec > MAXTIME || h->mtime.tv_nsec != 0)
1396 fields |= MTIME;
1397 if (opt.times)
1398 fields |= ATIME | CTIME;
1399 if (strlen(h->uname) > 31)
1400 fields |= UNAME;
1401 if (strlen(h->gname) > 31)
1402 fields |= GNAME;
1403 if (h->linklen > 100)
1404 fields |= LINKPATH;
1405 fields &= ~(exthdr.fields | opt.delete);
1406 mergehdr(&exthdr, h, fields);
1407 writeexthdr(f, 'x', &exthdr);
1408
1409 /* reset fields merged into extended header */
1410 if (fields & PATH)
1411 h->path = "", h->pathlen = 0;
1412 if (fields & UID)
1413 h->uid = 0;
1414 if (fields & GID)
1415 h->gid = 0;
1416 if (fields & SIZE)
1417 h->size = 0;
1418 if (fields & MTIME) {
1419 if (h->mtime.tv_sec > MAXTIME)
1420 h->mtime.tv_sec = MAXTIME;
1421 h->mtime.tv_nsec = 0;
1422 }
1423 if (fields & ATIME) {
1424 if (h->atime.tv_sec > MAXTIME)
1425 h->atime.tv_sec = MAXTIME;
1426 h->atime.tv_nsec = 0;
1427 }
1428 if (fields & CTIME) {
1429 if (h->ctime.tv_sec > MAXTIME)
1430 h->ctime.tv_sec = MAXTIME;
1431 h->ctime.tv_nsec = 0;
1432 }
1433 if (fields & UNAME)
1434 h->uname = "";
1435 if (fields & GNAME)
1436 h->gname = "";
1437 if (fields & LINKPATH)
1438 h->link = "", h->linklen = 0;
1439 h->fields &= ~fields;
1440 writeustar(f, h);
1441}
1442
1443static void
1444writecpio(FILE *f, struct header *h)
1445{
1446 static unsigned long ino;
1447 char buf[77];
1448 unsigned long mode;
1449 uintmax_t size;
1450 size_t namesize;
1451 int len;
1452
1453 if (!h) {
1454 memcpy(buf, "070707", 6);
1455 memset(buf + 6, '0', 70);
1456 memcpy(buf + 59, "000013", 6);
1457 if (fwrite(buf, 1, 76, f) != 76)
1458 fatal("write:");
1459 if (fwrite("TRAILER!!!", 1, 11, f) != 11)
1460 fatal("write:");
1461 return;
1462 }
1463 if (vflag)
1464 fprintf(stderr, "%s\n", h->path);
1465 mode = h->mode;
1466 switch (h->type) {
1467 case DIRTYPE:
1468 mode |= S_IFDIR;
1469 break;
1470 case FIFOTYPE:
1471 mode |= S_IFIFO;
1472 break;
1473 case REGTYPE:
1474 mode |= S_IFREG;
1475 break;
1476 case SYMTYPE:
1477 mode |= S_IFLNK;
1478 break;
1479 case BLKTYPE:
1480 mode |= S_IFBLK;
1481 break;
1482 case CHRTYPE:
1483 mode |= S_IFCHR;
1484 break;
1485 default:
1486 fatal("unknown or unsupported header type");
1487 }
1488 if (h->dev > 0777777)
1489 fatal("device is too large: %ju", (uintmax_t)h->dev);
1490 if (++ino > 0777777)
1491 fatal("inode is too large: %lu", ino);
1492 if (mode > 0777777)
1493 fatal("mode is too large: %lu", mode);
1494 if (h->uid > MAXUGID)
1495 fatal("uid is too large: %ju", (uintmax_t)h->uid);
1496 if (h->gid > MAXUGID)
1497 fatal("gid is too large: %ju", (uintmax_t)h->gid);
1498 if (h->nlink > 0777777)
1499 fatal("nlink is too large: %ju", (uintmax_t)h->nlink);
1500 if (h->rdev > 0777777)
1501 fatal("device is too large: %ju", (uintmax_t)h->rdev);
1502 if (h->mtime.tv_sec > MAXTIME)
1503 fatal("mtime is too large: %ju", (uintmax_t)h->mtime.tv_sec);
1504 namesize = h->pathlen;
1505 if (namesize > 0 && h->path[namesize - 1] == '/')
1506 --namesize;
1507 if (namesize > 077777777777 - 1)
1508 fatal("path is too large: %ju", (uintmax_t)h->pathlen + 1);
1509 size = h->type == SYMTYPE ? (uintmax_t)h->linklen : (uintmax_t)h->size;
1510 if (size > MAXSIZE)
1511 fatal("size is too large: %ju", h->size);
1512 len = snprintf(
1513 buf,
1514 sizeof buf,
1515 "070707%.6lo%.6lo%.6lo%.6lo%.6lo%.6lo%.6lo%.11llo%.6lo%.11jo",
1516 (unsigned long)h->dev,
1517 ino,
1518 mode,
1519 (unsigned long)h->uid,
1520 (unsigned long)h->gid,
1521 (unsigned long)h->nlink,
1522 (unsigned long)h->rdev,
1523 (unsigned long long)h->mtime.tv_sec,
1524 (unsigned long)namesize + 1,
1525 size
1526 );
1527 assert(len == 76);
1528 if (fwrite(buf, 1, 76, f) != 76)
1529 fatal("write:");
1530 if (fwrite(h->path, 1, namesize, f) != namesize || fputc('\0', f) == EOF)
1531 fatal("write:");
1532 switch (h->type) {
1533 case SYMTYPE:
1534 if (fwrite(h->link, 1, h->linklen, f) != h->linklen)
1535 fatal("write:");
1536 break;
1537 case REGTYPE:
1538 openfile(h);
1539 copy(&bioin, h->size, f, h->size);
1540 closefile(h);
1541 break;
1542 default:
1543 break;
1544 }
1545}
1546
1547static void
1548filepush(struct filelist *files, const char *name, size_t pathlen, dev_t dev)
1549{
1550 struct file *f;
1551 size_t namelen;
1552
1553 namelen = strlen(name);
1554 f = malloc(sizeof *f + namelen + 1);
1555 if (!f)
1556 fatal(NULL);
1557 memcpy(f->name, name, namelen + 1);
1558 f->namelen = namelen;
1559 f->pathlen = pathlen;
1560 f->dev = dev;
1561 f->next = files->pending;
1562 files->pending = f;
1563}
1564
1565static int
1566readfile(struct bufio *f, struct header *h)
1567{
1568 /* use our own path buffer, since we use it for traversal */
1569 static struct strbuf path;
1570 struct stat st;
1571 int flag;
1572 DIR *dir;
1573 struct dirent *d;
1574 ssize_t ret;
1575 dev_t dev;
1576
1577 (void)f;
1578
1579next:
1580 flag = follow == 'L' ? 0 : AT_SYMLINK_NOFOLLOW;
1581 if (files.pending) {
1582 struct file *f;
1583
1584 f = files.pending;
1585 files.pending = f->next;
1586 assert(f->pathlen <= path.len);
1587 path.len = f->pathlen;
1588 sbufcat(&path, f->name, f->namelen, 1024);
1589 if (follow == 'H' && f->pathlen > 0)
1590 flag &= ~AT_SYMLINK_NOFOLLOW;
1591 dev = f->dev;
1592 free(f);
1593 } else {
1594 if (!files.input)
1595 return 0;
1596 ret = getline(&path.str, &path.cap, files.input);
1597 if (ret < 0) {
1598 if (ferror(files.input))
1599 fatal("getline:");
1600 return 0;
1601 }
1602 if (ret > 0 && path.str[ret - 1] == '\n')
1603 path.str[--ret] = '\0';
1604 path.len = ret;
1605 dev = 0;
1606 }
1607
1608 if (fstatat(AT_FDCWD, path.str, &st, flag) != 0)
1609 fatal("stat %s:", path.str);
1610 if (Xflag && dev && st.st_dev != dev)
1611 goto next;
1612 if (S_ISDIR(st.st_mode) && path.str[path.len - 1] != '/')
1613 sbufcat(&path, "/", 1, 1024);
1614 h->fields = PATH | UID | GID | ATIME | MTIME | CTIME;
1615 h->path = path.str;
1616 h->pathlen = path.len;
1617 h->dev = st.st_dev;
1618 h->ino = st.st_ino;
1619 h->mode = st.st_mode & ~S_IFMT;
1620 h->uid = st.st_uid;
1621 h->gid = st.st_gid;
1622 h->nlink = st.st_nlink;
1623 h->rdev = 0;
1624 h->size = 0;
1625 h->atime = st.st_atim;
1626 h->mtime = st.st_mtim;
1627 h->ctime = st.st_ctim;
1628 h->uname = uidtouname(st.st_uid, "");
1629 h->gname = gidtogname(st.st_gid, "");
1630 h->link = "";
1631 h->linklen = 0;
1632 h->slash = NULL;
1633 h->data = NULL;
1634 h->file = h->path;
1635 h->fileatime = st.st_atim;
1636 h->flag = flag;
1637 switch (st.st_mode & S_IFMT) {
1638 case S_IFREG:
1639 h->type = REGTYPE;
1640 h->size = st.st_size;
1641 break;
1642 case S_IFLNK:
1643 h->type = SYMTYPE;
1644 h->linkbuf.len = 0;
1645 sbufalloc(&h->linkbuf, 1024, 1024);
1646 for (;;) {
1647 ret = readlink(h->path, h->linkbuf.str, h->linkbuf.cap - 1);
1648 if (ret < 0)
1649 fatal("readlink %s:", h->path);
1650 if ((size_t)ret < h->linkbuf.cap)
1651 break;
1652 if (h->linkbuf.cap > (size_t)SSIZE_MAX / 2)
1653 fatal("symlink target is too long");
1654 sbufalloc(&h->linkbuf, h->linkbuf.cap * 2, 1024);
1655 }
1656 h->linkbuf.str[ret] = '\0';
1657 h->linkbuf.len = ret;
1658 h->link = h->linkbuf.str;
1659 h->linklen = h->linkbuf.len;
1660 break;
1661 case S_IFCHR:
1662 h->type = CHRTYPE;
1663 h->rdev = st.st_rdev;
1664 break;
1665 case S_IFBLK:
1666 h->type = BLKTYPE;
1667 h->rdev = st.st_rdev;
1668 break;
1669 case S_IFDIR:
1670 h->type = DIRTYPE;
1671 dir = opendir(h->path);
1672 if (!dir)
1673 fatal("opendir %s:", h->path);
1674 for (;;) {
1675 errno = 0;
1676 d = readdir(dir);
1677 if (!d)
1678 break;
1679 if (strcmp(d->d_name, ".") == 0 || strcmp(d->d_name, "..") == 0)
1680 continue;
1681 filepush(&files, d->d_name, path.len, st.st_dev);
1682 }
1683 if (errno != 0)
1684 fatal("readdir %s:", h->path);
1685 closedir(dir);
1686 break;
1687 case S_IFIFO:
1688 h->type = FIFOTYPE;
1689 break;
1690 }
1691 return 1;
1692}
1693
1694static void
1695usage(void)
1696{
1697 fprintf(stderr, "usage: pax\n");
1698 exit(2);
1699}
1700
1701static void
1702print_listopt(struct header *h)
1703{
1704 const char *s;
1705 size_t len;
1706
1707 s = opt.listopt;
1708 while (*s) {
1709 if (*s == '%') {
1710 s++;
1711 if (*s == '%') {
1712 putchar('%');
1713 s++;
1714 } else {
1715 len = 0;
1716 while (s[len] && isalnum((unsigned char)s[len]))
1717 len++;
1718 if (len > 0) {
1719 if (strncmp(s, "path", len) == 0 && len == 4)
1720 printf("%s", h->path);
1721 else if (strncmp(s, "size", len) == 0 && len == 4)
1722 printf("%ju", (uintmax_t)h->size);
1723 else if (strncmp(s, "uid", len) == 0 && len == 3)
1724 printf("%ju", (uintmax_t)h->uid);
1725 else if (strncmp(s, "gid", len) == 0 && len == 3)
1726 printf("%ju", (uintmax_t)h->gid);
1727 else if (strncmp(s, "uname", len) == 0 && len == 5)
1728 printf("%s", h->uname);
1729 else if (strncmp(s, "gname", len) == 0 && len == 5)
1730 printf("%s", h->gname);
1731 else if (strncmp(s, "mode", len) == 0 && len == 4)
1732 printf("%04o", (unsigned int)(h->mode & 07777));
1733 else if (strncmp(s, "mtime", len) == 0 && len == 5)
1734 printf("%ju", (uintmax_t)h->mtime.tv_sec);
1735 else if (strncmp(s, "atime", len) == 0 && len == 5)
1736 printf("%ju", (uintmax_t)h->atime.tv_sec);
1737 else if (strncmp(s, "ctime", len) == 0 && len == 5)
1738 printf("%ju", (uintmax_t)h->ctime.tv_sec);
1739 else if (strncmp(s, "linkpath", len) == 0 && len == 8)
1740 printf("%s", h->link);
1741 else {
1742 putchar('%');
1743 fwrite(s, 1, len, stdout);
1744 }
1745 s += len;
1746 } else {
1747 putchar('%');
1748 }
1749 }
1750 } else if (*s == '\\') {
1751 s++;
1752 if (*s == 'n') {
1753 putchar('\n');
1754 s++;
1755 } else if (*s == 't') {
1756 putchar('\t');
1757 s++;
1758 } else if (*s == '\\') {
1759 putchar('\\');
1760 s++;
1761 } else if (*s) {
1762 putchar(*s);
1763 s++;
1764 }
1765 } else {
1766 putchar(*s);
1767 s++;
1768 }
1769 }
1770 putchar('\n');
1771}
1772
1773static void
1774parseopts(char *s)
1775{
1776 char *key, *val, *end, *d;
1777 int ext;
1778
1779 for (;;) {
1780 s += strspn(s, " \t\n\v\f\r");
1781 if (!*s)
1782 break;
1783 key = s;
1784 while (*s && *s != ',' && *s != '=')
1785 ++s;
1786 val = NULL;
1787 end = NULL, ext = 0; /* silence gcc uninitialized warning */
1788 if (*s == '=') {
1789 ext = s > key && s[-1] == ':';
1790 s[-ext] = '\0';
1791 val = ++s;
1792 for (d = s; *s && *s != ','; ++s, ++d) {
1793 if (*s == '\\')
1794 ++s;
1795 if (d < s)
1796 *d = *s;
1797 }
1798 end = d;
1799 }
1800 if (*s == ',')
1801 *s++ = '\0';
1802 if (strcmp(key, "linkdata") == 0) {
1803 if (val)
1804 fatal(
1805 "option 'linkdata' must not have a "
1806 "value"
1807 );
1808 opt.linkdata = 1;
1809 } else if (strcmp(key, "times") == 0) {
1810 if (val)
1811 fatal("option 'times' must not have a value");
1812 opt.times = 1;
1813 } else if (!val) {
1814 fatal("option '%s' must have a value", key);
1815 } else if (strcmp(key, "delete") == 0) {
1816 const struct keyword *kw;
1817
1818 for (kw = keywords; kw != keywords + LEN(keywords); ++kw) {
1819 switch (fnmatch(val, kw->name, 0)) {
1820 case 0:
1821 opt.delete |= kw->field;
1822 break;
1823 case FNM_NOMATCH:
1824 break;
1825 default:
1826 fatal("fnmatch error");
1827 }
1828 }
1829 } else if (strcmp(key, "exthdr.name") == 0) {
1830 opt.exthdrname = val;
1831 } else if (strcmp(key, "globexthdr.name") == 0) {
1832 opt.globexthdrname = val;
1833 } else if (strcmp(key, "invalid") == 0) {
1834 if (strcmp(val, "bypass") != 0 && strcmp(val, "rename") != 0 && strcmp(val, "UTF-8") != 0
1835 && strcmp(val, "write") != 0) {
1836 fatal(
1837 "invalid action '%s' for option "
1838 "'invalid'",
1839 val
1840 );
1841 }
1842 opt.invalid = val;
1843 } else if (strcmp(key, "listopt") == 0) {
1844 opt.listopt = val;
1845 } else {
1846 extkeyval(ext ? &exthdr : &globexthdr, key, val, end - val);
1847 }
1848 }
1849}
1850
1851static void
1852listhdr(FILE *f, struct header *h)
1853{
1854 char mode[11], time[13], info[23];
1855 char unamebuf[(sizeof(uid_t) * CHAR_BIT + 2) / 3 + 1];
1856 char gnamebuf[(sizeof(gid_t) * CHAR_BIT + 2) / 3 + 1];
1857 const char *uname, *gname, *timefmt;
1858 struct tm *tm;
1859
1860 if (!h)
1861 return;
1862 (void)f;
1863 if (opt.listopt) {
1864 print_listopt(h);
1865 return;
1866 }
1867 if (!vflag) {
1868 printf("%s\n", h->path);
1869 return;
1870 }
1871 memset(mode, '-', sizeof mode - 1);
1872 mode[10] = '\0';
1873 switch (h->type) {
1874 case SYMTYPE:
1875 mode[0] = 'l';
1876 break;
1877 case CHRTYPE:
1878 mode[0] = 'c';
1879 break;
1880 case BLKTYPE:
1881 mode[0] = 'b';
1882 break;
1883 case DIRTYPE:
1884 mode[0] = 'd';
1885 break;
1886 case FIFOTYPE:
1887 mode[0] = 'p';
1888 break;
1889 }
1890 if (h->mode & S_IRUSR)
1891 mode[1] = 'r';
1892 if (h->mode & S_IWUSR)
1893 mode[2] = 'w';
1894 if (h->mode & S_IXUSR)
1895 mode[3] = 'x';
1896 if (h->mode & S_IRGRP)
1897 mode[4] = 'r';
1898 if (h->mode & S_IWGRP)
1899 mode[5] = 'w';
1900 if (h->mode & S_IXGRP)
1901 mode[6] = 'x';
1902 if (h->mode & S_IROTH)
1903 mode[7] = 'r';
1904 if (h->mode & S_IWOTH)
1905 mode[8] = 'w';
1906 if (h->mode & S_IXOTH)
1907 mode[9] = 'x';
1908 if (h->mode & S_ISUID)
1909 mode[3] = mode[3] == 'x' ? 's' : 'S';
1910 if (h->mode & S_ISGID)
1911 mode[3] = mode[6] == 'x' ? 's' : 'S';
1912 if (h->mode & S_ISVTX)
1913 mode[9] = mode[9] == 'x' ? 't' : 'T';
1914 uname = h->uname;
1915 if (!uname[0]) {
1916 snprintf(unamebuf, sizeof unamebuf, "%ju", (uintmax_t)h->uid);
1917 uname = unamebuf;
1918 }
1919 gname = h->gname;
1920 if (!gname[0]) {
1921 snprintf(gnamebuf, sizeof gnamebuf, "%ju", (uintmax_t)h->gid);
1922 gname = gnamebuf;
1923 }
1924 timefmt = h->mtime.tv_sec + 15780000 < curtime || h->mtime.tv_sec > curtime ? "%b %e %Y"
1925 : "%b %e %H:%M";
1926 tm = localtime(&h->mtime.tv_sec);
1927 if (!tm)
1928 fatal("localtime:");
1929 strftime(time, sizeof time, timefmt, tm);
1930 if (h->type == CHRTYPE || h->type == BLKTYPE)
1931 snprintf(info, sizeof info, "%u, %u", major(h->rdev), minor(h->rdev));
1932 else
1933 snprintf(info, sizeof info, "%ju", (uintmax_t)h->size);
1934 printf(
1935 "%s %2ju %-8s %-8s %9s %s %s", mode, (uintmax_t)h->nlink, uname, gname, info, time, h->path
1936 );
1937 switch (h->type) {
1938 case LNKTYPE:
1939 printf(" == %s", h->link);
1940 break;
1941 case SYMTYPE:
1942 printf(" -> %s", h->link);
1943 break;
1944 }
1945 putchar('\n');
1946}
1947
1948static void
1949mkdirp(int fd, char *name, size_t len)
1950{
1951 char *p;
1952
1953 if (len == 0)
1954 return;
1955 for (p = name + 1; p < name + len - 1; ++p) {
1956 if (*p != '/')
1957 continue;
1958 *p = 0;
1959 if (mkdirat(fd, name, 0777) != 0 && errno != EEXIST)
1960 fatal("mkdir %s:", name);
1961 *p = '/';
1962 }
1963}
1964
1965static void
1966writefile(FILE *unused, struct header *h)
1967{
1968 FILE *f;
1969 int fd, retry, flags;
1970 struct stat st;
1971 mode_t mode;
1972
1973 (void)unused;
1974 if (!h)
1975 return;
1976 if (uflag && fstatat(destfd, h->path, &st, 0) == 0) {
1977 if (h->mtime.tv_sec < st.st_mtime
1978 || (h->mtime.tv_sec == st.st_mtime && h->mtime.tv_nsec < st.st_mtim.tv_nsec))
1979 return;
1980 }
1981 if (vflag)
1982 fprintf(stderr, "%s\n", h->path);
1983 if (lflag && h->file && h->type != DIRTYPE) {
1984 if (linkat(AT_FDCWD, h->file, destfd, h->path, h->flag) == 0)
1985 return;
1986 }
1987 retry = 1;
1988 if (0) {
1989 retry:
1990 retry = 0;
1991 mkdirp(destfd, h->path, h->pathlen);
1992 }
1993 mode = h->mode & ~(S_ISUID | S_ISGID);
1994 switch (h->type) {
1995 case REGTYPE:
1996 flags = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC;
1997 if (kflag)
1998 flags |= O_EXCL;
1999 fd = openat(destfd, h->path, flags, mode);
2000 if (fd < 0) {
2001 if (retry && errno == ENOENT)
2002 goto retry;
2003 fatal("open %s%s:", dest, h->path);
2004 }
2005 f = fdopen(fd, "w");
2006 if (!f)
2007 fatal("open %s:", h->path);
2008 openfile(h);
2009 copy(&bioin, h->size, f, h->size);
2010 closefile(h);
2011 fclose(f);
2012 break;
2013 case LNKTYPE:
2014 if (linkat(destfd, h->link, destfd, h->path, 0) != 0) {
2015 if (retry && errno == ENOENT)
2016 goto retry;
2017 fatal("link %s%s:", dest, h->path);
2018 }
2019 break;
2020 case SYMTYPE:
2021 if (symlinkat(h->link, destfd, h->path) != 0) {
2022 if (retry && errno == ENOENT)
2023 goto retry;
2024 fatal("symlink %s%s:", dest, h->path);
2025 }
2026 break;
2027 case CHRTYPE:
2028 case BLKTYPE:
2029 mode |= h->type == CHRTYPE ? S_IFCHR : S_IFBLK;
2030 if (mknodat(destfd, h->path, mode, h->rdev) != 0) {
2031 if (retry && errno == ENOENT)
2032 goto retry;
2033 fatal("mknod %s%s:", dest, h->path);
2034 }
2035 break;
2036 case DIRTYPE:
2037 if (mkdirat(destfd, h->path, mode) != 0) {
2038 if (retry && errno == ENOENT)
2039 goto retry;
2040 if (errno == EEXIST) {
2041 if (fstatat(destfd, h->path, &st, 0) == 0 && S_ISDIR(st.st_mode))
2042 break;
2043 errno = EEXIST;
2044 }
2045 fatal("mkdir %s%s:", dest, h->path);
2046 }
2047 break;
2048 case FIFOTYPE:
2049 if (mkfifoat(destfd, h->path, mode) != 0) {
2050 if (retry && errno == ENOENT)
2051 goto retry;
2052 if (errno == EEXIST) {
2053 if (fstatat(destfd, h->path, &st, 0) == 0 && S_ISFIFO(st.st_mode))
2054 break;
2055 errno = EEXIST;
2056 }
2057 fatal("mkfifo %s%s:", dest, h->path);
2058 }
2059 break;
2060 }
2061 if (preserve & (ATIME | MTIME)) {
2062 struct timespec ts[2];
2063
2064 ts[0] = preserve & ATIME ? h->atime : (struct timespec){.tv_nsec = UTIME_OMIT};
2065 ts[1] = preserve & MTIME ? h->mtime : (struct timespec){.tv_nsec = UTIME_OMIT};
2066 if (utimensat(destfd, h->path, ts, AT_SYMLINK_NOFOLLOW) != 0) {
2067 fprintf(stderr, "utimens %s%s: %s\n", dest, h->path, strerror(errno));
2068 exitstatus = 1;
2069 }
2070 }
2071 if (preserve & (UID | GID)) {
2072 uid_t uid;
2073 gid_t gid;
2074
2075 uid = preserve & UID ? unametouid(h->uname, h->uid) : (uid_t)-1;
2076 gid = preserve & GID ? gnametogid(h->gname, h->gid) : (gid_t)-1;
2077 if (fchownat(destfd, h->path, uid, gid, 0) != 0) {
2078 fprintf(stderr, "chown %s%s: %s\n", dest, h->path, strerror(errno));
2079 exitstatus = 1;
2080 } else {
2081 /* add back setuid/setgid bits if we preserved the
2082 * uid/gid */
2083 mode = h->mode;
2084 }
2085 }
2086 if (preserve & MODE && h->type != SYMTYPE) {
2087 if (fchmodat(destfd, h->path, mode, 0) != 0) {
2088 fprintf(stderr, "chmod %s%s: %s\n", dest, h->path, strerror(errno));
2089 exitstatus = 1;
2090 }
2091 }
2092}
2093
2094static int
2095match(struct header *h)
2096{
2097 static struct dir {
2098 char *path;
2099 size_t pathlen;
2100 } *dirs;
2101 static size_t dirslen;
2102 size_t i;
2103
2104 if (patslen == 0)
2105 return 1;
2106 if (!dflag) {
2107 struct dir *d;
2108
2109 for (d = dirs; d < dirs + dirslen; ++d) {
2110 if (h->pathlen >= d->pathlen && memcmp(h->path, d->path, d->pathlen) == 0)
2111 return !cflag;
2112 }
2113 }
2114 for (i = 0; i < patslen; ++i) {
2115 if (nflag && patsused[i])
2116 continue;
2117 switch (fnmatch(pats[i], h->path, FNM_PATHNAME | FNM_PERIOD)) {
2118 case 0:
2119 patsused[i] = 1;
2120 if (!dflag && h->type == DIRTYPE) {
2121 struct dir *d;
2122
2123 if ((dirslen & (dirslen - 1)) == 0) {
2124 dirs = reallocarray(dirs, dirslen ? dirslen * 2 : 32, sizeof *dirs);
2125 if (!dirs)
2126 fatal(NULL);
2127 }
2128 d = &dirs[dirslen++];
2129 d->pathlen = h->pathlen;
2130 d->path = malloc(d->pathlen + 1);
2131 if (!d->path)
2132 fatal(NULL);
2133 memcpy(d->path, h->path, h->pathlen);
2134 /* add trailing slash if not already present */
2135 if (d->path[d->pathlen - 1] != '/')
2136 d->path[d->pathlen++] = '/';
2137 }
2138 return !cflag;
2139 case FNM_NOMATCH:
2140 break;
2141 default:
2142 fatal("fnmatch error");
2143 }
2144 }
2145 return cflag;
2146}
2147
2148static void
2149parsereplstr(char *str)
2150{
2151 static struct replstr **end = &replstr;
2152 struct replstr *r;
2153 char *old, *new, delim;
2154 int err;
2155
2156 delim = str[0];
2157 if (!delim)
2158 usage();
2159 old = str + 1;
2160 str = strchr(old, delim);
2161 if (!str)
2162 usage();
2163 *str = 0;
2164 new = str + 1;
2165 str = strchr(new, delim);
2166 if (!str)
2167 usage();
2168 *str = 0;
2169
2170 r = malloc(sizeof *r);
2171 if (!r)
2172 fatal(NULL);
2173 r->next = NULL;
2174 r->global = 0;
2175 r->print = 0;
2176 r->symlink = 0;
2177 for (;;) {
2178 switch (*++str) {
2179 case 'g':
2180 r->global = 1;
2181 break;
2182 // ?man -p: preserve file attributes
2183 case 'p':
2184 r->print = 1;
2185 break;
2186 // ?man -s: silent mode or print summary
2187 case 's':
2188 r->symlink = 0;
2189 break;
2190 case 'S':
2191 r->symlink = 1;
2192 break;
2193 case 0:
2194 goto done;
2195 }
2196 }
2197done:
2198 err = regcomp(&r->old, old, REG_NEWLINE);
2199 if (err != 0) {
2200 char errbuf[256];
2201
2202 regerror(err, &r->old, errbuf, sizeof errbuf);
2203 fatal("invalid regular expression: %s", errbuf);
2204 }
2205 r->new = new;
2206 *end = r;
2207 end = &r->next;
2208}
2209
2210static int
2211applyrepl(struct replstr *r, struct strbuf *b, const char *old, size_t oldlen)
2212{
2213 regmatch_t match[10];
2214 size_t i, n, l;
2215 const char *s, *p;
2216 char *d;
2217 int flags;
2218
2219 flags = 0;
2220 b->len = 0;
2221 p = old;
2222 while (regexec(&r->old, p, LEN(match), match, flags) == 0) {
2223 n = match[0].rm_so;
2224 for (s = r->new; *s; ++s) {
2225 switch (*s) {
2226 case '&':
2227 i = 0;
2228 break;
2229 case '\\':
2230 i = *++s - '0';
2231 break;
2232 default:
2233 i = -1;
2234 break;
2235 }
2236 n += i <= 9 ? match[i].rm_eo - match[i].rm_so : 1;
2237 }
2238 d = sbufalloc(b, n + 1, 1024);
2239 b->len += n;
2240 memcpy(d, p, match[0].rm_so);
2241 d += match[0].rm_so;
2242 for (s = r->new; *s; ++s) {
2243 switch (*s) {
2244 case '&':
2245 i = 0;
2246 break;
2247 case '\\':
2248 i = *++s - '0';
2249 break;
2250 default:
2251 i = -1;
2252 break;
2253 }
2254 if (i <= 9) {
2255 l = match[i].rm_eo - match[i].rm_so;
2256 memcpy(d, p + match[i].rm_so, l);
2257 d += l;
2258 } else {
2259 *d++ = *s;
2260 }
2261 }
2262 flags |= REG_NOTBOL;
2263 p += match[0].rm_eo;
2264 if (!r->global)
2265 break;
2266 }
2267 if (flags == 0)
2268 return 0;
2269 sbufcat(b, p, oldlen - (p - old), 1024);
2270 if (r->print)
2271 fprintf(stderr, "%s >> %s\n", old, b->str);
2272 return 1;
2273}
2274
2275static void
2276replace(struct header *h)
2277{
2278 static struct strbuf path, link;
2279 struct replstr *r;
2280
2281 for (r = replstr; r; r = r->next) {
2282 if (applyrepl(r, &path, h->path, h->pathlen)) {
2283 h->path = path.str;
2284 h->pathlen = path.len;
2285 break;
2286 }
2287 }
2288 if (h->type != LNKTYPE && h->type != SYMTYPE)
2289 return;
2290 for (r = replstr; r; r = r->next) {
2291 if (h->type == SYMTYPE && !r->symlink)
2292 continue;
2293 if (applyrepl(r, &link, h->link, h->linklen)) {
2294 h->link = link.str;
2295 h->linklen = link.len;
2296 break;
2297 }
2298 }
2299}
2300
2301static int
2302is_invalid_name(const char *name)
2303{
2304 unsigned char c;
2305
2306 if (!name || !*name)
2307 return 1;
2308 for (; *name; name++) {
2309 c = (unsigned char)*name;
2310 if (c < 32 || c >= 127)
2311 return 1;
2312 }
2313 return 0;
2314}
2315
2316static void
2317interactiverename(struct header *h)
2318{
2319 static FILE *ttyfp = NULL;
2320 static char ttybuf[1024];
2321 char *res;
2322
2323 if (!iflag)
2324 return;
2325
2326 if (!ttyfp) {
2327 ttyfp = fopen("/dev/tty", "r+");
2328 if (!ttyfp)
2329 ttyfp = stdin;
2330 }
2331
2332 fprintf(stderr, "rename %s? ", h->path);
2333 fflush(stderr);
2334
2335 if (ttyfp == stdin)
2336 res = fgets(ttybuf, sizeof(ttybuf), stdin);
2337 else
2338 res = fgets(ttybuf, sizeof(ttybuf), ttyfp);
2339
2340 if (!res) {
2341 h->path = "";
2342 h->pathlen = 0;
2343 return;
2344 }
2345
2346 ttybuf[strcspn(ttybuf, "\n")] = '\0';
2347
2348 if (ttybuf[0] == '\0')
2349 return;
2350
2351 if (strcmp(ttybuf, ".") == 0) {
2352 h->path = "";
2353 h->pathlen = 0;
2354 return;
2355 }
2356
2357 h->pathbuf.len = 0;
2358 sbufcat(&h->pathbuf, ttybuf, strlen(ttybuf), 1024);
2359 h->path = h->pathbuf.str;
2360 h->pathlen = h->pathbuf.len;
2361}
2362
2363static void
2364checkinvalid(struct header *h)
2365{
2366 int saved_iflag;
2367
2368 if (!opt.invalid)
2369 return;
2370 if (is_invalid_name(h->path)) {
2371 if (strcmp(opt.invalid, "bypass") == 0) {
2372 h->path = "";
2373 h->pathlen = 0;
2374 } else if (strcmp(opt.invalid, "rename") == 0) {
2375 saved_iflag = iflag;
2376 iflag = 1;
2377 interactiverename(h);
2378 iflag = saved_iflag;
2379 }
2380 }
2381}
2382
2383static off_t
2384locate_tar_end(const char *filename)
2385{
2386 char buf[512];
2387 off_t offset = 0;
2388 int zero_blocks = 0;
2389 int fd, i, is_zero;
2390 ssize_t r;
2391
2392 fd = open(filename, O_RDONLY);
2393 if (fd < 0) {
2394 if (errno == ENOENT)
2395 return 0;
2396 fatal("open %s for append check:", filename);
2397 }
2398
2399 while ((r = read(fd, buf, 512)) == 512) {
2400 is_zero = 1;
2401 for (i = 0; i < 512; i++) {
2402 if (buf[i] != 0) {
2403 is_zero = 0;
2404 break;
2405 }
2406 }
2407 if (is_zero) {
2408 zero_blocks++;
2409 if (zero_blocks == 2) {
2410 close(fd);
2411 return offset;
2412 }
2413 } else {
2414 zero_blocks = 0;
2415 }
2416 offset += 512;
2417 }
2418
2419 close(fd);
2420 return offset;
2421}
2422
2423static void
2424handle_append(const char *filename, const char *algo, const char *format)
2425{
2426 off_t offset;
2427 int fd;
2428
2429 if (!aflag)
2430 return;
2431 if (algo)
2432 fatal("cannot append to compressed archives");
2433 if (strcmp(format, "ustar") != 0 && strcmp(format, "pax") != 0)
2434 fatal("append is only supported for ustar and pax formats");
2435
2436 if (filename) {
2437 offset = locate_tar_end(filename);
2438 if (offset > 0) {
2439 fd = open(filename, O_RDWR);
2440 if (fd >= 0) {
2441 if (ftruncate(fd, offset) != 0)
2442 fatal("ftruncate %s for append:", filename);
2443 close(fd);
2444 }
2445 }
2446 }
2447}
2448
2449// ?man pax: portable archive interchange
2450// ?man read, write, and list member files of archive files
2451int
2452main(int argc, char *argv[])
2453{
2454 const char *name = NULL, *arg, *format = "pax";
2455 const char *algo = NULL;
2456 enum mode mode = LIST;
2457 struct header hdr;
2458 readfn *readhdr = NULL;
2459 writefn *writehdr = listhdr;
2460 FILE *out = NULL;
2461 pid_t pid = -1;
2462 int i;
2463 size_t l;
2464
2465 ARGBEGIN
2466 {
2467 // ?man -a: print or show all entries
2468 case 'a':
2469 aflag = 1;
2470 break;
2471 // ?man -b:str: specify block size or base directory
2472 case 'b':
2473 EARGF(usage());
2474 break;
2475 // ?man -c: print count or perform stdout action
2476 case 'c':
2477 cflag = 1;
2478 break;
2479 // ?man -d: specify directory
2480 case 'd':
2481 dflag = 1;
2482 break;
2483 // ?man -f:str: force the operation
2484 case 'f':
2485 name = EARGF(usage());
2486 break;
2487 // ?man -H: specify option flag
2488 case 'H':
2489 follow = 'H';
2490 break;
2491 // ?man -i: interactive mode or prompt for confirmation
2492 case 'i':
2493 iflag = 1;
2494 break;
2495 // ?man -j: specify option flag
2496 case 'j':
2497 algo = "bzip2";
2498 break;
2499 // ?man -J: specify option flag
2500 case 'J':
2501 algo = "xz";
2502 break;
2503 // ?man -k: specify option flag
2504 case 'k':
2505 kflag = 1;
2506 break;
2507 // ?man -l: list in long format
2508 case 'l':
2509 lflag = 1;
2510 break;
2511 // ?man -L: specify option flag
2512 case 'L':
2513 follow = 'L';
2514 break;
2515 // ?man -n: print line numbers or counts
2516 case 'n':
2517 nflag = 1;
2518 break;
2519 // ?man -o:str: specify output file
2520 case 'o':
2521 parseopts(EARGF(usage()));
2522 break;
2523 // ?man -p:str: preserve file attributes
2524 case 'p':
2525 for (arg = EARGF(usage()); *arg; ++arg) {
2526 switch (*arg) {
2527 // ?man -a: print or show all entries
2528 case 'a':
2529 preserve &= ~ATIME;
2530 break;
2531 // ?man -e: specify expression or pattern
2532 case 'e':
2533 preserve = ~0;
2534 break;
2535 // ?man -m: specify mode or limit
2536 case 'm':
2537 preserve &= ~MTIME;
2538 break;
2539 // ?man -o: specify output file
2540 case 'o':
2541 preserve |= UID | GID;
2542 break;
2543 // ?man -p: preserve file attributes
2544 case 'p':
2545 preserve |= MODE;
2546 break;
2547 default:
2548 fatal("unknown -p option");
2549 }
2550 }
2551 break;
2552 // ?man -r: operate recursively
2553 case 'r':
2554 mode |= READ;
2555 break;
2556 // ?man -s:str: silent mode or print summary
2557 case 's':
2558 parsereplstr(EARGF(usage()));
2559 break;
2560 // ?man -t: sort or specify timestamp
2561 case 't':
2562 tflag = 1;
2563 break;
2564 // ?man -u: unbuffered output
2565 case 'u':
2566 uflag = 1;
2567 break;
2568 // ?man -v: verbose mode; show progress
2569 case 'v':
2570 vflag = 1;
2571 break;
2572 // ?man -w: wait for completion
2573 case 'w':
2574 mode |= WRITE;
2575 break;
2576 // ?man -x:str: hex format or match whole lines
2577 case 'x':
2578 format = EARGF(usage());
2579 break;
2580 // ?man -X: specify option flag
2581 case 'X':
2582 Xflag = 1;
2583 break;
2584 // ?man -z: specify option flag
2585 case 'z':
2586 algo = "gzip";
2587 break;
2588 default:
2589 usage();
2590 }
2591 ARGEND;
2592
2593 curtime = time(NULL);
2594 if (curtime == (time_t)-1)
2595 fatal("time:");
2596 exthdr.fields &= ~opt.delete;
2597 exthdr.delete = exthdr.fields;
2598 globexthdr.fields &= ~opt.delete;
2599 globexthdr.delete = globexthdr.fields;
2600 if ((exthdr.fields | globexthdr.fields | opt.delete) & SIZE)
2601 fatal("field 'size' cannot be overridden or deleted");
2602
2603 switch (mode) {
2604 case READ:
2605 writehdr = writefile;
2606 /* fallthrough */
2607 case LIST:
2608 if (name && strcmp(name, "-") != 0) {
2609 bioin.fd = open(name, O_RDONLY);
2610 if (bioin.fd < 0)
2611 fatal("open %s:", name);
2612 }
2613 readhdr = detectformat(&bioin, algo, &pid);
2614 if (!readhdr)
2615 fatal("could not detect archive format");
2616 if (argc) {
2617 pats = argv;
2618 patslen = argc;
2619 patsused = calloc(1, argc);
2620 if (!patsused)
2621 fatal(NULL);
2622 }
2623 break;
2624 case WRITE:
2625 if (name && strcmp(name, "-") == 0)
2626 name = NULL;
2627 handle_append(name, algo, format);
2628 out = compress(algo, name, &pid);
2629 if (strcmp(format, "ustar") == 0) {
2630 writehdr = writeustar;
2631 } else if (strcmp(format, "pax") == 0) {
2632 writehdr = writepax;
2633 if (globexthdr.fields)
2634 writeexthdr(stdout, 'g', &globexthdr);
2635 } else if (strcmp(format, "cpio") == 0) {
2636 writehdr = writecpio;
2637 } else {
2638 fatal("unsupported archive format '%s'", format);
2639 }
2640 break;
2641 case COPY:
2642 if (name || argc == 0)
2643 usage();
2644 l = strlen(argv[--argc]);
2645 dest = malloc(l + 2);
2646 if (!dest)
2647 fatal(NULL);
2648 memcpy(dest, argv[argc], l);
2649 memcpy(dest + l, "/", 2);
2650 destfd = open(dest, O_SEARCH | O_DIRECTORY);
2651 if (destfd < 0)
2652 fatal("open %s:", dest);
2653 writehdr = writefile;
2654 break;
2655 }
2656 if (mode & WRITE) {
2657 readhdr = readfile;
2658 bioin.fd = -1;
2659 for (i = 0; i < argc; ++i)
2660 filepush(&files, argv[i], 0, 0);
2661 if (argc == 0)
2662 files.input = stdin;
2663 }
2664
2665 memset(&hdr, 0, sizeof hdr);
2666 while (readhdr(&bioin, &hdr)) {
2667 mergehdr(&hdr, &exthdr, ~0);
2668 mergehdr(&hdr, &globexthdr, ~exthdr.fields);
2669 if (match(&hdr)) {
2670 replace(&hdr);
2671 checkinvalid(&hdr);
2672 interactiverename(&hdr);
2673 if (*hdr.path)
2674 writehdr(out, &hdr);
2675 }
2676 }
2677 writehdr(out, NULL);
2678 if (out) {
2679 if (fflush(out) != 0)
2680 fatal("write:");
2681 fclose(out);
2682 }
2683 for (i = 0; i < (int)patslen; ++i) {
2684 if (!patsused[i])
2685 fatal("pattern not matched: %s", pats[i]);
2686 }
2687
2688 if (pid != -1) {
2689 int st;
2690
2691 if (waitpid(pid, &st, 0) == -1)
2692 fatal("waitpid:");
2693 if (WIFEXITED(st) && WEXITSTATUS(st) != 0)
2694 fatal("child exited with status %d", WEXITSTATUS(st));
2695 if (WIFSIGNALED(st))
2696 fatal("child terminated by signal %d", WTERMSIG(st));
2697 }
2698 return exitstatus;
2699}