summaryrefslogtreecommitdiff
path: root/package/heirloom-cpio/src/pax.c
diff options
context:
space:
mode:
Diffstat (limited to 'package/heirloom-cpio/src/pax.c')
-rw-r--r--package/heirloom-cpio/src/pax.c757
1 files changed, 757 insertions, 0 deletions
diff --git a/package/heirloom-cpio/src/pax.c b/package/heirloom-cpio/src/pax.c
new file mode 100644
index 000000000..50632b6b1
--- /dev/null
+++ b/package/heirloom-cpio/src/pax.c
@@ -0,0 +1,757 @@
+/*
+ * cpio - copy file archives in and out
+ *
+ * Gunnar Ritter, Freiburg i. Br., Germany, April 2003.
+ */
+/*
+ * Copyright (c) 2003 Gunnar Ritter
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software
+ * in a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+
+#if __GNUC__ >= 3 && __GNUC_MINOR__ >= 4 || __GNUC__ >= 4
+#define USED __attribute__ ((used))
+#elif defined __GNUC__
+#define USED __attribute__ ((unused))
+#else
+#define USED
+#endif
+#if defined (SU3)
+static const char sccsid[] USED = "@(#)pax_su3.sl 1.26 (gritter) 6/26/05";
+#else
+static const char sccsid[] USED = "@(#)pax.sl 1.26 (gritter) 6/26/05";
+#endif
+/* Sccsid @(#)pax.c 1.26 (gritter) 6/26/05 */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fnmatch.h>
+#include <dirent.h>
+#include <regex.h>
+#include <wchar.h>
+#include <time.h>
+#include <inttypes.h>
+
+#include "iblok.h"
+#include "cpio.h"
+
+static char **files;
+static int filec;
+static struct iblok *filinp;
+static char *path;
+static size_t pathsz;
+static int pax_Hflag;
+
+static void setpres(const char *);
+static size_t ofiles_pax(char **, size_t *);
+static void prtime_pax(time_t);
+static void parsesub(char *);
+
+void
+flags(int ac, char **av)
+{
+ const char optstring[] = "rwab:cdf:HikKlLno:p:s:tuvx:X";
+ int i;
+ int illegal = 0;
+ char *x;
+
+#if defined (SU3)
+ pax = PAX_TYPE_PAX2001;
+#else
+ pax = PAX_TYPE_PAX1992;
+#endif
+ dflag = 1;
+ uflag = 1;
+ ofiles = ofiles_pax;
+ prtime = prtime_pax;
+ while ((i = getopt(ac, av, optstring)) != EOF) {
+ switch (i) {
+ case 'r':
+ if (action && action != 'i')
+ action = 'p';
+ else
+ action = 'i';
+ break;
+ case 'w':
+ if (action && action != 'o')
+ action = 'p';
+ else
+ action = 'o';
+ break;
+ case 'a':
+ Aflag = 1;
+ break;
+ case 'b':
+ blksiz = strtol(optarg, &x, 10);
+ switch (*x) {
+ case 'b':
+ blksiz *= 512;
+ break;
+ case 'k':
+ blksiz *= 1024;
+ break;
+ case 'm':
+ blksiz *= 1048576;
+ break;
+ case 'w':
+ blksiz *= 2;
+ break;
+ }
+ if (blksiz <= 0)
+ msg(4, -2,
+ "Illegal size given for -b option.\n");
+ Cflag = 1;
+ break;
+ case 'c':
+ fflag = 1;
+ break;
+ case 'd':
+ pax_dflag = 1;
+ break;
+ case 'f':
+ Oflag = Iflag = optarg;
+ break;
+ case 'H':
+ pax_Hflag = 1;
+ break;
+ case 'i':
+ rflag = 1;
+ break;
+ case 'k':
+ pax_kflag = 1;
+ break;
+ case 'K':
+ kflag = 1;
+ break;
+ case 'l':
+ lflag = 1;
+ break;
+ case 'L':
+ Lflag = 1;
+ break;
+ case 'n':
+ pax_nflag = 1;
+ break;
+ case 'o':
+ pax_options(optarg, 1);
+ break;
+ case 'p':
+ setpres(optarg);
+ break;
+ case 's':
+ pax_sflag = 1;
+ parsesub(optarg);
+ break;
+ case 't':
+ aflag = 1;
+ break;
+ case 'u':
+ uflag = 0;
+ pax_uflag = 1;
+ break;
+ case 'v':
+ vflag = 1;
+ break;
+ case 'x':
+ if (strcmp(optarg, "cpio") == 0)
+ fmttype = FMT_ODC;
+ else {
+ if (setfmt(optarg) < 0)
+ illegal = 1;
+ }
+ break;
+ case 'X':
+ pax_Xflag = 1;
+ break;
+ default:
+ illegal = 1;
+ }
+ }
+ switch (action) {
+ case 0:
+ if (rflag || pax_kflag || pax_uflag || pax_preserve)
+ illegal = 1;
+ action = 'i';
+ tflag = 1;
+ setvbuf(stdout, NULL, _IOLBF, 0);
+ /*FALLTHRU*/
+ case 'i':
+ if (aflag || pax_Xflag || lflag)
+ illegal = 1;
+ for (i = optind; i < ac; i++) {
+ addg(av[i], 0);
+ if (pax_dflag == 0) {
+ char *da;
+ int j;
+
+ da = smalloc(strlen(av[i]) + 2);
+ for (j = 0; av[i][j]; j++)
+ da[j] = av[i][j];
+ da[j++] = '/';
+ da[j++] = '*';
+ da[j] = 0;
+ addg(da, 1);
+ free(da);
+ }
+ }
+ break;
+ case 'o':
+ if (fflag || pax_kflag || pax_nflag || kflag)
+ illegal = 1;
+ if (Aflag && Oflag == NULL) {
+ msg(3, 0, "-a requires the -f option\n");
+ illegal = 1;
+ }
+ if (optind != ac) {
+ files = &av[optind];
+ filec = ac - optind;
+ } else
+ filinp = ib_alloc(0, 0);
+ if (pax_uflag)
+ Aflag = 1;
+ if (Aflag == 0 && fmttype == FMT_NONE)
+ fmttype = FMT_ODC;
+ break;
+ case 'p':
+ if (fflag || blksiz || Oflag || Iflag || fmttype != FMT_NONE ||
+ kflag)
+ illegal = 1;
+ if (optind == ac)
+ illegal = 1;
+ else if (optind+1 != ac) {
+ files = &av[optind];
+ filec = ac - optind - 1;
+ optind = ac - 1;
+ } else
+ filinp = ib_alloc(0, 0);
+ break;
+ }
+ if (illegal)
+ usage();
+}
+
+void
+usage(void)
+{
+ fprintf(stderr, "USAGE:\n\
+\t%s [-cdnvK] [-b size] [-f file] [-s replstr] [-x hdr] [patterns]\n\
+\t%s -r[cdiknuvK] [-b size] [-f file] [-p priv] [-s replstr] [-x hdr] [patterns]\n\
+\t%s -w[adituvLX] [-b size] [-f file] [-s replstr] [-x hdr] [files]\n\
+\t%s -rw[diklntuvLX] [-p priv] [-s replstr] [files] directory\n",
+ progname, progname, progname, progname);
+ exit(1);
+}
+
+static void
+setpres(const char *s)
+{
+ s--;
+ while (*++s) {
+ pax_preserve &= ~PAX_P_EVERY;
+ switch (*s) {
+ case 'a':
+ pax_preserve |= PAX_P_ATIME;
+ break;
+ case 'e':
+ pax_preserve |= PAX_P_EVERY;
+ break;
+ case 'm':
+ pax_preserve |= PAX_P_MTIME;
+ break;
+ case 'o':
+ pax_preserve |= PAX_P_OWNER;
+ break;
+ case 'p':
+ pax_preserve |= PAX_P_MODE;
+ break;
+ default:
+ msg(2, 0, "ignoring unknown option \"-p%c\"\n",
+ *s&0377);
+ }
+ }
+ if (pax_preserve & PAX_P_EVERY)
+ pax_preserve |= PAX_P_OWNER|PAX_P_MODE;
+}
+
+int
+gmatch(const char *s, const char *p)
+{
+ int val;
+#ifdef __GLIBC__
+ /* avoid glibc's broken [^...] */
+ extern char **environ;
+ char **savenv = environ;
+ char *newenv[] = { "POSIXLY_CORRECT=", NULL };
+ environ = newenv;
+#endif /* __GLIBC__ */
+ val = fnmatch(p, s, 0) == 0;
+#ifdef __GLIBC__
+ environ = savenv;
+#endif /* __GLIBC__ */
+ return val;
+}
+
+static const char *
+nextfile(void)
+{
+ char *line = NULL;
+ size_t linsiz = 0, linlen;
+
+ if (filinp) {
+ pax_Hflag = 0;
+ if ((linlen=ib_getlin(filinp, &line, &linsiz, srealloc)) == 0) {
+ filinp = NULL;
+ return NULL;
+ }
+ if (line[linlen-1] == '\n')
+ line[--linlen] = '\0';
+ return line;
+ } else if (filec > 0) {
+ filec--;
+ return *files++;
+ } else
+ return NULL;
+}
+
+static size_t
+catpath(size_t pend, const char *base)
+{
+ size_t blen = strlen(base);
+
+ if (pend + blen + 2 >= pathsz)
+ path = srealloc(path, pathsz = pend + blen + 16);
+ if (pend == 0 || path[pend-1] != '/')
+ path[pend++] = '/';
+ strcpy(&path[pend], base);
+ return pend + blen;
+}
+
+/*
+ * Descend the directory hierarchies given using stdin or arguments
+ * and return file names one per one.
+ */
+static size_t
+ofiles_pax(char **name, size_t *namsiz)
+{
+ static DIR **dt;
+ static int dti, dts;
+ static int *pend;
+ static dev_t *curdev;
+ static ino_t *curino;
+ struct stat st;
+ struct dirent *dp;
+ const char *nf;
+ int i;
+
+ if (dt == NULL) {
+ dt = scalloc(dts = 1, sizeof *dt);
+ pend = scalloc(dts, sizeof *pend);
+ curdev = scalloc(dts, sizeof *curdev);
+ curino = scalloc(dts, sizeof *curino);
+ }
+ for (;;) {
+ if (dti >= 0 && dt[dti] != NULL) {
+ if ((dp = readdir(dt[dti])) != NULL) {
+ if (dp->d_name[0] == '.' &&
+ (dp->d_name[1] == '\0' ||
+ dp->d_name[1] == '.' &&
+ dp->d_name[2] == '\0'))
+ continue;
+ if (dti+1 <= dts) {
+ dt = srealloc(dt, sizeof *dt * ++dts);
+ pend = srealloc(pend, sizeof *pend*dts);
+ curdev = srealloc(curdev, sizeof *curdev
+ * dts);
+ curino = srealloc(curino, sizeof *curino
+ * dts);
+ }
+ pend[dti+1] = catpath(pend[dti], dp->d_name);
+ if (pax_Hflag)
+ Lflag = dti < 0;
+ if ((Lflag ? stat : lstat)(path, &st) < 0) {
+ emsg(2, "Error with %s of \"%s\"",
+ lflag? "stat" : "lstat",
+ path);
+ errcnt++;
+ } else if ((st.st_mode&S_IFMT) == S_IFDIR &&
+ (pax_Xflag == 0 ||
+ curdev[0] == st.st_dev)) {
+ if (Lflag) {
+ for (i = 0; i <= dti; i++)
+ if (st.st_dev ==
+ curdev[i] &&
+ st.st_ino ==
+ curino[i]) {
+ if (pax ==
+ PAX_TYPE_PAX2001)
+ msg(4, 1,
+ "Symbolic link "
+ "loop at "
+ "\"%s\"\n",
+ path);
+ break;
+ }
+ if (i <= dti)
+ break;
+ }
+ if ((dt[dti+1]=opendir(path)) == NULL) {
+ emsg(2, "Cannot open directory "
+ "\"%s\"", path);
+ errcnt++;
+ } else {
+ dti++;
+ curdev[dti] = st.st_dev;
+ curino[dti] = st.st_ino;
+ continue;
+ }
+ } else
+ break;
+ } else {
+ path[pend[dti]] = '\0';
+ closedir(dt[dti]);
+ dt[dti--] = NULL;
+ if (pax_Hflag)
+ Lflag = dti < 0;
+ break;
+ }
+ } else {
+ if (pax_Hflag)
+ Lflag = 1;
+ while ((nf = nextfile()) != NULL &&
+ (Lflag ? stat : lstat)(nf, &st) < 0) {
+ emsg(2, "Error with stat of \"%s\"", nf);
+ errcnt++;
+ }
+ if (nf == NULL)
+ return 0;
+ dti = 0;
+ if (path)
+ free(path);
+ pend[dti] = strlen(nf);
+ strcpy(path = smalloc(pathsz = pend[dti]+1), nf);
+ if (pax_dflag || (st.st_mode&S_IFMT) != S_IFDIR) {
+ dti = -1;
+ break;
+ }
+ curdev[dti] = st.st_dev;
+ curino[dti] = st.st_ino;
+ if ((dt[dti] = opendir(path)) == NULL) {
+ emsg(2, "Cannot open directory \"%s\"", path);
+ errcnt++;
+ }
+ }
+ }
+ if (*name == NULL || *namsiz < pathsz) {
+ free(*name);
+ *name = smalloc(*namsiz=pathsz);
+ }
+ strcpy(*name, path);
+ return pend[dti+1];
+}
+
+struct pax_had {
+ struct pax_had *p_next;
+ const char *p_name;
+ time_t p_mtime;
+};
+
+static int pprime = 7919;
+
+static int
+phash(const char *s)
+{
+ uint32_t h = 0, g;
+
+ s--;
+ while (*++s) {
+ h = (h << 4) + (*s & 0377);
+ if (g = h & 0xf0000000) {
+ h = h ^ (g >> 24);
+ h = h ^ g;
+ }
+ }
+ return h % pprime;
+}
+
+static int
+plook(const char *name, struct pax_had **pp)
+{
+ static struct pax_had **pt;
+ uint32_t h, had;
+
+ if (pt == NULL)
+ pt = scalloc(pprime, sizeof *pt);
+ (*pp) = pt[h = phash(name)];
+ while (*pp != NULL) {
+ if (strcmp((*pp)->p_name, name) == 0)
+ break;
+ *pp = (*pp)->p_next;
+ }
+ had = *pp != NULL;
+ if (*pp == NULL) {
+ *pp = scalloc(1, sizeof **pp);
+ (*pp)->p_name = sstrdup(name);
+ (*pp)->p_next = pt[h];
+ pt[h] = *pp;
+ }
+ return had;
+}
+
+int
+pax_track(const char *name, time_t mtime)
+{
+ struct pax_had *pp;
+ struct stat st;
+
+ if (pax_uflag == 0 && (pax_nflag == 0 || patterns))
+ return 1;
+ if (action == 'i' && pax_uflag) {
+ if (lstat(name, &st) == 0 && mtime < st.st_mtime)
+ return 0;
+ }
+ if (action != 'i' || pax_nflag) {
+ if (plook(name, &pp) != 0) {
+ if (action != 'i' && pax_uflag == 0)
+ return 0;
+ if (mtime > pp->p_mtime) {
+ pp->p_mtime = mtime;
+ return 1;
+ }
+ return 0;
+ } else
+ pp->p_mtime = mtime;
+ }
+ return 1;
+}
+
+static void
+prtime_pax(time_t t)
+{
+ char b[30];
+ time_t now;
+
+ time(&now);
+ if (t > now || t < now - (6*30*86400))
+ strftime(b, sizeof b, "%b %e %Y", localtime(&t));
+ else
+ strftime(b, sizeof b, "%b %e %H:%M", localtime(&t));
+ printf(" %s ", b);
+}
+
+struct replacement {
+ regex_t r_re;
+ const char *r_rhs;
+ int r_nbra;
+ enum {
+ REPL_0 = 0,
+ REPL_G = 1,
+ REPL_P = 2
+ } r_flags;
+} *rep;
+
+#define NBRA 9
+static int ren, res;
+static int mb_cur_max;
+
+static wchar_t
+nextc(char **sc, int *np)
+{
+ char *p = *sc;
+ wchar_t wcbuf;
+ int len;
+
+ if (**sc == '\0') {
+ *np = 0;
+ return 0;
+ }
+ if (mb_cur_max == 1 || (**sc&0200) == 0) {
+ *np = 1;
+ return *(*sc)++ & 0377;
+ }
+ if ((len = mbtowc(&wcbuf, p, mb_cur_max)) < 0)
+ msg(3, -2, "Invalid multibyte character for \"-s\" option\n");
+ *np = len;
+ *sc += len;
+ return wcbuf;
+}
+
+static void
+parsesub(char *s)
+{
+ int len;
+ char *ps = NULL;
+ wchar_t seof = nextc(&s, &len);
+ wint_t c, d;
+ int nbra = 0;
+ int reflags;
+
+ if (seof == 0)
+ goto unt;
+ mb_cur_max = MB_CUR_MAX;
+ ps = s;
+ do {
+ if ((c = nextc(&s, &len)) == seof)
+ break;
+ if (c == '\\') {
+ if ((c = nextc(&s, &len)) == '(')
+ nbra++;
+ continue;
+ } else if (c == '[') {
+ d = WEOF;
+ do {
+ if ((c = nextc(&s, &len)) == '\0')
+ continue;
+ if (d == '[' && (c == ':' || c == '.' ||
+ c == '=')) {
+ d = c;
+ do {
+ if ((c=nextc(&s, &len)) == '\0')
+ continue;
+ } while (c != d || *s != ']');
+ nextc(&s, &len);
+ c = WEOF; /* reset d and continue */
+ }
+ d = c;
+ } while (c != ']');
+ }
+ } while (*s != '\0');
+ if (c != seof)
+ unt: msg(3, -2, "Unterminated argument for \"-s\" option.\n");
+ s[-len] = '\0';
+ if (ren <= res)
+ rep = srealloc(rep, ++res * sizeof *rep);
+ reflags = REG_ANGLES;
+ if (pax >= PAX_TYPE_PAX2001)
+ reflags |= REG_AVOIDNULL;
+ if (regcomp(&rep[ren].r_re, ps, reflags) != 0)
+ msg(3, -2, "Regular expression error in \"-s\" option\n");
+ rep[ren].r_rhs = s;
+ rep[ren].r_nbra = nbra;
+ while ((c = nextc(&s, &len)) != 0) {
+ if (c == '\\')
+ c = nextc(&s, &len);
+ else if (c == seof)
+ break;
+ }
+ rep[ren].r_flags = 0;
+ if (c == seof) {
+ s[-len] = '\0';
+ while ((c = nextc(&s, &len)) != '\0') {
+ switch (c) {
+ case 'g':
+ rep[ren].r_flags |= REPL_G;
+ break;
+ case 'p':
+ rep[ren].r_flags |= REPL_P;
+ break;
+ default:
+ msg(2, 0, "Ignoring unknown -s flag \"%c\"\n",
+ c);
+ }
+ }
+ }
+ ren++;
+}
+
+#define put(c) ((new = innew+1>=newsize ? srealloc(new, newsize+=32) : new), \
+ new[innew++] = (c))
+
+int
+pax_sname(char **oldp, size_t *olds)
+{
+ char *new = NULL;
+ size_t newsize = 0;
+ regmatch_t bralist[NBRA+1];
+ int c, i, k, l, y, z;
+ int innew = 0, ef = 0;
+ char *inp = *oldp;
+
+ for (z = 0; z < ren; z++) {
+ in: if (regexec(&rep[z].r_re, inp, NBRA+1, bralist, ef) != 0) {
+ if (ef == 0)
+ continue;
+ goto out;
+ }
+ for (i = 0; i < bralist[0].rm_so; i++)
+ put(inp[i]);
+ k = 0;
+ while (c = rep[z].r_rhs[k++] & 0377) {
+ y = -1;
+ if (c == '&')
+ y = 0;
+ else if (c == '\\') {
+ c = rep[z].r_rhs[k++] & 0377;
+ if (c >= '1' && c < rep[z].r_nbra+'1')
+ y = c - '0';
+ }
+ if (y >= 0)
+ for (l = bralist[y].rm_so; l < bralist[y].rm_eo;
+ l++)
+ put(inp[l]);
+ else
+ put(c);
+ }
+ k = innew;
+ for (i = bralist[0].rm_eo; inp[i]; i++)
+ put(inp[i]);
+ put('\0');
+ if (rep[z].r_flags & REPL_G) {
+ ef = REG_NOTBOL;
+ inp = &inp[bralist[0].rm_eo];
+ innew = k;
+ if (bralist[0].rm_so == bralist[0].rm_eo) {
+ if (inp[0] && (nextc(&inp, &l), inp[0]))
+ innew++;
+ else
+ goto out;
+ }
+ goto in;
+ }
+ out: if (rep[z].r_flags & REPL_P)
+ fprintf(stderr, "%s >> %s\n", *oldp, new);
+ free(*oldp);
+ *oldp = new;
+ *olds = newsize;
+ return *new != '\0';
+ }
+ return 1;
+}
+
+void
+pax_onexit(void)
+{
+ struct glist *gp;
+
+ for (gp = patterns; gp; gp = gp->g_nxt) {
+ if (gp->g_art)
+ continue;
+ if (gp->g_gotcha == 0 && (gp->g_nxt == NULL ||
+ gp->g_nxt->g_art == 0 ||
+ gp->g_gotcha == 0)) {
+ msg(3, 0, "Pattern not matched: \"%s\"\n", gp->g_pat);
+ errcnt++;
+ }
+ }
+}