diff options
Diffstat (limited to 'package/heirloom-cpio/src/pax.c')
-rw-r--r-- | package/heirloom-cpio/src/pax.c | 757 |
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++; + } + } +} |