[BACK]Return to gzip.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / usr.bin / gzip

Annotation of src/usr.bin/gzip/gzip.c, Revision 1.102

1.102   ! christos    1: /*     $NetBSD: gzip.c,v 1.101 2011/06/19 01:20:19 tsutsui Exp $       */
1.1       mrg         2:
                      3: /*
1.84      mrg         4:  * Copyright (c) 1997, 1998, 2003, 2004, 2006 Matthew R. Green
1.1       mrg         5:  * All rights reserved.
                      6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer in the
                     14:  *    documentation and/or other materials provided with the distribution.
                     15:  *
                     16:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     17:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     18:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     19:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
                     20:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
                     21:  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
                     22:  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
                     23:  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
                     24:  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     25:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     26:  * SUCH DAMAGE.
                     27:  */
                     28:
1.4       mrg        29: #include <sys/cdefs.h>
                     30: #ifndef lint
1.92      lukem      31: __COPYRIGHT("@(#) Copyright (c) 1997, 1998, 2003, 2004, 2006\
                     32:  Matthew R. Green.  All rights reserved.");
1.102   ! christos   33: __RCSID("$NetBSD: gzip.c,v 1.101 2011/06/19 01:20:19 tsutsui Exp $");
1.4       mrg        34: #endif /* not lint */
                     35:
1.1       mrg        36: /*
                     37:  * gzip.c -- GPL free gzip using zlib.
                     38:  *
1.65      dsl        39:  * RFC 1950 covers the zlib format
                     40:  * RFC 1951 covers the deflate format
                     41:  * RFC 1952 covers the gzip format
                     42:  *
1.6       mrg        43:  * TODO:
1.10      mrg        44:  *     - use mmap where possible
1.16      wiz        45:  *     - handle some signals better (remove outfile?)
1.41      mrg        46:  *     - make bzip2/compress -v/-t/-l support work as well as possible
1.1       mrg        47:  */
                     48:
                     49: #include <sys/param.h>
                     50: #include <sys/stat.h>
                     51: #include <sys/time.h>
                     52:
1.63      dsl        53: #include <inttypes.h>
1.1       mrg        54: #include <unistd.h>
                     55: #include <stdio.h>
                     56: #include <string.h>
                     57: #include <stdlib.h>
                     58: #include <err.h>
                     59: #include <errno.h>
                     60: #include <fcntl.h>
                     61: #include <zlib.h>
                     62: #include <fts.h>
                     63: #include <libgen.h>
                     64: #include <stdarg.h>
                     65: #include <getopt.h>
1.69      jmc        66: #include <time.h>
1.1       mrg        67:
1.63      dsl        68: #ifndef PRIdOFF
                     69: #define PRIdOFF PRId64
                     70: #endif
                     71:
1.10      mrg        72: /* what type of file are we dealing with */
                     73: enum filetype {
                     74:        FT_GZIP,
1.24      tsutsui    75: #ifndef NO_BZIP2_SUPPORT
1.10      mrg        76:        FT_BZIP2,
1.24      tsutsui    77: #endif
                     78: #ifndef NO_COMPRESS_SUPPORT
1.22      mrg        79:        FT_Z,
1.24      tsutsui    80: #endif
1.95      mrg        81: #ifndef NO_PACK_SUPPORT
                     82:        FT_PACK,
                     83: #endif
1.100     christos   84: #ifndef NO_XZ_SUPPORT
                     85:        FT_XZ,
                     86: #endif
1.10      mrg        87:        FT_LAST,
                     88:        FT_UNKNOWN
                     89: };
                     90:
1.24      tsutsui    91: #ifndef NO_BZIP2_SUPPORT
1.10      mrg        92: #include <bzlib.h>
                     93:
1.24      tsutsui    94: #define BZ2_SUFFIX     ".bz2"
                     95: #define BZIP2_MAGIC    "\102\132\150"
                     96: #endif
                     97:
                     98: #ifndef NO_COMPRESS_SUPPORT
1.22      mrg        99: #define Z_SUFFIX       ".Z"
                    100: #define Z_MAGIC                "\037\235"
1.24      tsutsui   101: #endif
1.10      mrg       102:
1.95      mrg       103: #ifndef NO_PACK_SUPPORT
                    104: #define PACK_MAGIC     "\037\036"
                    105: #endif
                    106:
1.100     christos  107: #ifndef NO_XZ_SUPPORT
                    108: #include <lzma.h>
                    109: #define XZ_SUFFIX      ".xz"
                    110: #define XZ_MAGIC       "\3757zXZ"
                    111: #endif
                    112:
1.10      mrg       113: #define GZ_SUFFIX      ".gz"
1.1       mrg       114:
1.37      mrg       115: #define BUFLEN         (64 * 1024)
1.1       mrg       116:
1.9       mrg       117: #define GZIP_MAGIC0    0x1F
1.10      mrg       118: #define GZIP_MAGIC1    0x8B
                    119: #define GZIP_OMAGIC1   0x9E
1.9       mrg       120:
1.48      mrg       121: #define GZIP_TIMESTAMP (off_t)4
1.47      mrg       122: #define GZIP_ORIGNAME  (off_t)10
                    123:
1.37      mrg       124: #define HEAD_CRC       0x02
                    125: #define EXTRA_FIELD    0x04
                    126: #define ORIG_NAME      0x08
                    127: #define COMMENT                0x10
1.1       mrg       128:
1.37      mrg       129: #define OS_CODE                3       /* Unix */
1.1       mrg       130:
1.63      dsl       131: typedef struct {
1.66      dsl       132:     const char *zipped;
1.63      dsl       133:     int                ziplen;
1.66      dsl       134:     const char *normal;        /* for unzip - must not be longer than zipped */
1.63      dsl       135: } suffixes_t;
                    136: static suffixes_t suffixes[] = {
1.66      dsl       137: #define        SUFFIX(Z, N) {Z, sizeof Z - 1, N}
1.63      dsl       138:        SUFFIX(GZ_SUFFIX,       ""),    /* Overwritten by -S .xxx */
                    139: #ifndef SMALL
                    140:        SUFFIX(GZ_SUFFIX,       ""),
                    141:        SUFFIX(".z",            ""),
                    142:        SUFFIX("-gz",           ""),
                    143:        SUFFIX("-z",            ""),
                    144:        SUFFIX("_z",            ""),
                    145:        SUFFIX(".taz",          ".tar"),
                    146:        SUFFIX(".tgz",          ".tar"),
1.56      mrg       147: #ifndef NO_BZIP2_SUPPORT
1.63      dsl       148:        SUFFIX(BZ2_SUFFIX,      ""),
1.56      mrg       149: #endif
                    150: #ifndef NO_COMPRESS_SUPPORT
1.63      dsl       151:        SUFFIX(Z_SUFFIX,        ""),
1.56      mrg       152: #endif
1.102   ! christos  153: #ifndef NO_XZ_SUPPORT
        !           154:        SUFFIX(XZ_SUFFIX,       ""),
        !           155: #endif
1.63      dsl       156:        SUFFIX(GZ_SUFFIX,       ""),    /* Overwritten by -S "" */
                    157: #endif /* SMALL */
                    158: #undef SUFFIX
1.56      mrg       159: };
1.63      dsl       160: #define NUM_SUFFIXES (sizeof suffixes / sizeof suffixes[0])
1.96      mrg       161: #define SUFFIX_MAXLEN  30
1.56      mrg       162:
1.98      mrg       163: static const char      gzip_version[] = "NetBSD gzip 20101018";
1.1       mrg       164:
                    165: static int     cflag;                  /* stdout mode */
                    166: static int     dflag;                  /* decompress mode */
1.25      mrg       167: static int     lflag;                  /* list mode */
1.41      mrg       168: static int     numflag = 6;            /* gzip -1..-9 value */
1.26      mrg       169:
1.25      mrg       170: #ifndef SMALL
1.1       mrg       171: static int     fflag;                  /* force mode */
1.98      mrg       172: static int     kflag;                  /* don't delete input files */
1.1       mrg       173: static int     nflag;                  /* don't save name/timestamp */
                    174: static int     Nflag;                  /* don't restore name/timestamp */
                    175: static int     qflag;                  /* quiet mode */
                    176: static int     rflag;                  /* recursive mode */
1.26      mrg       177: static int     tflag;                  /* test */
                    178: static int     vflag;                  /* verbose mode */
1.25      mrg       179: #else
                    180: #define                qflag   0
1.66      dsl       181: #define                tflag   0
1.25      mrg       182: #endif
1.26      mrg       183:
1.46      mrg       184: static int     exit_value = 0;         /* exit value */
                    185:
1.1       mrg       186: static char    *infile;                /* name of file coming in */
                    187:
1.63      dsl       188: static void    maybe_err(const char *fmt, ...)
                    189:     __attribute__((__format__(__printf__, 1, 2)));
1.101     tsutsui   190: #if !defined(NO_BZIP2_SUPPORT) || !defined(NO_PACK_SUPPORT) || \
                    191:     !defined(NO_XZ_SUPPORT)
1.63      dsl       192: static void    maybe_errx(const char *fmt, ...)
                    193:     __attribute__((__format__(__printf__, 1, 2)));
1.66      dsl       194: #endif
1.63      dsl       195: static void    maybe_warn(const char *fmt, ...)
                    196:     __attribute__((__format__(__printf__, 1, 2)));
                    197: static void    maybe_warnx(const char *fmt, ...)
                    198:     __attribute__((__format__(__printf__, 1, 2)));
1.32      mrg       199: static enum filetype file_gettype(u_char *);
1.63      dsl       200: #ifdef SMALL
                    201: #define gz_compress(if, of, sz, fn, tm) gz_compress(if, of, sz)
                    202: #endif
                    203: static off_t   gz_compress(int, int, off_t *, const char *, uint32_t);
1.46      mrg       204: static off_t   gz_uncompress(int, int, char *, size_t, off_t *, const char *);
1.45      agc       205: static off_t   file_compress(char *, char *, size_t);
                    206: static off_t   file_uncompress(char *, char *, size_t);
1.1       mrg       207: static void    handle_pathname(char *);
                    208: static void    handle_file(char *, struct stat *);
                    209: static void    handle_stdin(void);
                    210: static void    handle_stdout(void);
1.6       mrg       211: static void    print_ratio(off_t, off_t, FILE *);
1.7       mrg       212: static void    print_list(int fd, off_t, const char *, time_t);
1.10      mrg       213: static void    usage(void);
                    214: static void    display_version(void);
1.63      dsl       215: static const suffixes_t *check_suffix(char *, int);
1.71      yamt      216: static ssize_t read_retry(int, void *, size_t);
1.26      mrg       217:
1.63      dsl       218: #ifdef SMALL
                    219: #define unlink_input(f, sb) unlink(f)
                    220: #else
1.66      dsl       221: static off_t   cat_fd(unsigned char *, size_t, off_t *, int fd);
1.26      mrg       222: static void    prepend_gzip(char *, int *, char ***);
1.74      mrg       223: static void    handle_dir(char *);
1.63      dsl       224: static void    print_verbage(const char *, const char *, off_t, off_t);
1.45      agc       225: static void    print_test(const char *, int);
1.77      mrg       226: static void    copymodes(int fd, const struct stat *, const char *file);
                    227: static int     check_outfile(const char *outfile);
1.26      mrg       228: #endif
                    229:
1.24      tsutsui   230: #ifndef NO_BZIP2_SUPPORT
1.37      mrg       231: static off_t   unbzip2(int, int, char *, size_t, off_t *);
1.24      tsutsui   232: #endif
1.26      mrg       233:
1.24      tsutsui   234: #ifndef NO_COMPRESS_SUPPORT
1.63      dsl       235: static FILE    *zdopen(int);
1.37      mrg       236: static off_t   zuncompress(FILE *, FILE *, char *, size_t, off_t *);
1.24      tsutsui   237: #endif
1.1       mrg       238:
1.95      mrg       239: #ifndef NO_PACK_SUPPORT
                    240: static off_t   unpack(int, int, char *, size_t, off_t *);
                    241: #endif
                    242:
1.100     christos  243: #ifndef NO_XZ_SUPPORT
                    244: static off_t   unxz(int, int, char *, size_t, off_t *);
                    245: #endif
                    246:
1.1       mrg       247: int main(int, char *p[]);
                    248:
1.11      mrg       249: #ifdef SMALL
                    250: #define getopt_long(a,b,c,d,e) getopt(a,b,c)
                    251: #else
1.3       jdolecek  252: static const struct option longopts[] = {
1.1       mrg       253:        { "stdout",             no_argument,            0,      'c' },
                    254:        { "to-stdout",          no_argument,            0,      'c' },
                    255:        { "decompress",         no_argument,            0,      'd' },
                    256:        { "uncompress",         no_argument,            0,      'd' },
                    257:        { "force",              no_argument,            0,      'f' },
                    258:        { "help",               no_argument,            0,      'h' },
1.98      mrg       259:        { "keep",               no_argument,            0,      'k' },
1.5       mrg       260:        { "list",               no_argument,            0,      'l' },
1.1       mrg       261:        { "no-name",            no_argument,            0,      'n' },
                    262:        { "name",               no_argument,            0,      'N' },
                    263:        { "quiet",              no_argument,            0,      'q' },
                    264:        { "recursive",          no_argument,            0,      'r' },
                    265:        { "suffix",             required_argument,      0,      'S' },
                    266:        { "test",               no_argument,            0,      't' },
                    267:        { "verbose",            no_argument,            0,      'v' },
                    268:        { "version",            no_argument,            0,      'V' },
                    269:        { "fast",               no_argument,            0,      '1' },
                    270:        { "best",               no_argument,            0,      '9' },
                    271: #if 0
                    272:        /*
1.10      mrg       273:         * This is what else GNU gzip implements.  --ascii isn't useful
                    274:         * on NetBSD, and I don't care to have a --license.
1.1       mrg       275:         */
                    276:        { "ascii",              no_argument,            0,      'a' },
                    277:        { "license",            no_argument,            0,      'L' },
                    278: #endif
1.12      mrg       279:        { NULL,                 no_argument,            0,      0 },
1.1       mrg       280: };
1.11      mrg       281: #endif
1.1       mrg       282:
                    283: int
                    284: main(int argc, char **argv)
                    285: {
1.28      mrg       286:        const char *progname = getprogname();
1.25      mrg       287: #ifndef SMALL
1.15      mrg       288:        char *gzip;
1.63      dsl       289:        int len;
1.25      mrg       290: #endif
1.1       mrg       291:        int ch;
                    292:
1.15      mrg       293:        /* XXX set up signals */
                    294:
1.25      mrg       295: #ifndef SMALL
1.15      mrg       296:        if ((gzip = getenv("GZIP")) != NULL)
                    297:                prepend_gzip(gzip, &argc, &argv);
1.28      mrg       298: #endif
1.15      mrg       299:
1.1       mrg       300:        /*
                    301:         * XXX
                    302:         * handle being called `gunzip', `zcat' and `gzcat'
                    303:         */
                    304:        if (strcmp(progname, "gunzip") == 0)
                    305:                dflag = 1;
                    306:        else if (strcmp(progname, "zcat") == 0 ||
                    307:                 strcmp(progname, "gzcat") == 0)
                    308:                dflag = cflag = 1;
1.25      mrg       309:
                    310: #ifdef SMALL
1.99      tsutsui   311: #define OPT_LIST "123456789cdhlV"
1.25      mrg       312: #else
1.98      mrg       313: #define OPT_LIST "123456789cdfhklNnqrS:tVv"
1.25      mrg       314: #endif
1.1       mrg       315:
1.63      dsl       316:        while ((ch = getopt_long(argc, argv, OPT_LIST, longopts, NULL)) != -1) {
1.1       mrg       317:                switch (ch) {
1.81      wiz       318:                case '1': case '2': case '3':
                    319:                case '4': case '5': case '6':
                    320:                case '7': case '8': case '9':
                    321:                        numflag = ch - '0';
                    322:                        break;
1.1       mrg       323:                case 'c':
                    324:                        cflag = 1;
                    325:                        break;
                    326:                case 'd':
                    327:                        dflag = 1;
                    328:                        break;
1.5       mrg       329:                case 'l':
                    330:                        lflag = 1;
                    331:                        dflag = 1;
                    332:                        break;
1.26      mrg       333:                case 'V':
                    334:                        display_version();
                    335:                        /* NOTREACHED */
1.25      mrg       336: #ifndef SMALL
                    337:                case 'f':
                    338:                        fflag = 1;
                    339:                        break;
1.98      mrg       340:                case 'k':
                    341:                        kflag = 1;
                    342:                        break;
1.81      wiz       343:                case 'N':
                    344:                        nflag = 0;
                    345:                        Nflag = 1;
                    346:                        break;
1.1       mrg       347:                case 'n':
                    348:                        nflag = 1;
                    349:                        Nflag = 0;
                    350:                        break;
                    351:                case 'q':
                    352:                        qflag = 1;
                    353:                        break;
                    354:                case 'r':
                    355:                        rflag = 1;
                    356:                        break;
                    357:                case 'S':
1.63      dsl       358:                        len = strlen(optarg);
                    359:                        if (len != 0) {
1.96      mrg       360:                                if (len > SUFFIX_MAXLEN)
                    361:                                        errx(1, "incorrect suffix: '%s'", optarg);
1.66      dsl       362:                                suffixes[0].zipped = optarg;
1.63      dsl       363:                                suffixes[0].ziplen = len;
                    364:                        } else {
1.66      dsl       365:                                suffixes[NUM_SUFFIXES - 1].zipped = "";
1.63      dsl       366:                                suffixes[NUM_SUFFIXES - 1].ziplen = 0;
                    367:                        }
1.1       mrg       368:                        break;
                    369:                case 't':
                    370:                        cflag = 1;
                    371:                        tflag = 1;
                    372:                        dflag = 1;
                    373:                        break;
                    374:                case 'v':
                    375:                        vflag = 1;
                    376:                        break;
1.26      mrg       377: #endif
1.12      mrg       378:                default:
                    379:                        usage();
                    380:                        /* NOTREACHED */
1.1       mrg       381:                }
1.63      dsl       382:        }
1.1       mrg       383:        argv += optind;
                    384:        argc -= optind;
                    385:
                    386:        if (argc == 0) {
                    387:                if (dflag)      /* stdin mode */
                    388:                        handle_stdin();
                    389:                else            /* stdout mode */
                    390:                        handle_stdout();
                    391:        } else {
                    392:                do {
                    393:                        handle_pathname(argv[0]);
1.5       mrg       394:                } while (*++argv);
1.1       mrg       395:        }
1.29      mrg       396: #ifndef SMALL
1.6       mrg       397:        if (qflag == 0 && lflag && argc > 1)
1.7       mrg       398:                print_list(-1, 0, "(totals)", 0);
1.29      mrg       399: #endif
1.46      mrg       400:        exit(exit_value);
1.1       mrg       401: }
                    402:
                    403: /* maybe print a warning */
                    404: void
                    405: maybe_warn(const char *fmt, ...)
                    406: {
                    407:        va_list ap;
                    408:
                    409:        if (qflag == 0) {
                    410:                va_start(ap, fmt);
                    411:                vwarn(fmt, ap);
                    412:                va_end(ap);
                    413:        }
1.46      mrg       414:        if (exit_value == 0)
                    415:                exit_value = 1;
1.1       mrg       416: }
                    417:
1.46      mrg       418: /* ... without an errno. */
1.1       mrg       419: void
                    420: maybe_warnx(const char *fmt, ...)
                    421: {
                    422:        va_list ap;
                    423:
                    424:        if (qflag == 0) {
                    425:                va_start(ap, fmt);
                    426:                vwarnx(fmt, ap);
                    427:                va_end(ap);
                    428:        }
1.46      mrg       429:        if (exit_value == 0)
                    430:                exit_value = 1;
1.1       mrg       431: }
                    432:
1.46      mrg       433: /* maybe print an error */
1.1       mrg       434: void
1.46      mrg       435: maybe_err(const char *fmt, ...)
1.1       mrg       436: {
                    437:        va_list ap;
                    438:
                    439:        if (qflag == 0) {
                    440:                va_start(ap, fmt);
                    441:                vwarn(fmt, ap);
                    442:                va_end(ap);
                    443:        }
1.46      mrg       444:        exit(2);
1.1       mrg       445: }
                    446:
1.101     tsutsui   447: #if !defined(NO_BZIP2_SUPPORT) || !defined(NO_PACK_SUPPORT) || \
                    448:     !defined(NO_XZ_SUPPORT)
1.46      mrg       449: /* ... without an errno. */
1.9       mrg       450: void
1.46      mrg       451: maybe_errx(const char *fmt, ...)
1.9       mrg       452: {
                    453:        va_list ap;
                    454:
                    455:        if (qflag == 0) {
                    456:                va_start(ap, fmt);
                    457:                vwarnx(fmt, ap);
                    458:                va_end(ap);
                    459:        }
1.46      mrg       460:        exit(2);
1.9       mrg       461: }
1.66      dsl       462: #endif
1.9       mrg       463:
1.25      mrg       464: #ifndef SMALL
1.15      mrg       465: /* split up $GZIP and prepend it to the argument list */
                    466: static void
                    467: prepend_gzip(char *gzip, int *argc, char ***argv)
                    468: {
                    469:        char *s, **nargv, **ac;
                    470:        int nenvarg = 0, i;
                    471:
                    472:        /* scan how many arguments there are */
1.70      enami     473:        for (s = gzip;;) {
                    474:                while (*s == ' ' || *s == '\t')
                    475:                        s++;
                    476:                if (*s == 0)
                    477:                        goto count_done;
1.15      mrg       478:                nenvarg++;
1.70      enami     479:                while (*s != ' ' && *s != '\t')
                    480:                        if (*s++ == 0)
                    481:                                goto count_done;
1.15      mrg       482:        }
1.70      enami     483: count_done:
1.15      mrg       484:        /* punt early */
                    485:        if (nenvarg == 0)
                    486:                return;
                    487:
                    488:        *argc += nenvarg;
                    489:        ac = *argv;
                    490:
1.17      simonb    491:        nargv = (char **)malloc((*argc + 1) * sizeof(char *));
1.15      mrg       492:        if (nargv == NULL)
1.46      mrg       493:                maybe_err("malloc");
1.15      mrg       494:
                    495:        /* stash this away */
                    496:        *argv = nargv;
                    497:
                    498:        /* copy the program name first */
                    499:        i = 0;
                    500:        nargv[i++] = *(ac++);
                    501:
                    502:        /* take a copy of $GZIP and add it to the array */
                    503:        s = strdup(gzip);
                    504:        if (s == NULL)
1.46      mrg       505:                maybe_err("strdup");
1.70      enami     506:        for (;;) {
                    507:                /* Skip whitespaces. */
                    508:                while (*s == ' ' || *s == '\t')
                    509:                        s++;
                    510:                if (*s == 0)
                    511:                        goto copy_done;
1.15      mrg       512:                nargv[i++] = s;
1.70      enami     513:                /* Find the end of this argument. */
                    514:                while (*s != ' ' && *s != '\t')
                    515:                        if (*s++ == 0)
                    516:                                /* Argument followed by NUL. */
                    517:                                goto copy_done;
                    518:                /* Terminate by overwriting ' ' or '\t' with NUL. */
                    519:                *s++ = 0;
1.15      mrg       520:        }
1.70      enami     521: copy_done:
1.15      mrg       522:
                    523:        /* copy the original arguments and a NULL */
                    524:        while (*ac)
                    525:                nargv[i++] = *(ac++);
                    526:        nargv[i] = NULL;
                    527: }
1.25      mrg       528: #endif
1.15      mrg       529:
1.63      dsl       530: /* compress input to output. Return bytes read, -1 on error */
1.37      mrg       531: static off_t
1.63      dsl       532: gz_compress(int in, int out, off_t *gsizep, const char *origname, uint32_t mtime)
1.1       mrg       533: {
1.37      mrg       534:        z_stream z;
1.62      he        535:        char *outbufp, *inbufp;
1.37      mrg       536:        off_t in_tot = 0, out_tot = 0;
                    537:        ssize_t in_size;
                    538:        int i, error;
                    539:        uLong crc;
1.63      dsl       540: #ifdef SMALL
                    541:        static char header[] = { GZIP_MAGIC0, GZIP_MAGIC1, Z_DEFLATED, 0,
                    542:                                 0, 0, 0, 0,
                    543:                                 0, OS_CODE };
                    544: #endif
1.37      mrg       545:
1.63      dsl       546:        outbufp = malloc(BUFLEN);
                    547:        inbufp = malloc(BUFLEN);
                    548:        if (outbufp == NULL || inbufp == NULL) {
1.62      he        549:                maybe_err("malloc failed");
1.46      mrg       550:                goto out;
                    551:        }
1.37      mrg       552:
                    553:        memset(&z, 0, sizeof z);
1.38      mrg       554:        z.zalloc = Z_NULL;
                    555:        z.zfree = Z_NULL;
1.37      mrg       556:        z.opaque = 0;
                    557:
1.63      dsl       558: #ifdef SMALL
                    559:        memcpy(outbufp, header, sizeof header);
                    560:        i = sizeof header;
                    561: #else
                    562:        if (nflag != 0) {
                    563:                mtime = 0;
                    564:                origname = "";
                    565:        }
                    566:
                    567:        i = snprintf(outbufp, BUFLEN, "%c%c%c%c%c%c%c%c%c%c%s",
                    568:                     GZIP_MAGIC0, GZIP_MAGIC1, Z_DEFLATED,
                    569:                     *origname ? ORIG_NAME : 0,
                    570:                     mtime & 0xff,
                    571:                     (mtime >> 8) & 0xff,
                    572:                     (mtime >> 16) & 0xff,
                    573:                     (mtime >> 24) & 0xff,
1.65      dsl       574:                     numflag == 1 ? 4 : numflag == 9 ? 2 : 0,
                    575:                     OS_CODE, origname);
1.63      dsl       576:        if (i >= BUFLEN)
                    577:                /* this need PATH_MAX > BUFLEN ... */
                    578:                maybe_err("snprintf");
                    579:        if (*origname)
                    580:                i++;
                    581: #endif
                    582:
                    583:        z.next_out = outbufp + i;
                    584:        z.avail_out = BUFLEN - i;
                    585:
1.37      mrg       586:        error = deflateInit2(&z, numflag, Z_DEFLATED,
1.74      mrg       587:                             (-MAX_WBITS), 8, Z_DEFAULT_STRATEGY);
1.46      mrg       588:        if (error != Z_OK) {
                    589:                maybe_warnx("deflateInit2 failed");
                    590:                in_tot = -1;
                    591:                goto out;
                    592:        }
1.37      mrg       593:
                    594:        crc = crc32(0L, Z_NULL, 0);
                    595:        for (;;) {
                    596:                if (z.avail_out == 0) {
1.62      he        597:                        if (write(out, outbufp, BUFLEN) != BUFLEN) {
1.46      mrg       598:                                maybe_warn("write");
1.89      mrg       599:                                out_tot = -1;
1.46      mrg       600:                                goto out;
                    601:                        }
1.37      mrg       602:
1.62      he        603:                        out_tot += BUFLEN;
                    604:                        z.next_out = outbufp;
                    605:                        z.avail_out = BUFLEN;
1.37      mrg       606:                }
                    607:
                    608:                if (z.avail_in == 0) {
1.63      dsl       609:                        in_size = read(in, inbufp, BUFLEN);
                    610:                        if (in_size < 0) {
                    611:                                maybe_warn("read");
1.46      mrg       612:                                in_tot = -1;
                    613:                                goto out;
                    614:                        }
1.37      mrg       615:                        if (in_size == 0)
                    616:                                break;
                    617:
1.62      he        618:                        crc = crc32(crc, (const Bytef *)inbufp, (unsigned)in_size);
1.37      mrg       619:                        in_tot += in_size;
1.62      he        620:                        z.next_in = inbufp;
1.37      mrg       621:                        z.avail_in = in_size;
                    622:                }
                    623:
                    624:                error = deflate(&z, Z_NO_FLUSH);
1.46      mrg       625:                if (error != Z_OK && error != Z_STREAM_END) {
                    626:                        maybe_warnx("deflate failed");
                    627:                        in_tot = -1;
                    628:                        goto out;
                    629:                }
1.37      mrg       630:        }
1.1       mrg       631:
1.37      mrg       632:        /* clean up */
1.1       mrg       633:        for (;;) {
1.37      mrg       634:                size_t len;
1.77      mrg       635:                ssize_t w;
1.37      mrg       636:
                    637:                error = deflate(&z, Z_FINISH);
1.46      mrg       638:                if (error != Z_OK && error != Z_STREAM_END) {
                    639:                        maybe_warnx("deflate failed");
                    640:                        in_tot = -1;
                    641:                        goto out;
                    642:                }
1.37      mrg       643:
1.63      dsl       644:                len = (char *)z.next_out - outbufp;
1.37      mrg       645:
1.77      mrg       646:                w = write(out, outbufp, len);
                    647:                if (w == -1 || (size_t)w != len) {
1.46      mrg       648:                        maybe_warn("write");
                    649:                        out_tot = -1;
                    650:                        goto out;
                    651:                }
1.37      mrg       652:                out_tot += len;
1.62      he        653:                z.next_out = outbufp;
                    654:                z.avail_out = BUFLEN;
1.37      mrg       655:
                    656:                if (error == Z_STREAM_END)
1.1       mrg       657:                        break;
1.37      mrg       658:        }
                    659:
1.46      mrg       660:        if (deflateEnd(&z) != Z_OK) {
                    661:                maybe_warnx("deflateEnd failed");
                    662:                in_tot = -1;
                    663:                goto out;
                    664:        }
1.37      mrg       665:
1.63      dsl       666:        i = snprintf(outbufp, BUFLEN, "%c%c%c%c%c%c%c%c",
1.37      mrg       667:                 (int)crc & 0xff,
                    668:                 (int)(crc >> 8) & 0xff,
                    669:                 (int)(crc >> 16) & 0xff,
                    670:                 (int)(crc >> 24) & 0xff,
                    671:                 (int)in_tot & 0xff,
                    672:                 (int)(in_tot >> 8) & 0xff,
                    673:                 (int)(in_tot >> 16) & 0xff,
                    674:                 (int)(in_tot >> 24) & 0xff);
                    675:        if (i != 8)
1.63      dsl       676:                maybe_err("snprintf");
1.79      mrg       677: #if 0
1.73      mrg       678:        if (in_tot > 0xffffffff)
                    679:                maybe_warn("input file size >= 4GB cannot be saved");
1.79      mrg       680: #endif
1.63      dsl       681:        if (write(out, outbufp, i) != i) {
1.46      mrg       682:                maybe_warn("write");
                    683:                in_tot = -1;
1.63      dsl       684:        } else
                    685:                out_tot += i;
1.1       mrg       686:
1.46      mrg       687: out:
1.63      dsl       688:        if (inbufp != NULL)
                    689:                free(inbufp);
                    690:        if (outbufp != NULL)
                    691:                free(outbufp);
1.37      mrg       692:        if (gsizep)
                    693:                *gsizep = out_tot;
                    694:        return in_tot;
1.1       mrg       695: }
                    696:
1.37      mrg       697: /*
                    698:  * uncompress input to output then close the input.  return the
                    699:  * uncompressed size written, and put the compressed sized read
                    700:  * into `*gsizep'.
                    701:  */
1.1       mrg       702: static off_t
1.46      mrg       703: gz_uncompress(int in, int out, char *pre, size_t prelen, off_t *gsizep,
                    704:              const char *filename)
1.1       mrg       705: {
1.37      mrg       706:        z_stream z;
1.62      he        707:        char *outbufp, *inbufp;
1.72      lukem     708:        off_t out_tot = -1, in_tot = 0;
                    709:        uint32_t out_sub_tot = 0;
1.37      mrg       710:        enum {
                    711:                GZSTATE_MAGIC0,
                    712:                GZSTATE_MAGIC1,
                    713:                GZSTATE_METHOD,
                    714:                GZSTATE_FLAGS,
                    715:                GZSTATE_SKIPPING,
                    716:                GZSTATE_EXTRA,
                    717:                GZSTATE_EXTRA2,
                    718:                GZSTATE_EXTRA3,
                    719:                GZSTATE_ORIGNAME,
                    720:                GZSTATE_COMMENT,
                    721:                GZSTATE_HEAD_CRC1,
                    722:                GZSTATE_HEAD_CRC2,
                    723:                GZSTATE_INIT,
1.55      mrg       724:                GZSTATE_READ,
                    725:                GZSTATE_CRC,
                    726:                GZSTATE_LEN,
1.37      mrg       727:        } state = GZSTATE_MAGIC0;
                    728:        int flags = 0, skip_count = 0;
1.72      lukem     729:        int error = Z_STREAM_ERROR, done_reading = 0;
                    730:        uLong crc = 0;
1.68      dsl       731:        ssize_t wr;
1.71      yamt      732:        int needmore = 0;
1.37      mrg       733:
                    734: #define ADVANCE()       { z.next_in++; z.avail_in--; }
                    735:
1.62      he        736:        if ((outbufp = malloc(BUFLEN)) == NULL) {
                    737:                maybe_err("malloc failed");
                    738:                goto out2;
                    739:        }
                    740:        if ((inbufp = malloc(BUFLEN)) == NULL) {
                    741:                maybe_err("malloc failed");
                    742:                goto out1;
                    743:        }
                    744:
1.37      mrg       745:        memset(&z, 0, sizeof z);
                    746:        z.avail_in = prelen;
                    747:        z.next_in = pre;
1.62      he        748:        z.avail_out = BUFLEN;
                    749:        z.next_out = outbufp;
1.37      mrg       750:        z.zalloc = NULL;
                    751:        z.zfree = NULL;
                    752:        z.opaque = 0;
                    753:
                    754:        in_tot = prelen;
                    755:        out_tot = 0;
1.1       mrg       756:
1.37      mrg       757:        for (;;) {
1.71      yamt      758:                if ((z.avail_in == 0 || needmore) && done_reading == 0) {
1.77      mrg       759:                        ssize_t in_size;
1.71      yamt      760:
                    761:                        if (z.avail_in > 0) {
                    762:                                memmove(inbufp, z.next_in, z.avail_in);
                    763:                        }
                    764:                        z.next_in = inbufp;
                    765:                        in_size = read(in, z.next_in + z.avail_in,
                    766:                            BUFLEN - z.avail_in);
1.1       mrg       767:
1.37      mrg       768:                        if (in_size == -1) {
1.51      mrg       769:                                maybe_warn("failed to read stdin");
1.73      mrg       770:                                goto stop_and_fail;
1.71      yamt      771:                        } else if (in_size == 0) {
1.37      mrg       772:                                done_reading = 1;
1.71      yamt      773:                        }
1.37      mrg       774:
1.71      yamt      775:                        z.avail_in += in_size;
                    776:                        needmore = 0;
1.37      mrg       777:
                    778:                        in_tot += in_size;
                    779:                }
1.54      mrg       780:                if (z.avail_in == 0) {
1.86      mlelstv   781:                        if (done_reading && state != GZSTATE_MAGIC0) {
1.55      mrg       782:                                maybe_warnx("%s: unexpected end of file",
                    783:                                            filename);
1.86      mlelstv   784:                                goto stop_and_fail;
                    785:                        }
1.54      mrg       786:                        goto stop;
                    787:                }
1.37      mrg       788:                switch (state) {
                    789:                case GZSTATE_MAGIC0:
1.46      mrg       790:                        if (*z.next_in != GZIP_MAGIC0) {
1.87      mlelstv   791:                                if (in_tot > 0) {
1.88      mrg       792:                                        maybe_warnx("%s: trailing garbage "
                    793:                                                    "ignored", filename);
1.87      mlelstv   794:                                        goto stop;
                    795:                                }
1.55      mrg       796:                                maybe_warnx("input not gziped (MAGIC0)");
1.73      mrg       797:                                goto stop_and_fail;
1.46      mrg       798:                        }
1.37      mrg       799:                        ADVANCE();
                    800:                        state++;
1.54      mrg       801:                        out_sub_tot = 0;
                    802:                        crc = crc32(0L, Z_NULL, 0);
1.37      mrg       803:                        break;
                    804:
                    805:                case GZSTATE_MAGIC1:
                    806:                        if (*z.next_in != GZIP_MAGIC1 &&
1.46      mrg       807:                            *z.next_in != GZIP_OMAGIC1) {
1.55      mrg       808:                                maybe_warnx("input not gziped (MAGIC1)");
1.73      mrg       809:                                goto stop_and_fail;
1.46      mrg       810:                        }
1.37      mrg       811:                        ADVANCE();
                    812:                        state++;
                    813:                        break;
                    814:
                    815:                case GZSTATE_METHOD:
1.46      mrg       816:                        if (*z.next_in != Z_DEFLATED) {
1.51      mrg       817:                                maybe_warnx("unknown compression method");
1.73      mrg       818:                                goto stop_and_fail;
1.46      mrg       819:                        }
1.37      mrg       820:                        ADVANCE();
                    821:                        state++;
                    822:                        break;
                    823:
                    824:                case GZSTATE_FLAGS:
                    825:                        flags = *z.next_in;
                    826:                        ADVANCE();
                    827:                        skip_count = 6;
                    828:                        state++;
                    829:                        break;
                    830:
                    831:                case GZSTATE_SKIPPING:
                    832:                        if (skip_count > 0) {
                    833:                                skip_count--;
                    834:                                ADVANCE();
                    835:                        } else
                    836:                                state++;
                    837:                        break;
                    838:
                    839:                case GZSTATE_EXTRA:
                    840:                        if ((flags & EXTRA_FIELD) == 0) {
                    841:                                state = GZSTATE_ORIGNAME;
                    842:                                break;
                    843:                        }
                    844:                        skip_count = *z.next_in;
                    845:                        ADVANCE();
                    846:                        state++;
                    847:                        break;
                    848:
                    849:                case GZSTATE_EXTRA2:
                    850:                        skip_count |= ((*z.next_in) << 8);
                    851:                        ADVANCE();
                    852:                        state++;
                    853:                        break;
                    854:
                    855:                case GZSTATE_EXTRA3:
                    856:                        if (skip_count > 0) {
                    857:                                skip_count--;
                    858:                                ADVANCE();
1.1       mrg       859:                        } else
1.37      mrg       860:                                state++;
                    861:                        break;
                    862:
                    863:                case GZSTATE_ORIGNAME:
                    864:                        if ((flags & ORIG_NAME) == 0) {
                    865:                                state++;
                    866:                                break;
                    867:                        }
                    868:                        if (*z.next_in == 0)
                    869:                                state++;
                    870:                        ADVANCE();
                    871:                        break;
                    872:
                    873:                case GZSTATE_COMMENT:
                    874:                        if ((flags & COMMENT) == 0) {
                    875:                                state++;
                    876:                                break;
                    877:                        }
                    878:                        if (*z.next_in == 0)
                    879:                                state++;
                    880:                        ADVANCE();
                    881:                        break;
                    882:
                    883:                case GZSTATE_HEAD_CRC1:
                    884:                        if (flags & HEAD_CRC)
                    885:                                skip_count = 2;
                    886:                        else
                    887:                                skip_count = 0;
                    888:                        state++;
                    889:                        break;
                    890:
                    891:                case GZSTATE_HEAD_CRC2:
                    892:                        if (skip_count > 0) {
                    893:                                skip_count--;
                    894:                                ADVANCE();
                    895:                        } else
                    896:                                state++;
                    897:                        break;
                    898:
                    899:                case GZSTATE_INIT:
                    900:                        if (inflateInit2(&z, -MAX_WBITS) != Z_OK) {
1.51      mrg       901:                                maybe_warnx("failed to inflateInit");
1.73      mrg       902:                                goto stop_and_fail;
1.37      mrg       903:                        }
                    904:                        state++;
                    905:                        break;
                    906:
                    907:                case GZSTATE_READ:
                    908:                        error = inflate(&z, Z_FINISH);
1.73      mrg       909:                        switch (error) {
1.50      mrg       910:                        /* Z_BUF_ERROR goes with Z_FINISH... */
1.73      mrg       911:                        case Z_BUF_ERROR:
1.98      mrg       912:                                if (z.avail_out > 0 && !done_reading)
                    913:                                        continue;
                    914:
1.73      mrg       915:                        case Z_STREAM_END:
                    916:                        case Z_OK:
1.68      dsl       917:                                break;
1.73      mrg       918:
                    919:                        case Z_NEED_DICT:
                    920:                                maybe_warnx("Z_NEED_DICT error");
                    921:                                goto stop_and_fail;
                    922:                        case Z_DATA_ERROR:
                    923:                                maybe_warnx("data stream error");
                    924:                                goto stop_and_fail;
                    925:                        case Z_STREAM_ERROR:
                    926:                                maybe_warnx("internal stream error");
                    927:                                goto stop_and_fail;
                    928:                        case Z_MEM_ERROR:
                    929:                                maybe_warnx("memory allocation error");
                    930:                                goto stop_and_fail;
                    931:
                    932:                        default:
                    933:                                maybe_warn("unknown error from inflate(): %d",
                    934:                                    error);
                    935:                        }
1.68      dsl       936:                        wr = BUFLEN - z.avail_out;
1.50      mrg       937:
1.68      dsl       938:                        if (wr != 0) {
1.62      he        939:                                crc = crc32(crc, (const Bytef *)outbufp, (unsigned)wr);
1.37      mrg       940:                                if (
                    941: #ifndef SMALL
                    942:                                    /* don't write anything with -t */
                    943:                                    tflag == 0 &&
                    944: #endif
1.62      he        945:                                    write(out, outbufp, wr) != wr) {
1.52      yamt      946:                                        maybe_warn("error writing to output");
1.73      mrg       947:                                        goto stop_and_fail;
1.46      mrg       948:                                }
1.39      mrg       949:
                    950:                                out_tot += wr;
1.54      mrg       951:                                out_sub_tot += wr;
1.68      dsl       952:                        }
1.37      mrg       953:
1.68      dsl       954:                        if (error == Z_STREAM_END) {
                    955:                                inflateEnd(&z);
                    956:                                state++;
                    957:                        }
1.39      mrg       958:
1.68      dsl       959:                        z.next_out = outbufp;
                    960:                        z.avail_out = BUFLEN;
1.37      mrg       961:
1.68      dsl       962:                        break;
1.55      mrg       963:                case GZSTATE_CRC:
                    964:                        {
                    965:                                uLong origcrc;
                    966:
                    967:                                if (z.avail_in < 4) {
1.71      yamt      968:                                        if (!done_reading) {
                    969:                                                needmore = 1;
1.55      mrg       970:                                                continue;
1.71      yamt      971:                                        }
1.55      mrg       972:                                        maybe_warnx("truncated input");
1.73      mrg       973:                                        goto stop_and_fail;
1.55      mrg       974:                                }
1.57      mrg       975:                                origcrc = ((unsigned)z.next_in[0] & 0xff) |
                    976:                                        ((unsigned)z.next_in[1] & 0xff) << 8 |
                    977:                                        ((unsigned)z.next_in[2] & 0xff) << 16 |
                    978:                                        ((unsigned)z.next_in[3] & 0xff) << 24;
                    979:                                if (origcrc != crc) {
1.55      mrg       980:                                        maybe_warnx("invalid compressed"
                    981:                                             " data--crc error");
1.73      mrg       982:                                        goto stop_and_fail;
1.57      mrg       983:                                }
1.55      mrg       984:                        }
                    985:
                    986:                        z.avail_in -= 4;
                    987:                        z.next_in += 4;
                    988:
1.71      yamt      989:                        if (!z.avail_in && done_reading) {
1.55      mrg       990:                                goto stop;
1.71      yamt      991:                        }
1.55      mrg       992:                        state++;
                    993:                        break;
                    994:                case GZSTATE_LEN:
                    995:                        {
                    996:                                uLong origlen;
                    997:
                    998:                                if (z.avail_in < 4) {
1.71      yamt      999:                                        if (!done_reading) {
                   1000:                                                needmore = 1;
1.55      mrg      1001:                                                continue;
1.71      yamt     1002:                                        }
1.55      mrg      1003:                                        maybe_warnx("truncated input");
1.73      mrg      1004:                                        goto stop_and_fail;
1.55      mrg      1005:                                }
1.57      mrg      1006:                                origlen = ((unsigned)z.next_in[0] & 0xff) |
                   1007:                                        ((unsigned)z.next_in[1] & 0xff) << 8 |
                   1008:                                        ((unsigned)z.next_in[2] & 0xff) << 16 |
                   1009:                                        ((unsigned)z.next_in[3] & 0xff) << 24;
1.55      mrg      1010:
1.57      mrg      1011:                                if (origlen != out_sub_tot) {
1.55      mrg      1012:                                        maybe_warnx("invalid compressed"
                   1013:                                             " data--length error");
1.73      mrg      1014:                                        goto stop_and_fail;
1.57      mrg      1015:                                }
1.55      mrg      1016:                        }
                   1017:
                   1018:                        z.avail_in -= 4;
                   1019:                        z.next_in += 4;
                   1020:
1.37      mrg      1021:                        if (error < 0) {
1.51      mrg      1022:                                maybe_warnx("decompression error");
1.73      mrg      1023:                                goto stop_and_fail;
1.37      mrg      1024:                        }
1.55      mrg      1025:                        state = GZSTATE_MAGIC0;
1.1       mrg      1026:                        break;
                   1027:                }
1.37      mrg      1028:                continue;
1.73      mrg      1029: stop_and_fail:
1.78      mrg      1030:                out_tot = -1;
1.37      mrg      1031: stop:
                   1032:                break;
                   1033:        }
                   1034:        if (state > GZSTATE_INIT)
                   1035:                inflateEnd(&z);
1.1       mrg      1036:
1.62      he       1037:        free(inbufp);
                   1038: out1:
                   1039:        free(outbufp);
                   1040: out2:
1.37      mrg      1041:        if (gsizep)
                   1042:                *gsizep = in_tot;
                   1043:        return (out_tot);
1.1       mrg      1044: }
                   1045:
1.29      mrg      1046: #ifndef SMALL
1.1       mrg      1047: /*
1.77      mrg      1048:  * set the owner, mode, flags & utimes using the given file descriptor.
                   1049:  * file is only used in possible warning messages.
1.1       mrg      1050:  */
                   1051: static void
1.77      mrg      1052: copymodes(int fd, const struct stat *sbp, const char *file)
1.1       mrg      1053: {
                   1054:        struct timeval times[2];
1.77      mrg      1055:        struct stat sb;
1.1       mrg      1056:
                   1057:        /*
                   1058:         * If we have no info on the input, give this file some
                   1059:         * default values and return..
                   1060:         */
                   1061:        if (sbp == NULL) {
                   1062:                mode_t mask = umask(022);
                   1063:
1.77      mrg      1064:                (void)fchmod(fd, DEFFILEMODE & ~mask);
1.1       mrg      1065:                (void)umask(mask);
                   1066:                return;
                   1067:        }
1.77      mrg      1068:        sb = *sbp;
1.1       mrg      1069:
                   1070:        /* if the chown fails, remove set-id bits as-per compress(1) */
1.77      mrg      1071:        if (fchown(fd, sb.st_uid, sb.st_gid) < 0) {
1.1       mrg      1072:                if (errno != EPERM)
1.77      mrg      1073:                        maybe_warn("couldn't fchown: %s", file);
                   1074:                sb.st_mode &= ~(S_ISUID|S_ISGID);
1.1       mrg      1075:        }
                   1076:
                   1077:        /* we only allow set-id and the 9 normal permission bits */
1.77      mrg      1078:        sb.st_mode &= S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO;
                   1079:        if (fchmod(fd, sb.st_mode) < 0)
                   1080:                maybe_warn("couldn't fchmod: %s", file);
1.1       mrg      1081:
                   1082:        /* only try flags if they exist already */
1.77      mrg      1083:         if (sb.st_flags != 0 && fchflags(fd, sb.st_flags) < 0)
                   1084:                maybe_warn("couldn't fchflags: %s", file);
1.1       mrg      1085:
1.77      mrg      1086:        TIMESPEC_TO_TIMEVAL(&times[0], &sb.st_atimespec);
                   1087:        TIMESPEC_TO_TIMEVAL(&times[1], &sb.st_mtimespec);
                   1088:        if (futimes(fd, times) < 0)
1.1       mrg      1089:                maybe_warn("couldn't utimes: %s", file);
                   1090: }
1.29      mrg      1091: #endif
1.1       mrg      1092:
1.32      mrg      1093: /* what sort of file is this? */
                   1094: static enum filetype
                   1095: file_gettype(u_char *buf)
                   1096: {
                   1097:
                   1098:        if (buf[0] == GZIP_MAGIC0 &&
                   1099:            (buf[1] == GZIP_MAGIC1 || buf[1] == GZIP_OMAGIC1))
                   1100:                return FT_GZIP;
                   1101:        else
                   1102: #ifndef NO_BZIP2_SUPPORT
                   1103:        if (memcmp(buf, BZIP2_MAGIC, 3) == 0 &&
                   1104:            buf[3] >= '0' && buf[3] <= '9')
                   1105:                return FT_BZIP2;
                   1106:        else
                   1107: #endif
                   1108: #ifndef NO_COMPRESS_SUPPORT
                   1109:        if (memcmp(buf, Z_MAGIC, 2) == 0)
                   1110:                return FT_Z;
                   1111:        else
                   1112: #endif
1.95      mrg      1113: #ifndef NO_PACK_SUPPORT
                   1114:        if (memcmp(buf, PACK_MAGIC, 2) == 0)
                   1115:                return FT_PACK;
                   1116:        else
                   1117: #endif
1.100     christos 1118: #ifndef NO_XZ_SUPPORT
                   1119:        if (memcmp(buf, XZ_MAGIC, 4) == 0)      /* XXX: We only have 4 bytes */
                   1120:                return FT_XZ;
                   1121:        else
                   1122: #endif
1.32      mrg      1123:                return FT_UNKNOWN;
                   1124: }
                   1125:
1.46      mrg      1126: #ifndef SMALL
                   1127: /* check the outfile is OK. */
                   1128: static int
1.77      mrg      1129: check_outfile(const char *outfile)
1.46      mrg      1130: {
1.77      mrg      1131:        struct stat sb;
1.46      mrg      1132:        int ok = 1;
                   1133:
1.77      mrg      1134:        if (lflag == 0 && stat(outfile, &sb) == 0) {
1.59      mrg      1135:                if (fflag)
                   1136:                        unlink(outfile);
                   1137:                else if (isatty(STDIN_FILENO)) {
1.46      mrg      1138:                        char ans[10] = { 'n', '\0' };   /* default */
                   1139:
                   1140:                        fprintf(stderr, "%s already exists -- do you wish to "
                   1141:                                        "overwrite (y or n)? " , outfile);
                   1142:                        (void)fgets(ans, sizeof(ans) - 1, stdin);
                   1143:                        if (ans[0] != 'y' && ans[0] != 'Y') {
1.90      martin   1144:                                fprintf(stderr, "\tnot overwriting\n");
1.46      mrg      1145:                                ok = 0;
                   1146:                        } else
                   1147:                                unlink(outfile);
                   1148:                } else {
                   1149:                        maybe_warnx("%s already exists -- skipping", outfile);
                   1150:                        ok = 0;
                   1151:                }
                   1152:        }
                   1153:        return ok;
                   1154: }
1.56      mrg      1155:
1.63      dsl      1156: static void
1.77      mrg      1157: unlink_input(const char *file, const struct stat *sb)
1.56      mrg      1158: {
1.63      dsl      1159:        struct stat nsb;
                   1160:
1.98      mrg      1161:        if (kflag)
                   1162:                return;
1.63      dsl      1163:        if (stat(file, &nsb) != 0)
1.98      mrg      1164:                /* Must be gone already */
1.63      dsl      1165:                return;
                   1166:        if (nsb.st_dev != sb->st_dev || nsb.st_ino != sb->st_ino)
                   1167:                /* Definitely a different file */
                   1168:                return;
                   1169:        unlink(file);
                   1170: }
                   1171: #endif
1.56      mrg      1172:
1.63      dsl      1173: static const suffixes_t *
                   1174: check_suffix(char *file, int xlate)
                   1175: {
                   1176:        const suffixes_t *s;
                   1177:        int len = strlen(file);
                   1178:        char *sp;
                   1179:
                   1180:        for (s = suffixes; s != suffixes + NUM_SUFFIXES; s++) {
1.57      mrg      1181:                /* if it doesn't fit in "a.suf", don't bother */
1.63      dsl      1182:                if (s->ziplen >= len)
                   1183:                        continue;
                   1184:                sp = file + len - s->ziplen;
                   1185:                if (strcmp(s->zipped, sp) != 0)
1.57      mrg      1186:                        continue;
1.63      dsl      1187:                if (xlate)
                   1188:                        strcpy(sp, s->normal);
                   1189:                return s;
1.56      mrg      1190:        }
                   1191:        return NULL;
                   1192: }
1.46      mrg      1193:
1.1       mrg      1194: /*
                   1195:  * compress the given file: create a corresponding .gz file and remove the
                   1196:  * original.
                   1197:  */
1.31      mrg      1198: static off_t
1.45      agc      1199: file_compress(char *file, char *outfile, size_t outsize)
1.1       mrg      1200: {
1.63      dsl      1201:        int in;
1.37      mrg      1202:        int out;
1.63      dsl      1203:        off_t size, insize;
                   1204: #ifndef SMALL
1.1       mrg      1205:        struct stat isb, osb;
1.63      dsl      1206:        const suffixes_t *suff;
1.25      mrg      1207: #endif
1.1       mrg      1208:
1.63      dsl      1209:        in = open(file, O_RDONLY);
                   1210:        if (in == -1) {
                   1211:                maybe_warn("can't open %s", file);
                   1212:                return -1;
                   1213:        }
                   1214:
1.1       mrg      1215:        if (cflag == 0) {
1.56      mrg      1216: #ifndef SMALL
1.77      mrg      1217:                if (fstat(in, &isb) == 0) {
                   1218:                        if (isb.st_nlink > 1 && fflag == 0) {
                   1219:                                maybe_warnx("%s has %d other link%s -- "
                   1220:                                            "skipping", file, isb.st_nlink - 1,
                   1221:                                            isb.st_nlink == 1 ? "" : "s");
                   1222:                                close(in);
                   1223:                                return -1;
                   1224:                        }
1.63      dsl      1225:                }
1.56      mrg      1226:
1.63      dsl      1227:                if (fflag == 0 && (suff = check_suffix(file, 0))
                   1228:                    && suff->zipped[0] != 0) {
1.56      mrg      1229:                        maybe_warnx("%s already has %s suffix -- unchanged",
1.63      dsl      1230:                                    file, suff->zipped);
                   1231:                        close(in);
                   1232:                        return -1;
1.56      mrg      1233:                }
                   1234: #endif
                   1235:
1.63      dsl      1236:                /* Add (usually) .gz to filename */
1.77      mrg      1237:                if ((size_t)snprintf(outfile, outsize, "%s%s",
1.63      dsl      1238:                                        file, suffixes[0].zipped) >= outsize)
1.96      mrg      1239:                        memcpy(outfile + outsize - suffixes[0].ziplen - 1,
1.63      dsl      1240:                                suffixes[0].zipped, suffixes[0].ziplen + 1);
1.1       mrg      1241:
1.25      mrg      1242: #ifndef SMALL
1.77      mrg      1243:                if (check_outfile(outfile) == 0) {
1.63      dsl      1244:                        close(in);
                   1245:                        return -1;
1.34      mrg      1246:                }
1.25      mrg      1247: #endif
1.1       mrg      1248:        }
                   1249:
1.43      bouyer   1250:        if (cflag == 0) {
1.63      dsl      1251:                out = open(outfile, O_WRONLY | O_CREAT | O_EXCL, 0600);
1.39      mrg      1252:                if (out == -1) {
                   1253:                        maybe_warn("could not create output: %s", outfile);
1.63      dsl      1254:                        fclose(stdin);
                   1255:                        return -1;
1.39      mrg      1256:                }
1.1       mrg      1257:        } else
1.37      mrg      1258:                out = STDOUT_FILENO;
1.1       mrg      1259:
1.63      dsl      1260:        insize = gz_compress(in, out, &size, basename(file), (uint32_t)isb.st_mtime);
1.1       mrg      1261:
1.63      dsl      1262:        (void)close(in);
1.42      mrg      1263:
1.1       mrg      1264:        /*
1.63      dsl      1265:         * If there was an error, insize will be -1.
                   1266:         * If we compressed to stdout, just return the size.
                   1267:         * Otherwise stat the file and check it is the correct size.
                   1268:         * We only blow away the file if we can stat the output and it
                   1269:         * has the expected size.
1.1       mrg      1270:         */
1.63      dsl      1271:        if (cflag != 0)
                   1272:                return insize == -1 ? -1 : size;
                   1273:
1.29      mrg      1274: #ifndef SMALL
1.77      mrg      1275:        if (fstat(out, &osb) != 0) {
1.63      dsl      1276:                maybe_warn("couldn't stat: %s", outfile);
                   1277:                goto bad_outfile;
                   1278:        }
                   1279:
                   1280:        if (osb.st_size != size) {
                   1281:                maybe_warnx("output file: %s wrong size (%" PRIdOFF
                   1282:                                " != %" PRIdOFF "), deleting",
                   1283:                                outfile, osb.st_size, size);
                   1284:                goto bad_outfile;
                   1285:        }
                   1286:
1.77      mrg      1287:        copymodes(out, &isb, outfile);
1.29      mrg      1288: #endif
1.77      mrg      1289:        if (close(out) == -1)
                   1290:                maybe_warn("couldn't close output");
1.1       mrg      1291:
1.63      dsl      1292:        /* output is good, ok to delete input */
                   1293:        unlink_input(file, &isb);
                   1294:        return size;
                   1295:
                   1296: #ifndef SMALL
                   1297:     bad_outfile:
1.77      mrg      1298:        if (close(out) == -1)
                   1299:                maybe_warn("couldn't close output");
                   1300:
1.63      dsl      1301:        maybe_warnx("leaving original %s", file);
                   1302:        unlink(outfile);
                   1303:        return size;
                   1304: #endif
1.1       mrg      1305: }
                   1306:
                   1307: /* uncompress the given file and remove the original */
1.31      mrg      1308: static off_t
1.45      agc      1309: file_uncompress(char *file, char *outfile, size_t outsize)
1.1       mrg      1310: {
                   1311:        struct stat isb, osb;
                   1312:        off_t size;
1.63      dsl      1313:        ssize_t rbytes;
1.66      dsl      1314:        unsigned char header1[4];
1.10      mrg      1315:        enum filetype method;
1.93      skrll    1316:        int fd, ofd, zfd = -1;
1.48      mrg      1317: #ifndef SMALL
1.94      lukem    1318:        ssize_t rv;
1.48      mrg      1319:        time_t timestamp = 0;
1.66      dsl      1320:        unsigned char name[PATH_MAX + 1];
1.48      mrg      1321: #endif
1.9       mrg      1322:
                   1323:        /* gather the old name info */
1.1       mrg      1324:
1.9       mrg      1325:        fd = open(file, O_RDONLY);
1.46      mrg      1326:        if (fd < 0) {
                   1327:                maybe_warn("can't open %s", file);
                   1328:                goto lose;
                   1329:        }
1.63      dsl      1330:
                   1331:        strlcpy(outfile, file, outsize);
                   1332:        if (check_suffix(outfile, 1) == NULL && !(cflag || lflag)) {
                   1333:                maybe_warnx("%s: unknown suffix -- ignored", file);
                   1334:                goto lose;
                   1335:        }
                   1336:
1.57      mrg      1337:        rbytes = read(fd, header1, sizeof header1);
                   1338:        if (rbytes != sizeof header1) {
1.10      mrg      1339:                /* we don't want to fail here. */
1.25      mrg      1340: #ifndef SMALL
1.10      mrg      1341:                if (fflag)
1.63      dsl      1342:                        goto lose;
1.25      mrg      1343: #endif
1.57      mrg      1344:                if (rbytes == -1)
                   1345:                        maybe_warn("can't read %s", file);
                   1346:                else
1.82      mrg      1347:                        goto unexpected_EOF;
1.63      dsl      1348:                goto lose;
1.10      mrg      1349:        }
                   1350:
1.32      mrg      1351:        method = file_gettype(header1);
                   1352: #ifndef SMALL
1.42      mrg      1353:        if (fflag == 0 && method == FT_UNKNOWN) {
                   1354:                maybe_warnx("%s: not in gzip format", file);
1.63      dsl      1355:                goto lose;
1.42      mrg      1356:        }
1.63      dsl      1357:
1.25      mrg      1358: #endif
1.9       mrg      1359:
1.48      mrg      1360: #ifndef SMALL
1.63      dsl      1361:        if (method == FT_GZIP && Nflag) {
                   1362:                unsigned char ts[4];    /* timestamp */
1.48      mrg      1363:
1.85      mrg      1364:                rv = pread(fd, ts, sizeof ts, GZIP_TIMESTAMP);
1.94      lukem    1365:                if (rv >= 0 && rv < (ssize_t)(sizeof ts))
1.85      mrg      1366:                        goto unexpected_EOF;
                   1367:                if (rv == -1) {
                   1368:                        if (!fflag)
1.63      dsl      1369:                                maybe_warn("can't read %s", file);
                   1370:                        goto lose;
1.83      christos 1371:                }
1.63      dsl      1372:                timestamp = ts[3] << 24 | ts[2] << 16 | ts[1] << 8 | ts[0];
1.48      mrg      1373:
1.9       mrg      1374:                if (header1[3] & ORIG_NAME) {
1.63      dsl      1375:                        rbytes = pread(fd, name, sizeof name, GZIP_ORIGNAME);
1.42      mrg      1376:                        if (rbytes < 0) {
                   1377:                                maybe_warn("can't read %s", file);
1.63      dsl      1378:                                goto lose;
1.42      mrg      1379:                        }
1.63      dsl      1380:                        if (name[0] != 0) {
                   1381:                                /* preserve original directory name */
                   1382:                                char *dp = strrchr(file, '/');
                   1383:                                if (dp == NULL)
                   1384:                                        dp = file;
                   1385:                                else
                   1386:                                        dp++;
                   1387:                                snprintf(outfile, outsize, "%.*s%.*s",
1.64      he       1388:                                                (int) (dp - file),
                   1389:                                                file, (int) rbytes, name);
1.1       mrg      1390:                        }
                   1391:                }
1.9       mrg      1392:        }
1.63      dsl      1393: #endif
                   1394:        lseek(fd, 0, SEEK_SET);
1.1       mrg      1395:
1.31      mrg      1396:        if (cflag == 0 || lflag) {
1.63      dsl      1397:                if (fstat(fd, &isb) != 0)
                   1398:                        goto lose;
1.25      mrg      1399: #ifndef SMALL
1.63      dsl      1400:                if (isb.st_nlink > 1 && lflag == 0 && fflag == 0) {
                   1401:                        maybe_warnx("%s has %d other links -- skipping",
                   1402:                            file, isb.st_nlink - 1);
1.9       mrg      1403:                        goto lose;
1.63      dsl      1404:                }
                   1405:                if (nflag == 0 && timestamp)
                   1406:                        isb.st_mtime = timestamp;
1.77      mrg      1407:                if (check_outfile(outfile) == 0)
1.63      dsl      1408:                        goto lose;
1.31      mrg      1409: #endif
1.1       mrg      1410:        }
1.5       mrg      1411:
1.48      mrg      1412:        if (cflag == 0 && lflag == 0) {
1.46      mrg      1413:                zfd = open(outfile, O_WRONLY|O_CREAT|O_EXCL, 0600);
1.63      dsl      1414:                if (zfd == STDOUT_FILENO) {
                   1415:                        /* We won't close STDOUT_FILENO later... */
                   1416:                        zfd = dup(zfd);
                   1417:                        close(STDOUT_FILENO);
                   1418:                }
1.46      mrg      1419:                if (zfd == -1) {
                   1420:                        maybe_warn("can't open %s", outfile);
                   1421:                        goto lose;
                   1422:                }
                   1423:        } else
                   1424:                zfd = STDOUT_FILENO;
                   1425:
1.100     christos 1426:        switch (method) {
1.24      tsutsui  1427: #ifndef NO_BZIP2_SUPPORT
1.100     christos 1428:        case FT_BZIP2:
1.30      mrg      1429:                /* XXX */
1.46      mrg      1430:                if (lflag) {
                   1431:                        maybe_warnx("no -l with bzip2 files");
                   1432:                        goto lose;
                   1433:                }
1.26      mrg      1434:
1.63      dsl      1435:                size = unbzip2(fd, zfd, NULL, 0, NULL);
1.100     christos 1436:                break;
1.24      tsutsui  1437: #endif
1.29      mrg      1438:
1.24      tsutsui  1439: #ifndef NO_COMPRESS_SUPPORT
1.100     christos 1440:        case FT_Z: {
1.22      mrg      1441:                FILE *in, *out;
                   1442:
1.30      mrg      1443:                /* XXX */
1.46      mrg      1444:                if (lflag) {
                   1445:                        maybe_warnx("no -l with Lempel-Ziv files");
                   1446:                        goto lose;
                   1447:                }
1.26      mrg      1448:
1.63      dsl      1449:                if ((in = zdopen(fd)) == NULL) {
                   1450:                        maybe_warn("zdopen for read: %s", file);
1.46      mrg      1451:                        goto lose;
                   1452:                }
1.22      mrg      1453:
1.63      dsl      1454:                out = fdopen(dup(zfd), "w");
1.46      mrg      1455:                if (out == NULL) {
1.63      dsl      1456:                        maybe_warn("fdopen for write: %s", outfile);
                   1457:                        fclose(in);
1.46      mrg      1458:                        goto lose;
1.22      mrg      1459:                }
                   1460:
1.37      mrg      1461:                size = zuncompress(in, out, NULL, 0, NULL);
1.66      dsl      1462:                /* need to fclose() if ferror() is true... */
                   1463:                if (ferror(in) | fclose(in)) {
                   1464:                        maybe_warn("failed infile fclose");
1.42      mrg      1465:                        unlink(outfile);
1.46      mrg      1466:                        (void)fclose(out);
1.42      mrg      1467:                }
1.63      dsl      1468:                if (fclose(out) != 0) {
1.66      dsl      1469:                        maybe_warn("failed outfile fclose");
1.63      dsl      1470:                        unlink(outfile);
                   1471:                        goto lose;
1.22      mrg      1472:                }
1.100     christos 1473:                break;
                   1474:        }
1.24      tsutsui  1475: #endif
1.51      mrg      1476:
1.95      mrg      1477: #ifndef NO_PACK_SUPPORT
1.100     christos 1478:        case FT_PACK:
1.95      mrg      1479:                if (lflag) {
                   1480:                        maybe_warnx("no -l with packed files");
                   1481:                        goto lose;
                   1482:                }
                   1483:
                   1484:                size = unpack(fd, zfd, NULL, 0, NULL);
1.100     christos 1485:                break;
                   1486: #endif
                   1487:
                   1488: #ifndef NO_XZ_SUPPORT
                   1489:        case FT_XZ:
                   1490:                if (lflag) {
                   1491:                        maybe_warnx("no -l with xz files");
                   1492:                        goto lose;
                   1493:                }
                   1494:
                   1495:                size = unxz(fd, zfd, NULL, 0, NULL);
                   1496:                break;
1.95      mrg      1497: #endif
                   1498:
1.51      mrg      1499: #ifndef SMALL
1.100     christos 1500:        case FT_UNKNOWN:
1.63      dsl      1501:                if (lflag) {
                   1502:                        maybe_warnx("no -l for unknown filetypes");
1.51      mrg      1503:                        goto lose;
                   1504:                }
1.63      dsl      1505:                size = cat_fd(NULL, 0, NULL, fd);
1.100     christos 1506:                break;
1.51      mrg      1507: #endif
1.100     christos 1508:        default:
1.10      mrg      1509:                if (lflag) {
1.63      dsl      1510:                        print_list(fd, isb.st_size, outfile, isb.st_mtime);
                   1511:                        close(fd);
1.61      yamt     1512:                        return -1;      /* XXX */
1.10      mrg      1513:                }
                   1514:
1.63      dsl      1515:                size = gz_uncompress(fd, zfd, NULL, 0, NULL, file);
1.100     christos 1516:                break;
1.63      dsl      1517:        }
                   1518:
                   1519:        if (close(fd) != 0)
                   1520:                maybe_warn("couldn't close input");
                   1521:        if (zfd != STDOUT_FILENO && close(zfd) != 0)
                   1522:                maybe_warn("couldn't close output");
1.1       mrg      1523:
1.63      dsl      1524:        if (size == -1) {
                   1525:                if (cflag == 0)
                   1526:                        unlink(outfile);
                   1527:                maybe_warnx("%s: uncompress failed", file);
                   1528:                return -1;
1.10      mrg      1529:        }
1.1       mrg      1530:
                   1531:        /* if testing, or we uncompressed to stdout, this is all we need */
1.26      mrg      1532: #ifndef SMALL
                   1533:        if (tflag)
1.63      dsl      1534:                return size;
1.26      mrg      1535: #endif
1.67      dsl      1536:        /* if we are uncompressing to stdin, don't remove the file. */
1.26      mrg      1537:        if (cflag)
1.63      dsl      1538:                return size;
1.1       mrg      1539:
                   1540:        /*
                   1541:         * if we create a file...
                   1542:         */
1.63      dsl      1543:        /*
1.67      dsl      1544:         * if we can't stat the file don't remove the file.
1.63      dsl      1545:         */
1.77      mrg      1546:
                   1547:        ofd = open(outfile, O_RDWR, 0);
                   1548:        if (ofd == -1) {
                   1549:                maybe_warn("couldn't open (leaving original): %s",
                   1550:                           outfile);
                   1551:                return -1;
                   1552:        }
                   1553:        if (fstat(ofd, &osb) != 0) {
1.63      dsl      1554:                maybe_warn("couldn't stat (leaving original): %s",
                   1555:                           outfile);
1.77      mrg      1556:                close(ofd);
1.63      dsl      1557:                return -1;
                   1558:        }
                   1559:        if (osb.st_size != size) {
1.73      mrg      1560:                maybe_warnx("stat gave different size: %" PRIdOFF
1.63      dsl      1561:                                " != %" PRIdOFF " (leaving original)",
                   1562:                                size, osb.st_size);
1.77      mrg      1563:                close(ofd);
1.63      dsl      1564:                unlink(outfile);
                   1565:                return -1;
                   1566:        }
                   1567:        unlink_input(file, &isb);
1.29      mrg      1568: #ifndef SMALL
1.77      mrg      1569:        copymodes(ofd, &isb, outfile);
1.29      mrg      1570: #endif
1.77      mrg      1571:        close(ofd);
1.63      dsl      1572:        return size;
1.1       mrg      1573:
1.82      mrg      1574:     unexpected_EOF:
                   1575:        maybe_warnx("%s: unexpected end of file", file);
1.63      dsl      1576:     lose:
                   1577:        if (fd != -1)
                   1578:                close(fd);
                   1579:        if (zfd != -1 && zfd != STDOUT_FILENO)
                   1580:                close(fd);
1.46      mrg      1581:        return -1;
1.1       mrg      1582: }
                   1583:
1.37      mrg      1584: #ifndef SMALL
                   1585: static off_t
1.51      mrg      1586: cat_fd(unsigned char * prepend, size_t count, off_t *gsizep, int fd)
1.37      mrg      1587: {
                   1588:        char buf[BUFLEN];
                   1589:        off_t in_tot;
1.77      mrg      1590:        ssize_t w;
1.37      mrg      1591:
                   1592:        in_tot = count;
1.77      mrg      1593:        w = write(STDOUT_FILENO, prepend, count);
                   1594:        if (w == -1 || (size_t)w != count) {
1.46      mrg      1595:                maybe_warn("write to stdout");
                   1596:                return -1;
                   1597:        }
1.37      mrg      1598:        for (;;) {
1.74      mrg      1599:                ssize_t rv;
                   1600:
1.51      mrg      1601:                rv = read(fd, buf, sizeof buf);
                   1602:                if (rv == 0)
                   1603:                        break;
                   1604:                if (rv < 0) {
                   1605:                        maybe_warn("read from fd %d", fd);
                   1606:                        break;
                   1607:                }
1.37      mrg      1608:
1.46      mrg      1609:                if (write(STDOUT_FILENO, buf, rv) != rv) {
                   1610:                        maybe_warn("write to stdout");
1.51      mrg      1611:                        break;
1.46      mrg      1612:                }
1.37      mrg      1613:                in_tot += rv;
                   1614:        }
                   1615:
                   1616:        if (gsizep)
                   1617:                *gsizep = in_tot;
                   1618:        return (in_tot);
                   1619: }
                   1620: #endif
                   1621:
1.1       mrg      1622: static void
                   1623: handle_stdin(void)
                   1624: {
1.37      mrg      1625:        unsigned char header1[4];
                   1626:        off_t usize, gsize;
                   1627:        enum filetype method;
1.71      yamt     1628:        ssize_t bytes_read;
1.37      mrg      1629: #ifndef NO_COMPRESS_SUPPORT
                   1630:        FILE *in;
                   1631: #endif
1.1       mrg      1632:
1.25      mrg      1633: #ifndef SMALL
1.5       mrg      1634:        if (fflag == 0 && lflag == 0 && isatty(STDIN_FILENO)) {
1.1       mrg      1635:                maybe_warnx("standard input is a terminal -- ignoring");
                   1636:                return;
                   1637:        }
1.25      mrg      1638: #endif
1.5       mrg      1639:
                   1640:        if (lflag) {
                   1641:                struct stat isb;
                   1642:
1.37      mrg      1643:                /* XXX could read the whole file, etc. */
1.46      mrg      1644:                if (fstat(STDIN_FILENO, &isb) < 0) {
                   1645:                        maybe_warn("fstat");
                   1646:                        return;
                   1647:                }
1.7       mrg      1648:                print_list(STDIN_FILENO, isb.st_size, "stdout", isb.st_mtime);
1.5       mrg      1649:                return;
                   1650:        }
                   1651:
1.71      yamt     1652:        bytes_read = read_retry(STDIN_FILENO, header1, sizeof header1);
                   1653:        if (bytes_read == -1) {
1.46      mrg      1654:                maybe_warn("can't read stdin");
                   1655:                return;
1.71      yamt     1656:        } else if (bytes_read != sizeof(header1)) {
1.82      mrg      1657:                maybe_warnx("(stdin): unexpected end of file");
1.71      yamt     1658:                return;
1.46      mrg      1659:        }
1.37      mrg      1660:
                   1661:        method = file_gettype(header1);
                   1662:        switch (method) {
                   1663:        default:
                   1664: #ifndef SMALL
1.46      mrg      1665:                if (fflag == 0) {
                   1666:                        maybe_warnx("unknown compression format");
                   1667:                        return;
                   1668:                }
1.51      mrg      1669:                usize = cat_fd(header1, sizeof header1, &gsize, STDIN_FILENO);
1.37      mrg      1670:                break;
                   1671: #endif
                   1672:        case FT_GZIP:
                   1673:                usize = gz_uncompress(STDIN_FILENO, STDOUT_FILENO,
1.46      mrg      1674:                              header1, sizeof header1, &gsize, "(stdin)");
1.37      mrg      1675:                break;
                   1676: #ifndef NO_BZIP2_SUPPORT
                   1677:        case FT_BZIP2:
                   1678:                usize = unbzip2(STDIN_FILENO, STDOUT_FILENO,
                   1679:                                header1, sizeof header1, &gsize);
                   1680:                break;
                   1681: #endif
                   1682: #ifndef NO_COMPRESS_SUPPORT
                   1683:        case FT_Z:
1.63      dsl      1684:                if ((in = zdopen(STDIN_FILENO)) == NULL) {
1.46      mrg      1685:                        maybe_warnx("zopen of stdin");
                   1686:                        return;
                   1687:                }
1.37      mrg      1688:
                   1689:                usize = zuncompress(in, stdout, header1, sizeof header1, &gsize);
1.63      dsl      1690:                fclose(in);
1.37      mrg      1691:                break;
                   1692: #endif
1.95      mrg      1693: #ifndef NO_PACK_SUPPORT
                   1694:        case FT_PACK:
                   1695:                usize = unpack(STDIN_FILENO, STDOUT_FILENO,
                   1696:                               (char *)header1, sizeof header1, &gsize);
                   1697:                break;
                   1698: #endif
1.100     christos 1699: #ifndef NO_XZ_SUPPORT
                   1700:        case FT_XZ:
                   1701:                usize = unxz(STDIN_FILENO, STDOUT_FILENO,
                   1702:                             (char *)header1, sizeof header1, &gsize);
                   1703:                break;
                   1704: #endif
1.37      mrg      1705:        }
                   1706:
                   1707: #ifndef SMALL
                   1708:         if (vflag && !tflag && usize != -1 && gsize != -1)
1.63      dsl      1709:                print_verbage(NULL, NULL, usize, gsize);
1.78      mrg      1710:        if (vflag && tflag)
                   1711:                print_test("(stdin)", usize != -1);
1.37      mrg      1712: #endif
                   1713:
1.1       mrg      1714: }
                   1715:
                   1716: static void
                   1717: handle_stdout(void)
                   1718: {
1.37      mrg      1719:        off_t gsize, usize;
1.69      jmc      1720:        struct stat sb;
                   1721:        time_t systime;
                   1722:        uint32_t mtime;
                   1723:        int ret;
1.1       mrg      1724:
1.25      mrg      1725: #ifndef SMALL
1.1       mrg      1726:        if (fflag == 0 && isatty(STDOUT_FILENO)) {
                   1727:                maybe_warnx("standard output is a terminal -- ignoring");
                   1728:                return;
                   1729:        }
1.25      mrg      1730: #endif
1.69      jmc      1731:        /* If stdin is a file use it's mtime, otherwise use current time */
                   1732:        ret = fstat(STDIN_FILENO, &sb);
                   1733:
                   1734: #ifndef SMALL
                   1735:        if (ret < 0) {
                   1736:                maybe_warn("Can't stat stdin");
                   1737:                return;
                   1738:        }
                   1739: #endif
1.37      mrg      1740:
1.69      jmc      1741:        if (S_ISREG(sb.st_mode))
                   1742:                mtime = (uint32_t)sb.st_mtime;
                   1743:        else {
                   1744:                systime = time(NULL);
                   1745: #ifndef SMALL
                   1746:                if (systime == -1) {
                   1747:                        maybe_warn("time");
                   1748:                        return;
                   1749:                }
                   1750: #endif
                   1751:                mtime = (uint32_t)systime;
                   1752:        }
                   1753:
                   1754:        usize = gz_compress(STDIN_FILENO, STDOUT_FILENO, &gsize, "", mtime);
1.37      mrg      1755: #ifndef SMALL
                   1756:         if (vflag && !tflag && usize != -1 && gsize != -1)
1.63      dsl      1757:                print_verbage(NULL, NULL, usize, gsize);
1.37      mrg      1758: #endif
1.1       mrg      1759: }
                   1760:
                   1761: /* do what is asked for, for the path name */
                   1762: static void
                   1763: handle_pathname(char *path)
                   1764: {
1.44      agc      1765:        char *opath = path, *s = NULL;
1.1       mrg      1766:        ssize_t len;
1.63      dsl      1767:        int slen;
1.1       mrg      1768:        struct stat sb;
                   1769:
                   1770:        /* check for stdout/stdin */
                   1771:        if (path[0] == '-' && path[1] == '\0') {
                   1772:                if (dflag)
                   1773:                        handle_stdin();
                   1774:                else
                   1775:                        handle_stdout();
1.49      mrg      1776:                return;
1.1       mrg      1777:        }
                   1778:
                   1779: retry:
1.73      mrg      1780:        if (stat(path, &sb) != 0) {
1.1       mrg      1781:                /* lets try <path>.gz if we're decompressing */
1.44      agc      1782:                if (dflag && s == NULL && errno == ENOENT) {
1.1       mrg      1783:                        len = strlen(path);
1.63      dsl      1784:                        slen = suffixes[0].ziplen;
                   1785:                        s = malloc(len + slen + 1);
1.44      agc      1786:                        if (s == NULL)
1.46      mrg      1787:                                maybe_err("malloc");
1.63      dsl      1788:                        memcpy(s, path, len);
                   1789:                        memcpy(s + len, suffixes[0].zipped, slen + 1);
1.1       mrg      1790:                        path = s;
                   1791:                        goto retry;
                   1792:                }
                   1793:                maybe_warn("can't stat: %s", opath);
                   1794:                goto out;
                   1795:        }
                   1796:
                   1797:        if (S_ISDIR(sb.st_mode)) {
1.25      mrg      1798: #ifndef SMALL
1.1       mrg      1799:                if (rflag)
1.74      mrg      1800:                        handle_dir(path);
1.1       mrg      1801:                else
1.25      mrg      1802: #endif
1.60      yamt     1803:                        maybe_warnx("%s is a directory", path);
1.1       mrg      1804:                goto out;
                   1805:        }
                   1806:
                   1807:        if (S_ISREG(sb.st_mode))
                   1808:                handle_file(path, &sb);
1.63      dsl      1809:        else
                   1810:                maybe_warnx("%s is not a regular file", path);
1.1       mrg      1811:
                   1812: out:
                   1813:        if (s)
                   1814:                free(s);
                   1815: }
                   1816:
                   1817: /* compress/decompress a file */
                   1818: static void
                   1819: handle_file(char *file, struct stat *sbp)
                   1820: {
1.31      mrg      1821:        off_t usize, gsize;
1.45      agc      1822:        char    outfile[PATH_MAX];
1.1       mrg      1823:
                   1824:        infile = file;
                   1825:        if (dflag) {
1.45      agc      1826:                usize = file_uncompress(file, outfile, sizeof(outfile));
1.80      he       1827: #ifndef SMALL
1.78      mrg      1828:                if (vflag && tflag)
                   1829:                        print_test(file, usize != -1);
1.80      he       1830: #endif
1.46      mrg      1831:                if (usize == -1)
1.1       mrg      1832:                        return;
                   1833:                gsize = sbp->st_size;
                   1834:        } else {
1.45      agc      1835:                gsize = file_compress(file, outfile, sizeof(outfile));
1.46      mrg      1836:                if (gsize == -1)
1.1       mrg      1837:                        return;
                   1838:                usize = sbp->st_size;
                   1839:        }
                   1840:
1.26      mrg      1841:
                   1842: #ifndef SMALL
1.1       mrg      1843:        if (vflag && !tflag)
1.45      agc      1844:                print_verbage(file, (cflag) ? NULL : outfile, usize, gsize);
1.26      mrg      1845: #endif
1.1       mrg      1846: }
                   1847:
1.25      mrg      1848: #ifndef SMALL
1.63      dsl      1849: /* this is used with -r to recursively descend directories */
1.1       mrg      1850: static void
1.74      mrg      1851: handle_dir(char *dir)
1.1       mrg      1852: {
                   1853:        char *path_argv[2];
                   1854:        FTS *fts;
                   1855:        FTSENT *entry;
                   1856:
                   1857:        path_argv[0] = dir;
                   1858:        path_argv[1] = 0;
                   1859:        fts = fts_open(path_argv, FTS_PHYSICAL, NULL);
                   1860:        if (fts == NULL) {
                   1861:                warn("couldn't fts_open %s", dir);
                   1862:                return;
                   1863:        }
                   1864:
                   1865:        while ((entry = fts_read(fts))) {
                   1866:                switch(entry->fts_info) {
                   1867:                case FTS_D:
                   1868:                case FTS_DP:
                   1869:                        continue;
                   1870:
                   1871:                case FTS_DNR:
                   1872:                case FTS_ERR:
                   1873:                case FTS_NS:
                   1874:                        maybe_warn("%s", entry->fts_path);
                   1875:                        continue;
                   1876:                case FTS_F:
                   1877:                        handle_file(entry->fts_name, entry->fts_statp);
                   1878:                }
                   1879:        }
                   1880:        (void)fts_close(fts);
                   1881: }
1.25      mrg      1882: #endif
1.1       mrg      1883:
1.66      dsl      1884: /* print a ratio - size reduction as a fraction of uncompressed size */
1.6       mrg      1885: static void
                   1886: print_ratio(off_t in, off_t out, FILE *where)
                   1887: {
1.66      dsl      1888:        int percent10;  /* 10 * percent */
                   1889:        off_t diff;
                   1890:        char buff[8];
                   1891:        int len;
1.35      mrg      1892:
1.66      dsl      1893:        diff = in - out/2;
                   1894:        if (diff <= 0)
                   1895:                /*
                   1896:                 * Output is more than double size of input! print -99.9%
                   1897:                 * Quite possibly we've failed to get the original size.
                   1898:                 */
                   1899:                percent10 = -999;
                   1900:        else {
                   1901:                /*
                   1902:                 * We only need 12 bits of result from the final division,
                   1903:                 * so reduce the values until a 32bit division will suffice.
                   1904:                 */
                   1905:                while (in > 0x100000) {
                   1906:                        diff >>= 1;
                   1907:                        in >>= 1;
                   1908:                }
                   1909:                if (in != 0)
                   1910:                        percent10 = ((u_int)diff * 2000) / (u_int)in - 1000;
                   1911:                else
                   1912:                        percent10 = 0;
                   1913:        }
1.35      mrg      1914:
1.66      dsl      1915:        len = snprintf(buff, sizeof buff, "%2.2d.", percent10);
                   1916:        /* Move the '.' to before the last digit */
                   1917:        buff[len - 1] = buff[len - 2];
                   1918:        buff[len - 2] = '.';
                   1919:        fprintf(where, "%5s%%", buff);
1.6       mrg      1920: }
                   1921:
1.26      mrg      1922: #ifndef SMALL
1.1       mrg      1923: /* print compression statistics, and the new name (if there is one!) */
                   1924: static void
1.63      dsl      1925: print_verbage(const char *file, const char *nfile, off_t usize, off_t gsize)
1.1       mrg      1926: {
1.37      mrg      1927:        if (file)
                   1928:                fprintf(stderr, "%s:%s  ", file,
                   1929:                    strlen(file) < 7 ? "\t\t" : "\t");
1.63      dsl      1930:        print_ratio(usize, gsize, stderr);
1.4       mrg      1931:        if (nfile)
                   1932:                fprintf(stderr, " -- replaced with %s", nfile);
1.1       mrg      1933:        fprintf(stderr, "\n");
                   1934:        fflush(stderr);
                   1935: }
                   1936:
                   1937: /* print test results */
                   1938: static void
1.45      agc      1939: print_test(const char *file, int ok)
1.1       mrg      1940: {
                   1941:
1.46      mrg      1942:        if (exit_value == 0 && ok == 0)
                   1943:                exit_value = 1;
1.1       mrg      1944:        fprintf(stderr, "%s:%s  %s\n", file,
                   1945:            strlen(file) < 7 ? "\t\t" : "\t", ok ? "OK" : "NOT OK");
                   1946:        fflush(stderr);
                   1947: }
1.26      mrg      1948: #endif
1.1       mrg      1949:
1.5       mrg      1950: /* print a file's info ala --list */
                   1951: /* eg:
                   1952:   compressed uncompressed  ratio uncompressed_name
                   1953:       354841      1679360  78.8% /usr/pkgsrc/distfiles/libglade-2.0.1.tar
                   1954: */
                   1955: static void
1.35      mrg      1956: print_list(int fd, off_t out, const char *outfile, time_t ts)
1.5       mrg      1957: {
                   1958:        static int first = 1;
1.29      mrg      1959: #ifndef SMALL
1.6       mrg      1960:        static off_t in_tot, out_tot;
1.72      lukem    1961:        uint32_t crc = 0;
1.29      mrg      1962: #endif
1.77      mrg      1963:        off_t in = 0, rv;
1.5       mrg      1964:
1.7       mrg      1965:        if (first) {
1.26      mrg      1966: #ifndef SMALL
1.7       mrg      1967:                if (vflag)
                   1968:                        printf("method  crc     date  time  ");
1.26      mrg      1969: #endif
1.7       mrg      1970:                if (qflag == 0)
                   1971:                        printf("  compressed uncompressed  "
                   1972:                               "ratio uncompressed_name\n");
                   1973:        }
1.5       mrg      1974:        first = 0;
                   1975:
1.6       mrg      1976:        /* print totals? */
1.29      mrg      1977: #ifndef SMALL
1.6       mrg      1978:        if (fd == -1) {
                   1979:                in = in_tot;
                   1980:                out = out_tot;
1.29      mrg      1981:        } else
                   1982: #endif
                   1983:        {
1.6       mrg      1984:                /* read the last 4 bytes - this is the uncompressed size */
1.7       mrg      1985:                rv = lseek(fd, (off_t)(-8), SEEK_END);
1.6       mrg      1986:                if (rv != -1) {
1.7       mrg      1987:                        unsigned char buf[8];
1.63      dsl      1988:                        uint32_t usize;
1.6       mrg      1989:
1.82      mrg      1990:                        rv = read(fd, (char *)buf, sizeof(buf));
                   1991:                        if (rv == -1)
1.37      mrg      1992:                                maybe_warn("read of uncompressed size");
1.82      mrg      1993:                        else if (rv != sizeof(buf))
                   1994:                                maybe_warnx("read of uncompressed size");
                   1995:
                   1996:                        else {
                   1997:                                usize = buf[4] | buf[5] << 8 |
                   1998:                                        buf[6] << 16 | buf[7] << 24;
                   1999:                                in = (off_t)usize;
1.29      mrg      2000: #ifndef SMALL
1.82      mrg      2001:                                crc = buf[0] | buf[1] << 8 |
                   2002:                                      buf[2] << 16 | buf[3] << 24;
1.29      mrg      2003: #endif
1.82      mrg      2004:                        }
1.6       mrg      2005:                }
                   2006:        }
1.5       mrg      2007:
1.26      mrg      2008: #ifndef SMALL
1.7       mrg      2009:        if (vflag && fd == -1)
                   2010:                printf("                            ");
                   2011:        else if (vflag) {
                   2012:                char *date = ctime(&ts);
                   2013:
                   2014:                /* skip the day, 1/100th second, and year */
                   2015:                date += 4;
                   2016:                date[12] = 0;
                   2017:                printf("%5s %08x %11s ", "defla"/*XXX*/, crc, date);
                   2018:        }
1.29      mrg      2019:        in_tot += in;
                   2020:        out_tot += out;
1.26      mrg      2021: #endif
1.35      mrg      2022:        printf("%12llu %12llu ", (unsigned long long)out, (unsigned long long)in);
1.6       mrg      2023:        print_ratio(in, out, stdout);
                   2024:        printf(" %s\n", outfile);
1.5       mrg      2025: }
                   2026:
1.1       mrg      2027: /* display the usage of NetBSD gzip */
                   2028: static void
                   2029: usage(void)
                   2030: {
                   2031:
                   2032:        fprintf(stderr, "%s\n", gzip_version);
                   2033:        fprintf(stderr,
1.29      mrg      2034:     "usage: %s [-" OPT_LIST "] [<file> [<file> ...]]\n"
1.11      mrg      2035: #ifndef SMALL
1.81      wiz      2036:     " -1 --fast            fastest (worst) compression\n"
                   2037:     " -2 .. -8             set compression level\n"
                   2038:     " -9 --best            best (slowest) compression\n"
1.1       mrg      2039:     " -c --stdout          write to stdout, keep original files\n"
                   2040:     "    --to-stdout\n"
                   2041:     " -d --decompress      uncompress files\n"
                   2042:     "    --uncompress\n"
                   2043:     " -f --force           force overwriting & compress links\n"
                   2044:     " -h --help            display this help\n"
1.98      mrg      2045:     " -k --keep            don't delete input files during operation\n"
1.81      wiz      2046:     " -l --list            list compressed file contents\n"
                   2047:     " -N --name            save or restore original file name and time stamp\n"
1.1       mrg      2048:     " -n --no-name         don't save original file name or time stamp\n"
                   2049:     " -q --quiet           output no warnings\n"
                   2050:     " -r --recursive       recursively compress files in directories\n"
                   2051:     " -S .suf              use suffix .suf instead of .gz\n"
                   2052:     "    --suffix .suf\n"
                   2053:     " -t --test            test compressed file\n"
                   2054:     " -V --version         display program version\n"
1.81      wiz      2055:     " -v --verbose         print extra statistics\n",
1.11      mrg      2056: #else
                   2057:     ,
                   2058: #endif
1.1       mrg      2059:            getprogname());
                   2060:        exit(0);
                   2061: }
                   2062:
                   2063: /* display the version of NetBSD gzip */
                   2064: static void
                   2065: display_version(void)
                   2066: {
                   2067:
                   2068:        fprintf(stderr, "%s\n", gzip_version);
                   2069:        exit(0);
                   2070: }
1.10      mrg      2071:
1.24      tsutsui  2072: #ifndef NO_BZIP2_SUPPORT
1.10      mrg      2073: #include "unbzip2.c"
1.24      tsutsui  2074: #endif
                   2075: #ifndef NO_COMPRESS_SUPPORT
1.22      mrg      2076: #include "zuncompress.c"
1.24      tsutsui  2077: #endif
1.95      mrg      2078: #ifndef NO_PACK_SUPPORT
                   2079: #include "unpack.c"
                   2080: #endif
1.100     christos 2081: #ifndef NO_XZ_SUPPORT
                   2082: #include "unxz.c"
                   2083: #endif
1.71      yamt     2084:
                   2085: static ssize_t
                   2086: read_retry(int fd, void *buf, size_t sz)
                   2087: {
                   2088:        char *cp = buf;
1.77      mrg      2089:        size_t left = MIN(sz, (size_t) SSIZE_MAX);
1.71      yamt     2090:
                   2091:        while (left > 0) {
                   2092:                ssize_t ret;
                   2093:
1.77      mrg      2094:                ret = read(fd, cp, left);
1.71      yamt     2095:                if (ret == -1) {
                   2096:                        return ret;
                   2097:                } else if (ret == 0) {
                   2098:                        break; /* EOF */
                   2099:                }
                   2100:                cp += ret;
                   2101:                left -= ret;
                   2102:        }
                   2103:
                   2104:        return sz - left;
                   2105: }

CVSweb <webmaster@jp.NetBSD.org>