[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.29.2.18

1.29.2.18! tron        1: /*     $NetBSD$        */
1.1       mrg         2:
                      3: /*
1.29.2.7  jmc         4:  * Copyright (c) 1997, 1998, 2003, 2004 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:  * 3. The name of the author may not be used to endorse or promote products
                     16:  *    derived from this software without specific prior written permission.
                     17:  *
                     18:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     19:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     20:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     21:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
                     22:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
                     23:  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
                     24:  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
                     25:  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
                     26:  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     27:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     28:  * SUCH DAMAGE.
                     29:  */
                     30:
1.4       mrg        31: #include <sys/cdefs.h>
                     32: #ifndef lint
1.29.2.7  jmc        33: __COPYRIGHT("@(#) Copyright (c) 1997, 1998, 2003, 2004 Matthew R. Green\n\
1.4       mrg        34:      All rights reserved.\n");
1.29.2.18! tron       35: __RCSID("$NetBSD$");
1.4       mrg        36: #endif /* not lint */
                     37:
1.1       mrg        38: /*
                     39:  * gzip.c -- GPL free gzip using zlib.
                     40:  *
1.6       mrg        41:  * TODO:
                     42:  *     - handle .taz/.tgz files?
1.10      mrg        43:  *     - use mmap where possible
1.16      wiz        44:  *     - handle some signals better (remove outfile?)
1.29.2.7  jmc        45:  *     - make bzip2/compress -v/-t/-l support work as well as possible
1.1       mrg        46:  */
                     47:
                     48: #include <sys/param.h>
                     49: #include <sys/stat.h>
                     50: #include <sys/time.h>
                     51:
                     52: #include <unistd.h>
                     53: #include <stdio.h>
                     54: #include <string.h>
                     55: #include <stdlib.h>
                     56: #include <err.h>
                     57: #include <errno.h>
                     58: #include <fcntl.h>
                     59: #include <zlib.h>
                     60: #include <fts.h>
                     61: #include <libgen.h>
                     62: #include <stdarg.h>
                     63: #include <getopt.h>
                     64:
1.10      mrg        65: /* what type of file are we dealing with */
                     66: enum filetype {
                     67:        FT_GZIP,
1.24      tsutsui    68: #ifndef NO_BZIP2_SUPPORT
1.10      mrg        69:        FT_BZIP2,
1.24      tsutsui    70: #endif
                     71: #ifndef NO_COMPRESS_SUPPORT
1.22      mrg        72:        FT_Z,
1.24      tsutsui    73: #endif
1.10      mrg        74:        FT_LAST,
                     75:        FT_UNKNOWN
                     76: };
                     77:
1.24      tsutsui    78: #ifndef NO_BZIP2_SUPPORT
1.10      mrg        79: #include <bzlib.h>
                     80:
1.24      tsutsui    81: #define BZ2_SUFFIX     ".bz2"
                     82: #define BZIP2_MAGIC    "\102\132\150"
                     83: #endif
                     84:
                     85: #ifndef NO_COMPRESS_SUPPORT
1.22      mrg        86: #define Z_SUFFIX       ".Z"
                     87: #define Z_MAGIC                "\037\235"
1.24      tsutsui    88: #endif
1.10      mrg        89:
                     90: #define GZ_SUFFIX      ".gz"
1.1       mrg        91:
1.29.2.7  jmc        92: #define BUFLEN         (64 * 1024)
1.1       mrg        93:
1.9       mrg        94: #define GZIP_MAGIC0    0x1F
1.10      mrg        95: #define GZIP_MAGIC1    0x8B
                     96: #define GZIP_OMAGIC1   0x9E
1.9       mrg        97:
1.29.2.15  tron       98: #define GZIP_TIMESTAMP (off_t)4
1.29.2.14  tron       99: #define GZIP_ORIGNAME  (off_t)10
                    100:
1.29.2.7  jmc       101: #define HEAD_CRC       0x02
                    102: #define EXTRA_FIELD    0x04
                    103: #define ORIG_NAME      0x08
                    104: #define COMMENT                0x10
1.1       mrg       105:
1.29.2.7  jmc       106: #define OS_CODE                3       /* Unix */
1.1       mrg       107:
1.29.2.13  tron      108: static const char      gzip_version[] = "NetBSD gzip 20040524";
1.1       mrg       109:
                    110: static int     cflag;                  /* stdout mode */
                    111: static int     dflag;                  /* decompress mode */
1.25      mrg       112: static int     lflag;                  /* list mode */
1.29.2.7  jmc       113: static int     numflag = 6;            /* gzip -1..-9 value */
1.26      mrg       114:
1.25      mrg       115: #ifndef SMALL
1.1       mrg       116: static int     fflag;                  /* force mode */
                    117: static int     nflag;                  /* don't save name/timestamp */
                    118: static int     Nflag;                  /* don't restore name/timestamp */
                    119: static int     qflag;                  /* quiet mode */
                    120: static int     rflag;                  /* recursive mode */
1.26      mrg       121: static int     tflag;                  /* test */
                    122: static char    *Sflag;
                    123: static int     vflag;                  /* verbose mode */
1.25      mrg       124: #else
                    125: #define                qflag   0
                    126: #endif
1.26      mrg       127:
1.29.2.13  tron      128: static int     exit_value = 0;         /* exit value */
                    129:
1.29.2.12  tron      130: static const char      *suffix;
1.10      mrg       131: #define suffix_len     (strlen(suffix) + 1)    /* len + nul */
1.1       mrg       132: static char    *infile;                /* name of file coming in */
                    133:
1.29.2.13  tron      134: static void    maybe_err(const char *fmt, ...);
                    135: static void    maybe_errx(const char *fmt, ...);
1.1       mrg       136: static void    maybe_warn(const char *fmt, ...);
                    137: static void    maybe_warnx(const char *fmt, ...);
1.29.2.4  jmc       138: static enum filetype file_gettype(u_char *);
1.29.2.13  tron      139: static int     check_outfile(const char *outfile, struct stat *sb);
1.29.2.7  jmc       140: static off_t   gz_compress(FILE *, int, off_t *, const char *, time_t);
1.29.2.13  tron      141: static off_t   gz_uncompress(int, int, char *, size_t, off_t *, const char *);
1.29.2.12  tron      142: static off_t   file_compress(char *, char *, size_t);
                    143: static off_t   file_uncompress(char *, char *, size_t);
1.29.2.18! tron      144: static off_t   cat_fd(unsigned char *, size_t, off_t *, int fd);
1.1       mrg       145: static void    handle_pathname(char *);
                    146: static void    handle_file(char *, struct stat *);
                    147: static void    handle_stdin(void);
                    148: static void    handle_stdout(void);
1.6       mrg       149: static void    print_ratio(off_t, off_t, FILE *);
1.7       mrg       150: static void    print_list(int fd, off_t, const char *, time_t);
1.10      mrg       151: static void    usage(void);
                    152: static void    display_version(void);
1.26      mrg       153:
                    154: #ifndef SMALL
                    155: static void    prepend_gzip(char *, int *, char ***);
                    156: static void    handle_dir(char *, struct stat *);
1.29.2.2  grant     157: static void    print_verbage(char *, char *, off_t, off_t);
1.29.2.12  tron      158: static void    print_test(const char *, int);
1.29      mrg       159: static void    copymodes(const char *, struct stat *);
1.26      mrg       160: #endif
                    161:
1.24      tsutsui   162: #ifndef NO_BZIP2_SUPPORT
1.29.2.7  jmc       163: static off_t   unbzip2(int, int, char *, size_t, off_t *);
1.24      tsutsui   164: #endif
1.26      mrg       165:
1.24      tsutsui   166: #ifndef NO_COMPRESS_SUPPORT
1.29.2.7  jmc       167: static FILE    *zopen(const char *, FILE *);
                    168: static off_t   zuncompress(FILE *, FILE *, char *, size_t, off_t *);
1.24      tsutsui   169: #endif
1.1       mrg       170:
                    171: int main(int, char *p[]);
                    172:
1.11      mrg       173: #ifdef SMALL
                    174: #define getopt_long(a,b,c,d,e) getopt(a,b,c)
                    175: #else
1.3       jdolecek  176: static const struct option longopts[] = {
1.1       mrg       177:        { "stdout",             no_argument,            0,      'c' },
                    178:        { "to-stdout",          no_argument,            0,      'c' },
                    179:        { "decompress",         no_argument,            0,      'd' },
                    180:        { "uncompress",         no_argument,            0,      'd' },
                    181:        { "force",              no_argument,            0,      'f' },
                    182:        { "help",               no_argument,            0,      'h' },
1.5       mrg       183:        { "list",               no_argument,            0,      'l' },
1.1       mrg       184:        { "no-name",            no_argument,            0,      'n' },
                    185:        { "name",               no_argument,            0,      'N' },
                    186:        { "quiet",              no_argument,            0,      'q' },
                    187:        { "recursive",          no_argument,            0,      'r' },
                    188:        { "suffix",             required_argument,      0,      'S' },
                    189:        { "test",               no_argument,            0,      't' },
                    190:        { "verbose",            no_argument,            0,      'v' },
                    191:        { "version",            no_argument,            0,      'V' },
                    192:        { "fast",               no_argument,            0,      '1' },
                    193:        { "best",               no_argument,            0,      '9' },
                    194: #if 0
                    195:        /*
1.10      mrg       196:         * This is what else GNU gzip implements.  --ascii isn't useful
                    197:         * on NetBSD, and I don't care to have a --license.
1.1       mrg       198:         */
                    199:        { "ascii",              no_argument,            0,      'a' },
                    200:        { "license",            no_argument,            0,      'L' },
                    201: #endif
1.12      mrg       202:        { NULL,                 no_argument,            0,      0 },
1.1       mrg       203: };
1.11      mrg       204: #endif
1.1       mrg       205:
                    206: int
                    207: main(int argc, char **argv)
                    208: {
1.28      mrg       209:        const char *progname = getprogname();
1.25      mrg       210: #ifndef SMALL
1.15      mrg       211:        char *gzip;
1.25      mrg       212: #endif
1.1       mrg       213:        int ch;
                    214:
1.15      mrg       215:        /* XXX set up signals */
                    216:
1.10      mrg       217:        suffix = GZ_SUFFIX;;
                    218:
1.25      mrg       219: #ifndef SMALL
1.15      mrg       220:        if ((gzip = getenv("GZIP")) != NULL)
                    221:                prepend_gzip(gzip, &argc, &argv);
1.28      mrg       222: #endif
1.15      mrg       223:
1.1       mrg       224:        /*
                    225:         * XXX
                    226:         * handle being called `gunzip', `zcat' and `gzcat'
                    227:         */
                    228:        if (strcmp(progname, "gunzip") == 0)
                    229:                dflag = 1;
                    230:        else if (strcmp(progname, "zcat") == 0 ||
                    231:                 strcmp(progname, "gzcat") == 0)
                    232:                dflag = cflag = 1;
1.25      mrg       233:
                    234: #ifdef SMALL
1.29.2.2  grant     235: #define OPT_LIST "cdhHltV123456789"
1.25      mrg       236: #else
1.28      mrg       237: #define OPT_LIST "cdfhHlnNqrS:tvV123456789"
1.25      mrg       238: #endif
1.1       mrg       239:
1.28      mrg       240:        while ((ch = getopt_long(argc, argv, OPT_LIST, longopts, NULL)) != -1)
1.1       mrg       241:                switch (ch) {
                    242:                case 'c':
                    243:                        cflag = 1;
                    244:                        break;
                    245:                case 'd':
                    246:                        dflag = 1;
                    247:                        break;
1.5       mrg       248:                case 'l':
                    249:                        lflag = 1;
                    250:                        dflag = 1;
                    251:                        break;
1.26      mrg       252:                case 'V':
                    253:                        display_version();
                    254:                        /* NOTREACHED */
                    255:                case '1': case '2': case '3':
                    256:                case '4': case '5': case '6':
                    257:                case '7': case '8': case '9':
1.29.2.7  jmc       258:                        numflag = ch - '0';
1.26      mrg       259:                        break;
1.25      mrg       260: #ifndef SMALL
                    261:                case 'f':
                    262:                        fflag = 1;
                    263:                        break;
1.1       mrg       264:                case 'n':
                    265:                        nflag = 1;
                    266:                        Nflag = 0;
                    267:                        break;
                    268:                case 'N':
                    269:                        nflag = 0;
                    270:                        Nflag = 1;
                    271:                        break;
                    272:                case 'q':
                    273:                        qflag = 1;
                    274:                        break;
                    275:                case 'r':
                    276:                        rflag = 1;
                    277:                        break;
                    278:                case 'S':
                    279:                        Sflag = optarg;
                    280:                        break;
                    281:                case 't':
                    282:                        cflag = 1;
                    283:                        tflag = 1;
                    284:                        dflag = 1;
                    285:                        break;
                    286:                case 'v':
                    287:                        vflag = 1;
                    288:                        break;
1.26      mrg       289: #endif
1.12      mrg       290:                default:
                    291:                        usage();
                    292:                        /* NOTREACHED */
1.1       mrg       293:                }
                    294:        argv += optind;
                    295:        argc -= optind;
                    296:
                    297:        if (argc == 0) {
                    298:                if (dflag)      /* stdin mode */
                    299:                        handle_stdin();
                    300:                else            /* stdout mode */
                    301:                        handle_stdout();
                    302:        } else {
                    303:                do {
                    304:                        handle_pathname(argv[0]);
1.5       mrg       305:                } while (*++argv);
1.1       mrg       306:        }
1.29      mrg       307: #ifndef SMALL
1.6       mrg       308:        if (qflag == 0 && lflag && argc > 1)
1.7       mrg       309:                print_list(-1, 0, "(totals)", 0);
1.29      mrg       310: #endif
1.29.2.13  tron      311:        exit(exit_value);
1.1       mrg       312: }
                    313:
                    314: /* maybe print a warning */
                    315: void
                    316: maybe_warn(const char *fmt, ...)
                    317: {
                    318:        va_list ap;
                    319:
                    320:        if (qflag == 0) {
                    321:                va_start(ap, fmt);
                    322:                vwarn(fmt, ap);
                    323:                va_end(ap);
                    324:        }
1.29.2.13  tron      325:        if (exit_value == 0)
                    326:                exit_value = 1;
1.1       mrg       327: }
                    328:
1.29.2.13  tron      329: /* ... without an errno. */
1.1       mrg       330: void
                    331: maybe_warnx(const char *fmt, ...)
                    332: {
                    333:        va_list ap;
                    334:
                    335:        if (qflag == 0) {
                    336:                va_start(ap, fmt);
                    337:                vwarnx(fmt, ap);
                    338:                va_end(ap);
                    339:        }
1.29.2.13  tron      340:        if (exit_value == 0)
                    341:                exit_value = 1;
1.1       mrg       342: }
                    343:
1.29.2.13  tron      344: /* maybe print an error */
1.1       mrg       345: void
1.29.2.13  tron      346: maybe_err(const char *fmt, ...)
1.1       mrg       347: {
                    348:        va_list ap;
                    349:
                    350:        if (qflag == 0) {
                    351:                va_start(ap, fmt);
                    352:                vwarn(fmt, ap);
                    353:                va_end(ap);
                    354:        }
1.29.2.13  tron      355:        exit(2);
1.1       mrg       356: }
                    357:
1.29.2.13  tron      358: /* ... without an errno. */
1.9       mrg       359: void
1.29.2.13  tron      360: maybe_errx(const char *fmt, ...)
1.9       mrg       361: {
                    362:        va_list ap;
                    363:
                    364:        if (qflag == 0) {
                    365:                va_start(ap, fmt);
                    366:                vwarnx(fmt, ap);
                    367:                va_end(ap);
                    368:        }
1.29.2.13  tron      369:        exit(2);
1.9       mrg       370: }
                    371:
1.25      mrg       372: #ifndef SMALL
1.15      mrg       373: /* split up $GZIP and prepend it to the argument list */
                    374: static void
                    375: prepend_gzip(char *gzip, int *argc, char ***argv)
                    376: {
                    377:        char *s, **nargv, **ac;
                    378:        int nenvarg = 0, i;
                    379:
                    380:        /* scan how many arguments there are */
                    381:        for (s = gzip; *s; s++) {
                    382:                if (*s == ' ' || *s == '\t')
                    383:                        continue;
                    384:                nenvarg++;
                    385:                for (; *s; s++)
                    386:                        if (*s == ' ' || *s == '\t')
                    387:                                break;
1.29.2.12  tron      388:                if (*s == 0x0)
1.18      mrg       389:                        break;
1.15      mrg       390:        }
                    391:        /* punt early */
                    392:        if (nenvarg == 0)
                    393:                return;
                    394:
                    395:        *argc += nenvarg;
                    396:        ac = *argv;
                    397:
1.17      simonb    398:        nargv = (char **)malloc((*argc + 1) * sizeof(char *));
1.15      mrg       399:        if (nargv == NULL)
1.29.2.13  tron      400:                maybe_err("malloc");
1.15      mrg       401:
                    402:        /* stash this away */
                    403:        *argv = nargv;
                    404:
                    405:        /* copy the program name first */
                    406:        i = 0;
                    407:        nargv[i++] = *(ac++);
                    408:
                    409:        /* take a copy of $GZIP and add it to the array */
                    410:        s = strdup(gzip);
                    411:        if (s == NULL)
1.29.2.13  tron      412:                maybe_err("strdup");
1.15      mrg       413:        for (; *s; s++) {
                    414:                if (*s == ' ' || *s == '\t')
                    415:                        continue;
                    416:                nargv[i++] = s;
                    417:                for (; *s; s++)
                    418:                        if (*s == ' ' || *s == '\t') {
                    419:                                *s = 0;
                    420:                                break;
                    421:                        }
                    422:        }
                    423:
                    424:        /* copy the original arguments and a NULL */
                    425:        while (*ac)
                    426:                nargv[i++] = *(ac++);
                    427:        nargv[i] = NULL;
                    428: }
1.25      mrg       429: #endif
1.15      mrg       430:
1.1       mrg       431: /* compress input to output then close both files */
1.29.2.7  jmc       432: static off_t
                    433: gz_compress(FILE *in, int out, off_t *gsizep, const char *origname, time_t mtime)
1.1       mrg       434: {
1.29.2.7  jmc       435:        z_stream z;
                    436:        char inbuf[BUFLEN], outbuf[BUFLEN];
                    437:        off_t in_tot = 0, out_tot = 0;
                    438:        ssize_t in_size;
                    439:        char *str;
                    440:        int i, error;
                    441:        uLong crc;
                    442:
                    443:        i = asprintf(&str, "%c%c%c%c%c%c%c%c%c%c%s",
                    444:                     GZIP_MAGIC0, GZIP_MAGIC1,
                    445:                     Z_DEFLATED, origname ? ORIG_NAME : 0,
                    446:                     (int)mtime & 0xff,
                    447:                     (int)(mtime >> 8) & 0xff,
                    448:                     (int)(mtime >> 16) & 0xff,
                    449:                     (int)(mtime >> 24) & 0xff,
                    450:                     0, OS_CODE, origname ? origname : "");
                    451:        if (i == -1)
1.29.2.13  tron      452:                maybe_err("asprintf");
1.29.2.7  jmc       453:        if (origname)
                    454:                i++;
1.29.2.13  tron      455:        if (write(out, str, i) != i) {
                    456:                maybe_warn("write");
                    457:                in_tot = -1;
                    458:                goto out;
                    459:        }
1.29.2.7  jmc       460:        free(str);
                    461:
                    462:        memset(&z, 0, sizeof z);
                    463:        z.next_out = outbuf;
                    464:        z.avail_out = sizeof outbuf;
                    465:        z.zalloc = Z_NULL;
                    466:        z.zfree = Z_NULL;
                    467:        z.opaque = 0;
                    468:
                    469:        error = deflateInit2(&z, numflag, Z_DEFLATED,
                    470:                             -MAX_WBITS, 8, Z_DEFAULT_STRATEGY);
1.29.2.13  tron      471:        if (error != Z_OK) {
                    472:                maybe_warnx("deflateInit2 failed");
                    473:                in_tot = -1;
                    474:                goto out;
                    475:        }
1.1       mrg       476:
1.29.2.7  jmc       477:        crc = crc32(0L, Z_NULL, 0);
1.1       mrg       478:        for (;;) {
1.29.2.7  jmc       479:                if (z.avail_out == 0) {
1.29.2.13  tron      480:                        if (write(out, outbuf, sizeof outbuf) != sizeof outbuf) {
                    481:                                maybe_warn("write");
                    482:                                in_tot = -1;
                    483:                                goto out;
                    484:                        }
1.29.2.7  jmc       485:
                    486:                        out_tot += sizeof outbuf;
                    487:                        z.next_out = outbuf;
                    488:                        z.avail_out = sizeof outbuf;
                    489:                }
1.1       mrg       490:
1.29.2.7  jmc       491:                if (z.avail_in == 0) {
                    492:                        in_size = fread(inbuf, 1, sizeof inbuf, in);
1.29.2.13  tron      493:                        if (ferror(in)) {
                    494:                                maybe_warn("fread");
                    495:                                in_tot = -1;
                    496:                                goto out;
                    497:                        }
1.29.2.7  jmc       498:                        if (in_size == 0)
                    499:                                break;
                    500:
                    501:                        crc = crc32(crc, (const Bytef *)inbuf, (unsigned)in_size);
                    502:                        in_tot += in_size;
                    503:                        z.next_in = inbuf;
                    504:                        z.avail_in = in_size;
                    505:                }
                    506:
                    507:                error = deflate(&z, Z_NO_FLUSH);
1.29.2.13  tron      508:                if (error != Z_OK && error != Z_STREAM_END) {
                    509:                        maybe_warnx("deflate failed");
                    510:                        in_tot = -1;
                    511:                        goto out;
                    512:                }
1.1       mrg       513:        }
1.29.2.7  jmc       514:
                    515:        /* clean up */
                    516:        for (;;) {
                    517:                size_t len;
                    518:
                    519:                error = deflate(&z, Z_FINISH);
1.29.2.13  tron      520:                if (error != Z_OK && error != Z_STREAM_END) {
                    521:                        maybe_warnx("deflate failed");
                    522:                        in_tot = -1;
                    523:                        goto out;
                    524:                }
1.29.2.7  jmc       525:
                    526:                len = sizeof outbuf - z.avail_out;
                    527:
1.29.2.13  tron      528:                if (write(out, outbuf, len) != len) {
                    529:                        maybe_warn("write");
                    530:                        out_tot = -1;
                    531:                        goto out;
                    532:                }
1.29.2.7  jmc       533:                out_tot += len;
                    534:                z.next_out = outbuf;
                    535:                z.avail_out = sizeof outbuf;
                    536:
                    537:                if (error == Z_STREAM_END)
                    538:                        break;
                    539:        }
                    540:
1.29.2.13  tron      541:        if (deflateEnd(&z) != Z_OK) {
                    542:                maybe_warnx("deflateEnd failed");
                    543:                in_tot = -1;
                    544:                goto out;
                    545:        }
1.29.2.7  jmc       546:
                    547:        i = asprintf(&str, "%c%c%c%c%c%c%c%c",
                    548:                 (int)crc & 0xff,
                    549:                 (int)(crc >> 8) & 0xff,
                    550:                 (int)(crc >> 16) & 0xff,
                    551:                 (int)(crc >> 24) & 0xff,
                    552:                 (int)in_tot & 0xff,
                    553:                 (int)(in_tot >> 8) & 0xff,
                    554:                 (int)(in_tot >> 16) & 0xff,
                    555:                 (int)(in_tot >> 24) & 0xff);
                    556:        if (i != 8)
1.29.2.13  tron      557:                maybe_err("asprintf");
                    558:        if (write(out, str, i) != i) {
                    559:                maybe_warn("write");
                    560:                in_tot = -1;
                    561:        }
1.29.2.7  jmc       562:        free(str);
                    563:
1.29.2.13  tron      564: out:
1.29.2.7  jmc       565:        if (gsizep)
                    566:                *gsizep = out_tot;
                    567:        return in_tot;
1.1       mrg       568: }
                    569:
1.29.2.7  jmc       570: /*
                    571:  * uncompress input to output then close the input.  return the
                    572:  * uncompressed size written, and put the compressed sized read
                    573:  * into `*gsizep'.
                    574:  */
1.1       mrg       575: static off_t
1.29.2.13  tron      576: gz_uncompress(int in, int out, char *pre, size_t prelen, off_t *gsizep,
                    577:              const char *filename)
1.1       mrg       578: {
1.29.2.7  jmc       579:        z_stream z;
                    580:        char outbuf[BUFLEN], inbuf[BUFLEN];
                    581:        off_t out_tot, in_tot;
                    582:        enum {
                    583:                GZSTATE_MAGIC0,
                    584:                GZSTATE_MAGIC1,
                    585:                GZSTATE_METHOD,
                    586:                GZSTATE_FLAGS,
                    587:                GZSTATE_SKIPPING,
                    588:                GZSTATE_EXTRA,
                    589:                GZSTATE_EXTRA2,
                    590:                GZSTATE_EXTRA3,
                    591:                GZSTATE_ORIGNAME,
                    592:                GZSTATE_COMMENT,
                    593:                GZSTATE_HEAD_CRC1,
                    594:                GZSTATE_HEAD_CRC2,
                    595:                GZSTATE_INIT,
                    596:                GZSTATE_READ
                    597:        } state = GZSTATE_MAGIC0;
                    598:        int flags = 0, skip_count = 0;
                    599:        int error, done_reading = 0;
                    600:
                    601: #define ADVANCE()       { z.next_in++; z.avail_in--; }
                    602:
                    603:        memset(&z, 0, sizeof z);
                    604:        z.avail_in = prelen;
                    605:        z.next_in = pre;
                    606:        z.avail_out = sizeof outbuf;
                    607:        z.next_out = outbuf;
                    608:        z.zalloc = NULL;
                    609:        z.zfree = NULL;
                    610:        z.opaque = 0;
1.1       mrg       611:
1.29.2.7  jmc       612:        in_tot = prelen;
                    613:        out_tot = 0;
1.1       mrg       614:
1.29.2.7  jmc       615:        for (;;) {
                    616:                if (z.avail_in == 0 && done_reading == 0) {
                    617:                        size_t in_size = read(in, inbuf, BUFLEN);
                    618:
                    619:                        if (in_size == -1) {
1.26      mrg       620: #ifndef SMALL
1.29.2.13  tron      621:                                if (tflag && vflag)
                    622:                                        print_test(filename, 0);
1.26      mrg       623: #endif
1.29.2.18! tron      624:                                maybe_warn("failed to read stdin");
1.29.2.13  tron      625:                                out_tot = -1;
                    626:                                goto stop;
1.29.2.7  jmc       627:                        } else if (in_size == 0)
                    628:                                done_reading = 1;
                    629:
                    630:                        z.avail_in = in_size;
                    631:                        z.next_in = inbuf;
                    632:
                    633:                        in_tot += in_size;
1.1       mrg       634:                }
1.29.2.7  jmc       635:                switch (state) {
                    636:                case GZSTATE_MAGIC0:
1.29.2.13  tron      637:                        if (*z.next_in != GZIP_MAGIC0) {
1.29.2.18! tron      638:                                maybe_warnx("input not gziped");
1.29.2.13  tron      639:                                out_tot = -1;
                    640:                                goto stop;
                    641:                        }
1.29.2.7  jmc       642:                        ADVANCE();
                    643:                        state++;
                    644:                        break;
                    645:
                    646:                case GZSTATE_MAGIC1:
                    647:                        if (*z.next_in != GZIP_MAGIC1 &&
1.29.2.13  tron      648:                            *z.next_in != GZIP_OMAGIC1) {
1.29.2.18! tron      649:                                maybe_warnx("input not gziped");
1.29.2.13  tron      650:                                out_tot = -1;
                    651:                                goto stop;
                    652:                        }
1.29.2.7  jmc       653:                        ADVANCE();
                    654:                        state++;
                    655:                        break;
                    656:
                    657:                case GZSTATE_METHOD:
1.29.2.13  tron      658:                        if (*z.next_in != Z_DEFLATED) {
1.29.2.18! tron      659:                                maybe_warnx("unknown compression method");
1.29.2.13  tron      660:                                out_tot = -1;
                    661:                                goto stop;
                    662:                        }
1.29.2.7  jmc       663:                        ADVANCE();
                    664:                        state++;
                    665:                        break;
                    666:
                    667:                case GZSTATE_FLAGS:
                    668:                        flags = *z.next_in;
                    669:                        ADVANCE();
                    670:                        skip_count = 6;
                    671:                        state++;
                    672:                        break;
                    673:
                    674:                case GZSTATE_SKIPPING:
                    675:                        if (skip_count > 0) {
                    676:                                skip_count--;
                    677:                                ADVANCE();
                    678:                        } else
                    679:                                state++;
                    680:                        break;
                    681:
                    682:                case GZSTATE_EXTRA:
                    683:                        if ((flags & EXTRA_FIELD) == 0) {
                    684:                                state = GZSTATE_ORIGNAME;
                    685:                                break;
                    686:                        }
                    687:                        skip_count = *z.next_in;
                    688:                        ADVANCE();
                    689:                        state++;
                    690:                        break;
                    691:
                    692:                case GZSTATE_EXTRA2:
                    693:                        skip_count |= ((*z.next_in) << 8);
                    694:                        ADVANCE();
                    695:                        state++;
                    696:                        break;
                    697:
                    698:                case GZSTATE_EXTRA3:
                    699:                        if (skip_count > 0) {
                    700:                                skip_count--;
                    701:                                ADVANCE();
                    702:                        } else
                    703:                                state++;
                    704:                        break;
                    705:
                    706:                case GZSTATE_ORIGNAME:
                    707:                        if ((flags & ORIG_NAME) == 0) {
                    708:                                state++;
                    709:                                break;
                    710:                        }
                    711:                        if (*z.next_in == 0)
                    712:                                state++;
                    713:                        ADVANCE();
                    714:                        break;
                    715:
                    716:                case GZSTATE_COMMENT:
                    717:                        if ((flags & COMMENT) == 0) {
                    718:                                state++;
                    719:                                break;
                    720:                        }
                    721:                        if (*z.next_in == 0)
                    722:                                state++;
                    723:                        ADVANCE();
                    724:                        break;
                    725:
                    726:                case GZSTATE_HEAD_CRC1:
                    727:                        if (flags & HEAD_CRC)
                    728:                                skip_count = 2;
                    729:                        else
                    730:                                skip_count = 0;
                    731:                        state++;
                    732:                        break;
                    733:
                    734:                case GZSTATE_HEAD_CRC2:
                    735:                        if (skip_count > 0) {
                    736:                                skip_count--;
                    737:                                ADVANCE();
                    738:                        } else
                    739:                                state++;
                    740:                        break;
                    741:
                    742:                case GZSTATE_INIT:
                    743:                        if (inflateInit2(&z, -MAX_WBITS) != Z_OK) {
1.29.2.18! tron      744:                                maybe_warnx("failed to inflateInit");
1.29.2.13  tron      745:                                out_tot = -1;
1.29.2.7  jmc       746:                                goto stop;
                    747:                        }
                    748:                        state++;
                    749:                        break;
1.1       mrg       750:
1.29.2.7  jmc       751:                case GZSTATE_READ:
                    752:                        error = inflate(&z, Z_FINISH);
1.29.2.17  jmc       753:                        /* Z_BUF_ERROR goes with Z_FINISH... */
1.29.2.7  jmc       754:                        if (error == Z_STREAM_END || error == Z_BUF_ERROR) {
                    755:                                size_t wr = BUFLEN - z.avail_out;
1.1       mrg       756:
1.29.2.17  jmc       757:                                /* Nothing left? */
                    758:                                if (wr == 0)
1.29.2.13  tron      759:                                        goto stop;
1.29.2.17  jmc       760:
1.29.2.7  jmc       761:                                if (
1.26      mrg       762: #ifndef SMALL
1.29.2.7  jmc       763:                                    /* don't write anything with -t */
                    764:                                    tflag == 0 &&
1.26      mrg       765: #endif
1.29.2.13  tron      766:                                    write(out, outbuf, wr) != wr) {
                    767:                                        maybe_warn("error writing "
1.29.2.7  jmc       768:                                                     "to output\n");
1.29.2.13  tron      769:                                        out_tot = -1;
                    770:                                        goto stop;
                    771:                                }
1.29.2.7  jmc       772:
                    773:                                out_tot += wr;
                    774:
                    775:                                if (error == Z_STREAM_END)
                    776:                                        goto stop;
1.1       mrg       777:
1.29.2.7  jmc       778:                                z.next_out = outbuf;
                    779:                                z.avail_out = BUFLEN;
                    780:
                    781:                                break;
                    782:                        }
                    783:                        if (error < 0) {
1.29.2.18! tron      784:                                maybe_warnx("decompression error");
1.29.2.7  jmc       785:                                out_tot = -1;
                    786:                                goto stop;
                    787:                        }
                    788:                        break;
                    789:                }
                    790:                continue;
                    791: stop:
                    792:                break;
1.1       mrg       793:        }
1.29.2.7  jmc       794:        if (state > GZSTATE_INIT)
                    795:                inflateEnd(&z);
1.1       mrg       796:
1.29.2.7  jmc       797: #ifndef SMALL
1.29.2.13  tron      798:        if (tflag && vflag)
                    799:                print_test(filename, out_tot != -1);
1.29.2.7  jmc       800: #endif
                    801:
                    802:        if (gsizep)
                    803:                *gsizep = in_tot;
                    804:        return (out_tot);
1.1       mrg       805: }
                    806:
1.29      mrg       807: #ifndef SMALL
1.1       mrg       808: /*
                    809:  * set the owner, mode, flags & utimes for a file
                    810:  */
                    811: static void
                    812: copymodes(const char *file, struct stat *sbp)
                    813: {
                    814:        struct timeval times[2];
                    815:
                    816:        /*
                    817:         * If we have no info on the input, give this file some
                    818:         * default values and return..
                    819:         */
                    820:        if (sbp == NULL) {
                    821:                mode_t mask = umask(022);
                    822:
                    823:                (void)chmod(file, DEFFILEMODE & ~mask);
                    824:                (void)umask(mask);
                    825:                return;
                    826:        }
                    827:
                    828:        /* if the chown fails, remove set-id bits as-per compress(1) */
                    829:        if (chown(file, sbp->st_uid, sbp->st_gid) < 0) {
                    830:                if (errno != EPERM)
                    831:                        maybe_warn("couldn't chown: %s", file);
                    832:                sbp->st_mode &= ~(S_ISUID|S_ISGID);
                    833:        }
                    834:
                    835:        /* we only allow set-id and the 9 normal permission bits */
                    836:        sbp->st_mode &= S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO;
                    837:        if (chmod(file, sbp->st_mode) < 0)
                    838:                maybe_warn("couldn't chmod: %s", file);
                    839:
                    840:        /* only try flags if they exist already */
                    841:         if (sbp->st_flags != 0 && chflags(file, sbp->st_flags) < 0)
                    842:                maybe_warn("couldn't chflags: %s", file);
                    843:
                    844:        TIMESPEC_TO_TIMEVAL(&times[0], &sbp->st_atimespec);
                    845:        TIMESPEC_TO_TIMEVAL(&times[1], &sbp->st_mtimespec);
                    846:        if (utimes(file, times) < 0)
                    847:                maybe_warn("couldn't utimes: %s", file);
                    848: }
1.29      mrg       849: #endif
1.1       mrg       850:
1.29.2.4  jmc       851: /* what sort of file is this? */
                    852: static enum filetype
                    853: file_gettype(u_char *buf)
                    854: {
                    855:
                    856:        if (buf[0] == GZIP_MAGIC0 &&
                    857:            (buf[1] == GZIP_MAGIC1 || buf[1] == GZIP_OMAGIC1))
                    858:                return FT_GZIP;
                    859:        else
                    860: #ifndef NO_BZIP2_SUPPORT
                    861:        if (memcmp(buf, BZIP2_MAGIC, 3) == 0 &&
                    862:            buf[3] >= '0' && buf[3] <= '9')
                    863:                return FT_BZIP2;
                    864:        else
                    865: #endif
                    866: #ifndef NO_COMPRESS_SUPPORT
                    867:        if (memcmp(buf, Z_MAGIC, 2) == 0)
                    868:                return FT_Z;
                    869:        else
                    870: #endif
                    871:                return FT_UNKNOWN;
                    872: }
                    873:
1.29.2.13  tron      874: #ifndef SMALL
                    875: /* check the outfile is OK. */
                    876: static int
                    877: check_outfile(const char *outfile, struct stat *sb)
                    878: {
                    879:        int ok = 1;
                    880:
                    881:        if (fflag == 0 && lflag == 0 && stat(outfile, sb) == 0) {
                    882:                if (isatty(STDIN_FILENO)) {
                    883:                        char ans[10] = { 'n', '\0' };   /* default */
                    884:
                    885:                        fprintf(stderr, "%s already exists -- do you wish to "
                    886:                                        "overwrite (y or n)? " , outfile);
                    887:                        (void)fgets(ans, sizeof(ans) - 1, stdin);
                    888:                        if (ans[0] != 'y' && ans[0] != 'Y') {
                    889:                                fprintf(stderr, "\tnot overwritting\n");
                    890:                                ok = 0;
                    891:                        } else
                    892:                                unlink(outfile);
                    893:                } else {
                    894:                        maybe_warnx("%s already exists -- skipping", outfile);
                    895:                        ok = 0;
                    896:                }
                    897:        }
                    898:        return ok;
                    899: }
                    900: #endif
                    901:
1.1       mrg       902: /*
                    903:  * compress the given file: create a corresponding .gz file and remove the
                    904:  * original.
                    905:  */
1.29.2.2  grant     906: static off_t
1.29.2.12  tron      907: file_compress(char *file, char *outfile, size_t outsize)
1.1       mrg       908: {
                    909:        FILE *in;
1.29.2.7  jmc       910:        int out;
1.1       mrg       911:        struct stat isb, osb;
1.29.2.2  grant     912:        off_t size;
1.25      mrg       913: #ifndef SMALL
1.1       mrg       914:        u_int32_t mtime = 0;
1.29.2.7  jmc       915:        char *savename;
1.25      mrg       916: #endif
1.1       mrg       917:
                    918:        if (cflag == 0) {
1.29.2.12  tron      919:                (void)strncpy(outfile, file, outsize - suffix_len);
                    920:                outfile[outsize - suffix_len] = '\0';
                    921:                (void)strlcat(outfile, suffix, outsize);
1.1       mrg       922:
1.25      mrg       923: #ifndef SMALL
1.29.2.13  tron      924:                if (check_outfile(outfile, &osb) == 0)
                    925:                        goto lose;
                    926:
1.1       mrg       927:                if (stat(file, &isb) == 0) {
1.29.2.3  jmc       928:                        if (isb.st_nlink > 1 && fflag == 0) {
1.1       mrg       929:                                maybe_warnx("%s has %d other link%s -- "
1.29.2.3  jmc       930:                                            "skipping", file, isb.st_nlink - 1,
1.1       mrg       931:                                            isb.st_nlink == 1 ? "" : "s");
                    932:                                goto lose;
                    933:                        }
                    934:                        if (nflag == 0)
                    935:                                mtime = (u_int32_t)isb.st_mtime;
                    936:                }
1.29.2.3  jmc       937: #endif
1.1       mrg       938:        }
                    939:        in = fopen(file, "r");
1.29.2.13  tron      940:        if (in == NULL) {
                    941:                maybe_warn("can't fopen %s", file);
                    942:                goto lose;
                    943:        }
1.1       mrg       944:
1.29.2.7  jmc       945: #ifndef SMALL
1.29.2.8  tron      946:        if (nflag == 0)
                    947:                savename = basename(file);
                    948:        else
                    949:                savename = NULL;
1.1       mrg       950: #endif
1.29.2.8  tron      951:        if (cflag == 0) {
1.29.2.7  jmc       952:                out = open(outfile, O_WRONLY|O_CREAT|O_EXCL, 0600);
                    953:                if (out == -1) {
                    954:                        maybe_warn("could not create output: %s", outfile);
                    955:                        goto lose;
                    956:                }
1.1       mrg       957:        } else
1.29.2.7  jmc       958:                out = STDOUT_FILENO;
1.1       mrg       959:
1.29.2.7  jmc       960: #ifdef SMALL
                    961:        gz_compress(in, out, NULL, NULL, 0);
                    962: #else
                    963:        gz_compress(in, out, NULL, savename, mtime);
                    964: #endif
1.1       mrg       965:
1.29.2.7  jmc       966:        (void)fclose(in);
1.1       mrg       967:
                    968:        /*
                    969:         * if we compressed to stdout, we don't know the size and
                    970:         * we don't know the new file name, punt.  if we can't stat
                    971:         * the file, whine, otherwise set the size from the stat
                    972:         * buffer.  we only blow away the file if we can stat the
                    973:         * output, just in case.
                    974:         */
                    975:        if (cflag == 0) {
1.29.2.7  jmc       976:                if (close(out) == -1)
                    977:                        maybe_warn("couldn't close ouput");
                    978:
1.1       mrg       979:                if (stat(outfile, &osb) < 0) {
                    980:                        maybe_warn("couldn't stat: %s", outfile);
                    981:                        maybe_warnx("leaving original %s", file);
                    982:                        size = 0;
                    983:                } else {
                    984:                        unlink(file);
                    985:                        size = osb.st_size;
                    986:                }
1.29      mrg       987: #ifndef SMALL
1.1       mrg       988:                copymodes(outfile, &isb);
1.29      mrg       989: #endif
1.1       mrg       990:        } else {
                    991: lose:
1.29.2.13  tron      992:                size = -1;
1.1       mrg       993:        }
                    994:
                    995:        return (size);
                    996: }
                    997:
                    998: /* uncompress the given file and remove the original */
1.29.2.2  grant     999: static off_t
1.29.2.12  tron     1000: file_uncompress(char *file, char *outfile, size_t outsize)
1.1       mrg      1001: {
                   1002:        struct stat isb, osb;
1.29.2.12  tron     1003:        char *s;
1.1       mrg      1004:        off_t size;
                   1005:        ssize_t len = strlen(file);
1.29.2.7  jmc      1006:        unsigned char header1[4], name[PATH_MAX + 1];
1.10      mrg      1007:        enum filetype method;
1.29.2.15  tron     1008:        int fd, zfd;
                   1009: #ifndef SMALL
                   1010:        time_t timestamp = 0;
                   1011: #endif
1.9       mrg      1012:
                   1013:        /* gather the old name info */
1.1       mrg      1014:
1.9       mrg      1015:        fd = open(file, O_RDONLY);
1.29.2.13  tron     1016:        if (fd < 0) {
                   1017:                maybe_warn("can't open %s", file);
                   1018:                goto lose;
                   1019:        }
1.29.2.7  jmc      1020:        if (read(fd, header1, sizeof header1) != sizeof header1) {
1.10      mrg      1021:                /* we don't want to fail here. */
1.25      mrg      1022: #ifndef SMALL
1.10      mrg      1023:                if (fflag)
1.29.2.7  jmc      1024:                        goto lose_close_it;
1.25      mrg      1025: #endif
1.29.2.13  tron     1026:                maybe_warn("can't read %s", file);
                   1027:                goto lose;
1.10      mrg      1028:        }
                   1029:
1.29.2.4  jmc      1030:        method = file_gettype(header1);
1.29      mrg      1031:
1.29.2.4  jmc      1032: #ifndef SMALL
                   1033:        if (Sflag == NULL) {
                   1034: # ifndef NO_BZIP2_SUPPORT
                   1035:                if (method == FT_BZIP2)
1.10      mrg      1036:                        suffix = BZ2_SUFFIX;
1.29.2.4  jmc      1037:                else
1.26      mrg      1038: # endif
1.29.2.4  jmc      1039: # ifndef NO_COMPRESS_SUPPORT
                   1040:                if (method == FT_Z)
1.22      mrg      1041:                        suffix = Z_SUFFIX;
1.26      mrg      1042: # endif
1.29.2.4  jmc      1043:        }
1.9       mrg      1044:
1.29.2.7  jmc      1045:        if (fflag == 0 && method == FT_UNKNOWN) {
                   1046:                maybe_warnx("%s: not in gzip format", file);
                   1047:                goto lose_close_it;
                   1048:        }
1.25      mrg      1049: #endif
1.9       mrg      1050:
1.10      mrg      1051:        if (cflag == 0 || lflag) {
                   1052:                s = &file[len - suffix_len + 1];
                   1053:                if (strncmp(s, suffix, suffix_len) == 0) {
                   1054:                        (void)strncpy(outfile, file, len - suffix_len + 1);
                   1055:                        outfile[len - suffix_len + 1] = '\0';
1.29.2.7  jmc      1056:                } else if (lflag == 0) {
                   1057:                        maybe_warnx("unknown suffix %s", s);
                   1058:                        goto lose_close_it;
                   1059:                }
1.10      mrg      1060:        }
                   1061:
1.25      mrg      1062: #ifdef SMALL
                   1063:        if (method == FT_GZIP && lflag)
                   1064: #else
                   1065:        if (method == FT_GZIP && (Nflag || lflag))
                   1066: #endif
                   1067:        {
1.29.2.15  tron     1068: #ifndef SMALL
                   1069:                unsigned char header2[4];       /* timestamp */
                   1070:
                   1071:                if (lseek(fd, GZIP_TIMESTAMP, SEEK_SET) == -1) {
                   1072:                        maybe_warn("can't lseek %s", file);
                   1073:                        goto close_header_read;
                   1074:                }
                   1075:                if (read(fd, header2, sizeof header2) != sizeof header2) {
                   1076:                        if (fflag)
                   1077:                                goto lose_close_it;
                   1078:                        maybe_warn("can't read %s", file);
                   1079:                        goto lose;
                   1080:                }
                   1081:                timestamp = ((time_t)header2[3] << 24)
                   1082:                          + ((time_t)header2[2] << 16)
                   1083:                          + ((time_t)header2[1] << 8)
                   1084:                          +  (time_t)header2[0];
                   1085: #endif
                   1086:
1.9       mrg      1087:                if (header1[3] & ORIG_NAME) {
                   1088:                        size_t rbytes;
                   1089:                        int i;
                   1090:
1.29.2.14  tron     1091:                        if (lseek(fd, GZIP_ORIGNAME, SEEK_SET) == -1) {
                   1092:                                maybe_warn("can't lseek %s", file);
                   1093:                                goto close_header_read;
                   1094:                        }
1.9       mrg      1095:                        rbytes = read(fd, name, PATH_MAX + 1);
1.29.2.7  jmc      1096:                        if (rbytes < 0) {
                   1097:                                maybe_warn("can't read %s", file);
                   1098:                                goto lose_close_it;
                   1099:                        }
1.9       mrg      1100:                        for (i = 0; i < rbytes && name[i]; i++)
                   1101:                                ;
                   1102:                        if (i < rbytes) {
                   1103:                                name[i] = 0;
                   1104:                                /* now maybe merge old dirname */
1.29.2.12  tron     1105:                                if (strchr(outfile, '/') == NULL)
                   1106:                                        (void) strlcpy(outfile, name, outsize);
1.9       mrg      1107:                                else {
1.29.2.12  tron     1108:                                        char    newbuf[PATH_MAX + 1];
                   1109:
                   1110:                                        (void) snprintf(newbuf, sizeof(newbuf),
                   1111:                                                "%s/%s", dirname(outfile),
                   1112:                                                name);
                   1113:                                        (void) strlcpy(outfile, newbuf,
                   1114:                                                outsize);
1.1       mrg      1115:                                }
                   1116:                        }
                   1117:                }
1.9       mrg      1118:        }
1.29.2.14  tron     1119: close_header_read:
1.9       mrg      1120:        close(fd);
1.1       mrg      1121:
1.29.2.2  grant    1122:        if (cflag == 0 || lflag) {
1.25      mrg      1123: #ifndef SMALL
1.29.2.13  tron     1124:                if (check_outfile(outfile, &osb) == 0)
1.9       mrg      1125:                        goto lose;
1.29.2.13  tron     1126:
1.29.2.2  grant    1127: #endif
1.9       mrg      1128:                if (stat(file, &isb) == 0) {
1.29.2.2  grant    1129: #ifndef SMALL
1.29.2.3  jmc      1130:                        if (isb.st_nlink > 1 && lflag == 0 && fflag == 0) {
1.9       mrg      1131:                                maybe_warnx("%s has %d other links -- skipping",
                   1132:                                    file, isb.st_nlink - 1);
1.1       mrg      1133:                                goto lose;
                   1134:                        }
1.29.2.15  tron     1135:                        if (nflag == 0 && timestamp)
                   1136:                                isb.st_mtime = timestamp;
1.29.2.2  grant    1137: #endif
1.9       mrg      1138:                } else
                   1139:                        goto lose;
1.1       mrg      1140:        }
1.5       mrg      1141:
1.29.2.15  tron     1142:        if (cflag == 0 && lflag == 0) {
1.29.2.13  tron     1143:                zfd = open(outfile, O_WRONLY|O_CREAT|O_EXCL, 0600);
                   1144:                if (zfd == -1) {
                   1145:                        maybe_warn("can't open %s", outfile);
                   1146:                        goto lose;
                   1147:                }
                   1148:        } else
                   1149:                zfd = STDOUT_FILENO;
                   1150:
1.24      tsutsui  1151: #ifndef NO_BZIP2_SUPPORT
1.10      mrg      1152:        if (method == FT_BZIP2) {
1.29.2.13  tron     1153:                int in;
1.5       mrg      1154:
1.29.2.1  grant    1155:                /* XXX */
1.29.2.13  tron     1156:                if (lflag) {
                   1157:                        maybe_warnx("no -l with bzip2 files");
                   1158:                        goto lose;
                   1159:                }
1.26      mrg      1160:
1.29.2.13  tron     1161:                if ((in = open(file, O_RDONLY)) == -1) {
                   1162:                        maybe_warn("open for read: %s", file);
1.29.2.7  jmc      1163:                        goto lose;
                   1164:                }
1.5       mrg      1165:
1.29.2.13  tron     1166:                size = unbzip2(in, zfd, NULL, 0, NULL);
                   1167:                if (size == -1) {
1.29.2.6  jmc      1168:                        if (cflag == 0)
                   1169:                                unlink(outfile);
1.29.2.13  tron     1170:                        maybe_warnx("%s: uncompress failed", file);
1.10      mrg      1171:                        goto lose;
                   1172:                }
1.29.2.7  jmc      1173:                if (close(in) != 0)
                   1174:                        maybe_warn("couldn't close input");
1.29.2.13  tron     1175:                if (cflag == 0 && close(zfd) != 0)
1.29.2.7  jmc      1176:                        maybe_warn("couldn't close output");
1.24      tsutsui  1177:        } else
                   1178: #endif
1.29      mrg      1179:
1.24      tsutsui  1180: #ifndef NO_COMPRESS_SUPPORT
                   1181:        if (method == FT_Z) {
1.22      mrg      1182:                FILE *in, *out;
                   1183:
1.29.2.1  grant    1184:                /* XXX */
1.29.2.13  tron     1185:                if (lflag) {
                   1186:                        maybe_warnx("no -l with Lempel-Ziv files");
                   1187:                        goto lose;
                   1188:                }
1.22      mrg      1189:
1.29.2.13  tron     1190:                if ((in = zopen(file, NULL)) == NULL) {
                   1191:                        maybe_warn("open for read: %s", file);
                   1192:                        goto lose;
1.29.2.11  tron     1193:                }
1.29.2.13  tron     1194:
1.29.2.12  tron     1195:                out = fdopen(zfd, "w");
1.29.2.13  tron     1196:                if (out == NULL) {
                   1197:                        maybe_warn("open for write: %s", outfile);
                   1198:                        goto lose;
                   1199:                }
1.22      mrg      1200:
1.29.2.7  jmc      1201:                size = zuncompress(in, out, NULL, 0, NULL);
                   1202:                if (ferror(in) || fclose(in) != 0) {
                   1203:                        unlink(outfile);
1.29.2.13  tron     1204:                        (void)fclose(out);
                   1205:                        maybe_warn("failed infile fclose");
1.29.2.7  jmc      1206:                }
1.29.2.6  jmc      1207:                if (cflag == 0) {
1.29.2.13  tron     1208:                        if (size == -1) {
                   1209:                                maybe_warnx("%s: uncompress failed", file);
                   1210:                                (void)fclose(out);
1.29.2.6  jmc      1211:                                unlink(outfile);
                   1212:                                goto lose;
                   1213:                        }
1.29.2.7  jmc      1214:                        if (fclose(out) != 0) {
1.29.2.6  jmc      1215:                                unlink(outfile);
1.29.2.13  tron     1216:                                maybe_warn("failed outfile close");
                   1217:                                goto lose;
1.29.2.6  jmc      1218:                        }
1.22      mrg      1219:                }
1.24      tsutsui  1220:        } else
                   1221: #endif
1.29.2.18! tron     1222:
        !          1223: #ifndef SMALL
        !          1224:        if (method == FT_UNKNOWN) {
        !          1225:                int in;
        !          1226:
        !          1227:                in = open(file, O_RDONLY);
        !          1228:                if (in == -1) {
        !          1229:                        maybe_warn("can't open %s", file);
        !          1230:                        goto lose;
        !          1231:                }
        !          1232:                size = cat_fd(NULL, 0, NULL, in);
        !          1233:        } else
        !          1234: #endif
1.24      tsutsui  1235:        {
1.29.2.13  tron     1236:                int in;
1.1       mrg      1237:
1.29.2.7  jmc      1238:                if (lflag) {
1.29.2.13  tron     1239:                        if ((zfd = open(file, O_RDONLY)) == -1) {
                   1240:                                maybe_warn("open: %s", file);
                   1241:                                goto lose;
                   1242:                        }
1.29.2.12  tron     1243:                        print_list(zfd, isb.st_size, outfile, isb.st_mtime);
1.10      mrg      1244:                        return 0;       /* XXX */
                   1245:                }
                   1246:
1.29.2.7  jmc      1247:                in = open(file, O_RDONLY);
1.29.2.13  tron     1248:                if (in == -1) {
                   1249:                        maybe_warn("can't open %s", file);
                   1250:                        goto lose;
                   1251:                }
1.1       mrg      1252:
1.29.2.13  tron     1253:                size = gz_uncompress(in, zfd, NULL, 0, NULL, file);
1.29.2.7  jmc      1254:                (void)close(in);
1.29.2.6  jmc      1255:                if (cflag == 0) {
1.29.2.12  tron     1256:                        if (close(zfd))
1.29.2.7  jmc      1257:                                maybe_warn("failed close");
                   1258:                        if (size == -1) {
1.29.2.13  tron     1259:                                maybe_warnx("%s: uncompress failed", file);
1.29.2.6  jmc      1260:                                unlink(outfile);
                   1261:                                goto lose;
                   1262:                        }
1.10      mrg      1263:                }
                   1264:        }
1.1       mrg      1265:
                   1266:        /* if testing, or we uncompressed to stdout, this is all we need */
1.26      mrg      1267: #ifndef SMALL
                   1268:        if (tflag)
                   1269:                return (size);
                   1270: #endif
                   1271:        if (cflag)
1.1       mrg      1272:                return (size);
                   1273:
                   1274:        /*
                   1275:         * if we create a file...
                   1276:         */
                   1277:        if (cflag == 0) {
                   1278:                /*
                   1279:                 * if we can't stat the file, or we are uncompressing to
                   1280:                 * stdin, don't remove the file.
                   1281:                 */
                   1282:                if (stat(outfile, &osb) < 0) {
                   1283:                        maybe_warn("couldn't stat (leaving original): %s",
                   1284:                                   outfile);
                   1285:                        goto lose;
                   1286:                }
                   1287:                if (osb.st_size != size) {
                   1288:                        maybe_warn("stat gave different size: %llu != %llu "
                   1289:                            "(leaving original)",
                   1290:                            (unsigned long long)size,
                   1291:                            (unsigned long long)osb.st_size);
                   1292:                        goto lose;
                   1293:                }
1.29.2.6  jmc      1294:                if (cflag == 0)
                   1295:                        unlink(file);
1.1       mrg      1296:                size = osb.st_size;
1.29      mrg      1297: #ifndef SMALL
1.1       mrg      1298:                copymodes(outfile, &isb);
1.29      mrg      1299: #endif
1.1       mrg      1300:        }
                   1301:        return (size);
                   1302:
1.29.2.7  jmc      1303: lose_close_it:
                   1304:        close(fd);
1.1       mrg      1305: lose:
1.29.2.13  tron     1306:        return -1;
1.1       mrg      1307: }
                   1308:
1.29.2.7  jmc      1309: #ifndef SMALL
                   1310: static off_t
1.29.2.18! tron     1311: cat_fd(unsigned char * prepend, size_t count, off_t *gsizep, int fd)
1.29.2.7  jmc      1312: {
                   1313:        char buf[BUFLEN];
                   1314:        size_t rv;
                   1315:        off_t in_tot;
                   1316:
                   1317:        in_tot = count;
1.29.2.13  tron     1318:        if (write(STDOUT_FILENO, prepend, count) != count) {
                   1319:                maybe_warn("write to stdout");
                   1320:                return -1;
                   1321:        }
1.29.2.7  jmc      1322:        for (;;) {
1.29.2.18! tron     1323:                rv = read(fd, buf, sizeof buf);
        !          1324:                if (rv == 0)
        !          1325:                        break;
        !          1326:                if (rv < 0) {
        !          1327:                        maybe_warn("read from fd %d", fd);
        !          1328:                        break;
        !          1329:                }
1.29.2.7  jmc      1330:
1.29.2.13  tron     1331:                if (write(STDOUT_FILENO, buf, rv) != rv) {
                   1332:                        maybe_warn("write to stdout");
1.29.2.18! tron     1333:                        break;
1.29.2.13  tron     1334:                }
1.29.2.7  jmc      1335:                in_tot += rv;
                   1336:        }
                   1337:
                   1338:        if (gsizep)
                   1339:                *gsizep = in_tot;
                   1340:        return (in_tot);
                   1341: }
                   1342: #endif
                   1343:
1.1       mrg      1344: static void
                   1345: handle_stdin(void)
                   1346: {
1.29.2.7  jmc      1347:        unsigned char header1[4];
                   1348:        off_t usize, gsize;
                   1349:        enum filetype method;
                   1350: #ifndef NO_COMPRESS_SUPPORT
                   1351:        FILE *in;
                   1352: #endif
1.1       mrg      1353:
1.25      mrg      1354: #ifndef SMALL
1.5       mrg      1355:        if (fflag == 0 && lflag == 0 && isatty(STDIN_FILENO)) {
1.1       mrg      1356:                maybe_warnx("standard input is a terminal -- ignoring");
                   1357:                return;
                   1358:        }
1.25      mrg      1359: #endif
1.5       mrg      1360:
                   1361:        if (lflag) {
                   1362:                struct stat isb;
                   1363:
1.29.2.7  jmc      1364:                /* XXX could read the whole file, etc. */
1.29.2.13  tron     1365:                if (fstat(STDIN_FILENO, &isb) < 0) {
                   1366:                        maybe_warn("fstat");
                   1367:                        return;
                   1368:                }
1.7       mrg      1369:                print_list(STDIN_FILENO, isb.st_size, "stdout", isb.st_mtime);
1.5       mrg      1370:                return;
                   1371:        }
                   1372:
1.29.2.13  tron     1373:        if (read(STDIN_FILENO, header1, sizeof header1) != sizeof header1) {
                   1374:                maybe_warn("can't read stdin");
                   1375:                return;
                   1376:        }
1.29.2.7  jmc      1377:
                   1378:        method = file_gettype(header1);
                   1379:        switch (method) {
                   1380:        default:
                   1381: #ifndef SMALL
1.29.2.13  tron     1382:                if (fflag == 0) {
                   1383:                        maybe_warnx("unknown compression format");
                   1384:                        return;
                   1385:                }
1.29.2.18! tron     1386:                usize = cat_fd(header1, sizeof header1, &gsize, STDIN_FILENO);
1.29.2.7  jmc      1387:                break;
                   1388: #endif
                   1389:        case FT_GZIP:
                   1390:                usize = gz_uncompress(STDIN_FILENO, STDOUT_FILENO,
1.29.2.13  tron     1391:                              header1, sizeof header1, &gsize, "(stdin)");
1.29.2.7  jmc      1392:                break;
                   1393: #ifndef NO_BZIP2_SUPPORT
                   1394:        case FT_BZIP2:
                   1395:                usize = unbzip2(STDIN_FILENO, STDOUT_FILENO,
                   1396:                                header1, sizeof header1, &gsize);
                   1397:                break;
                   1398: #endif
                   1399: #ifndef NO_COMPRESS_SUPPORT
                   1400:        case FT_Z:
1.29.2.13  tron     1401:                if ((in = zopen(NULL, stdin)) == NULL) {
                   1402:                        maybe_warnx("zopen of stdin");
                   1403:                        return;
                   1404:                }
1.29.2.7  jmc      1405:
                   1406:                usize = zuncompress(in, stdout, header1, sizeof header1, &gsize);
                   1407:                break;
                   1408: #endif
                   1409:        }
                   1410:
                   1411: #ifndef SMALL
                   1412:         if (vflag && !tflag && usize != -1 && gsize != -1)
                   1413:                print_verbage(NULL, 0, usize, gsize);
                   1414: #endif
                   1415:
1.1       mrg      1416: }
                   1417:
                   1418: static void
                   1419: handle_stdout(void)
                   1420: {
1.29.2.7  jmc      1421:        off_t gsize, usize;
1.1       mrg      1422:
1.25      mrg      1423: #ifndef SMALL
1.1       mrg      1424:        if (fflag == 0 && isatty(STDOUT_FILENO)) {
                   1425:                maybe_warnx("standard output is a terminal -- ignoring");
                   1426:                return;
                   1427:        }
1.25      mrg      1428: #endif
1.29.2.7  jmc      1429:        usize = gz_compress(stdin, STDOUT_FILENO, &gsize, NULL, 0);
                   1430:
                   1431: #ifndef SMALL
                   1432:         if (vflag && !tflag && usize != -1 && gsize != -1)
                   1433:                print_verbage(NULL, 0, usize, gsize);
                   1434: #endif
1.1       mrg      1435: }
                   1436:
                   1437: /* do what is asked for, for the path name */
                   1438: static void
                   1439: handle_pathname(char *path)
                   1440: {
1.29.2.9  tron     1441:        char *opath = path, *s = NULL;
1.1       mrg      1442:        ssize_t len;
                   1443:        struct stat sb;
                   1444:
                   1445:        /* check for stdout/stdin */
                   1446:        if (path[0] == '-' && path[1] == '\0') {
                   1447:                if (dflag)
                   1448:                        handle_stdin();
                   1449:                else
                   1450:                        handle_stdout();
1.29.2.16  tron     1451:                return;
1.1       mrg      1452:        }
                   1453:
                   1454: retry:
                   1455:        if (stat(path, &sb) < 0) {
                   1456:                /* lets try <path>.gz if we're decompressing */
1.29.2.9  tron     1457:                if (dflag && s == NULL && errno == ENOENT) {
1.1       mrg      1458:                        len = strlen(path);
1.29.2.9  tron     1459:                        s = malloc(len + suffix_len + 1);
                   1460:                        if (s == NULL)
1.29.2.13  tron     1461:                                maybe_err("malloc");
1.1       mrg      1462:                        memmove(s, path, len);
1.10      mrg      1463:                        memmove(&s[len], suffix, suffix_len);
1.29.2.9  tron     1464:                        s[len + suffix_len] = 0x0;
1.1       mrg      1465:                        path = s;
                   1466:                        goto retry;
                   1467:                }
                   1468:                maybe_warn("can't stat: %s", opath);
                   1469:                goto out;
                   1470:        }
                   1471:
                   1472:        if (S_ISDIR(sb.st_mode)) {
1.25      mrg      1473: #ifndef SMALL
1.1       mrg      1474:                if (rflag)
                   1475:                        handle_dir(path, &sb);
                   1476:                else
1.25      mrg      1477: #endif
1.1       mrg      1478:                        maybe_warn("%s is a directory", path);
                   1479:                goto out;
                   1480:        }
                   1481:
                   1482:        if (S_ISREG(sb.st_mode))
                   1483:                handle_file(path, &sb);
                   1484:
                   1485: out:
                   1486:        if (s)
                   1487:                free(s);
                   1488: }
                   1489:
                   1490: /* compress/decompress a file */
                   1491: static void
                   1492: handle_file(char *file, struct stat *sbp)
                   1493: {
1.29.2.2  grant    1494:        off_t usize, gsize;
1.29.2.12  tron     1495:        char    outfile[PATH_MAX];
1.1       mrg      1496:
                   1497:        infile = file;
                   1498:        if (dflag) {
1.29.2.12  tron     1499:                usize = file_uncompress(file, outfile, sizeof(outfile));
1.29.2.13  tron     1500:                if (usize == -1)
1.1       mrg      1501:                        return;
                   1502:                gsize = sbp->st_size;
                   1503:        } else {
1.29.2.12  tron     1504:                gsize = file_compress(file, outfile, sizeof(outfile));
1.29.2.13  tron     1505:                if (gsize == -1)
1.1       mrg      1506:                        return;
                   1507:                usize = sbp->st_size;
                   1508:        }
                   1509:
1.26      mrg      1510:
                   1511: #ifndef SMALL
1.1       mrg      1512:        if (vflag && !tflag)
1.29.2.12  tron     1513:                print_verbage(file, (cflag) ? NULL : outfile, usize, gsize);
1.26      mrg      1514: #endif
1.1       mrg      1515: }
                   1516:
1.25      mrg      1517: #ifndef SMALL
1.1       mrg      1518: /* this is used with -r to recursively decend directories */
                   1519: static void
                   1520: handle_dir(char *dir, struct stat *sbp)
                   1521: {
                   1522:        char *path_argv[2];
                   1523:        FTS *fts;
                   1524:        FTSENT *entry;
                   1525:
                   1526:        path_argv[0] = dir;
                   1527:        path_argv[1] = 0;
                   1528:        fts = fts_open(path_argv, FTS_PHYSICAL, NULL);
                   1529:        if (fts == NULL) {
                   1530:                warn("couldn't fts_open %s", dir);
                   1531:                return;
                   1532:        }
                   1533:
                   1534:        while ((entry = fts_read(fts))) {
                   1535:                switch(entry->fts_info) {
                   1536:                case FTS_D:
                   1537:                case FTS_DP:
                   1538:                        continue;
                   1539:
                   1540:                case FTS_DNR:
                   1541:                case FTS_ERR:
                   1542:                case FTS_NS:
                   1543:                        maybe_warn("%s", entry->fts_path);
                   1544:                        continue;
                   1545:                case FTS_F:
                   1546:                        handle_file(entry->fts_name, entry->fts_statp);
                   1547:                }
                   1548:        }
                   1549:        (void)fts_close(fts);
                   1550: }
1.25      mrg      1551: #endif
1.1       mrg      1552:
1.6       mrg      1553: /* print a ratio */
                   1554: static void
                   1555: print_ratio(off_t in, off_t out, FILE *where)
                   1556: {
1.29.2.5  jmc      1557:        int64_t percent10;      /* 10 * percent */
                   1558:        off_t diff = in - out;
                   1559:        char ch;
1.6       mrg      1560:
1.29.2.5  jmc      1561:        if (in == 0)
                   1562:                percent10 = 0;
                   1563:        else if (diff > 0x400000)       /* anything with 22 or more bits */
                   1564:                percent10 = diff / (in / 1000);
                   1565:        else
                   1566:                percent10 = (1000 * diff) / in;
                   1567:
                   1568:        if (percent10 < 0) {
                   1569:                percent10 = -percent10;
                   1570:                ch = '-';
                   1571:        } else
                   1572:                ch = ' ';
                   1573:
                   1574:        /*
                   1575:         * ugh.  for negative percentages < 10, we need to avoid printing a
                   1576:         * a space between the "-" and the single number.
                   1577:         */
                   1578:        if (ch == '-' && percent10 / 10LL < 10)
                   1579:                fprintf(where, " -%1d.%1u%%", (unsigned)(percent10 / 10LL),
                   1580:                                              (unsigned)(percent10 % 10LL));
1.6       mrg      1581:        else
1.29.2.5  jmc      1582:                fprintf(where, "%c%2d.%1u%%", ch, (unsigned)(percent10 / 10LL),
                   1583:                                                  (unsigned)(percent10 % 10LL));
1.6       mrg      1584: }
                   1585:
1.26      mrg      1586: #ifndef SMALL
1.1       mrg      1587: /* print compression statistics, and the new name (if there is one!) */
                   1588: static void
1.29.2.2  grant    1589: print_verbage(char *file, char *nfile, off_t usize, off_t gsize)
1.1       mrg      1590: {
1.29.2.7  jmc      1591:        if (file)
                   1592:                fprintf(stderr, "%s:%s  ", file,
                   1593:                    strlen(file) < 7 ? "\t\t" : "\t");
1.29.2.2  grant    1594:        print_ratio((off_t)usize, (off_t)gsize, stderr);
1.4       mrg      1595:        if (nfile)
                   1596:                fprintf(stderr, " -- replaced with %s", nfile);
1.1       mrg      1597:        fprintf(stderr, "\n");
                   1598:        fflush(stderr);
                   1599: }
                   1600:
                   1601: /* print test results */
                   1602: static void
1.29.2.12  tron     1603: print_test(const char *file, int ok)
1.1       mrg      1604: {
                   1605:
1.29.2.13  tron     1606:        if (exit_value == 0 && ok == 0)
                   1607:                exit_value = 1;
1.1       mrg      1608:        fprintf(stderr, "%s:%s  %s\n", file,
                   1609:            strlen(file) < 7 ? "\t\t" : "\t", ok ? "OK" : "NOT OK");
                   1610:        fflush(stderr);
                   1611: }
1.26      mrg      1612: #endif
1.1       mrg      1613:
1.5       mrg      1614: /* print a file's info ala --list */
                   1615: /* eg:
                   1616:   compressed uncompressed  ratio uncompressed_name
                   1617:       354841      1679360  78.8% /usr/pkgsrc/distfiles/libglade-2.0.1.tar
                   1618: */
                   1619: static void
1.29.2.5  jmc      1620: print_list(int fd, off_t out, const char *outfile, time_t ts)
1.5       mrg      1621: {
                   1622:        static int first = 1;
1.29      mrg      1623: #ifndef SMALL
1.6       mrg      1624:        static off_t in_tot, out_tot;
1.29      mrg      1625:        u_int32_t crc;
                   1626: #endif
1.29.2.5  jmc      1627:        off_t in;
1.5       mrg      1628:        int rv;
                   1629:
1.7       mrg      1630:        if (first) {
1.26      mrg      1631: #ifndef SMALL
1.7       mrg      1632:                if (vflag)
                   1633:                        printf("method  crc     date  time  ");
1.26      mrg      1634: #endif
1.7       mrg      1635:                if (qflag == 0)
                   1636:                        printf("  compressed uncompressed  "
                   1637:                               "ratio uncompressed_name\n");
                   1638:        }
1.5       mrg      1639:        first = 0;
                   1640:
1.6       mrg      1641:        /* print totals? */
1.29      mrg      1642: #ifndef SMALL
1.6       mrg      1643:        if (fd == -1) {
                   1644:                in = in_tot;
                   1645:                out = out_tot;
1.29      mrg      1646:        } else
                   1647: #endif
                   1648:        {
1.6       mrg      1649:                /* read the last 4 bytes - this is the uncompressed size */
1.7       mrg      1650:                rv = lseek(fd, (off_t)(-8), SEEK_END);
1.6       mrg      1651:                if (rv != -1) {
1.7       mrg      1652:                        unsigned char buf[8];
1.6       mrg      1653:                        u_int32_t usize;
                   1654:
                   1655:                        if (read(fd, (char *)buf, sizeof(buf)) != sizeof(buf))
1.29.2.7  jmc      1656:                                maybe_warn("read of uncompressed size");
1.7       mrg      1657:                        usize = buf[4] | buf[5] << 8 | buf[6] << 16 | buf[7] << 24;
1.29.2.5  jmc      1658:                        in = (off_t)usize;
1.29      mrg      1659: #ifndef SMALL
                   1660:                        crc = buf[0] | buf[1] << 8 | buf[2] << 16 | buf[3] << 24;
                   1661: #endif
1.6       mrg      1662:                }
                   1663:        }
1.5       mrg      1664:
1.26      mrg      1665: #ifndef SMALL
1.7       mrg      1666:        if (vflag && fd == -1)
                   1667:                printf("                            ");
                   1668:        else if (vflag) {
                   1669:                char *date = ctime(&ts);
                   1670:
                   1671:                /* skip the day, 1/100th second, and year */
                   1672:                date += 4;
                   1673:                date[12] = 0;
                   1674:                printf("%5s %08x %11s ", "defla"/*XXX*/, crc, date);
                   1675:        }
1.29      mrg      1676:        in_tot += in;
                   1677:        out_tot += out;
1.26      mrg      1678: #endif
1.29.2.5  jmc      1679:        printf("%12llu %12llu ", (unsigned long long)out, (unsigned long long)in);
1.6       mrg      1680:        print_ratio(in, out, stdout);
                   1681:        printf(" %s\n", outfile);
1.5       mrg      1682: }
                   1683:
1.1       mrg      1684: /* display the usage of NetBSD gzip */
                   1685: static void
                   1686: usage(void)
                   1687: {
                   1688:
                   1689:        fprintf(stderr, "%s\n", gzip_version);
                   1690:        fprintf(stderr,
1.29      mrg      1691:     "usage: %s [-" OPT_LIST "] [<file> [<file> ...]]\n"
1.11      mrg      1692: #ifndef SMALL
1.1       mrg      1693:     " -c --stdout          write to stdout, keep original files\n"
                   1694:     "    --to-stdout\n"
                   1695:     " -d --decompress      uncompress files\n"
                   1696:     "    --uncompress\n"
                   1697:     " -f --force           force overwriting & compress links\n"
                   1698:     " -h --help            display this help\n"
                   1699:     " -n --no-name         don't save original file name or time stamp\n"
                   1700:     " -N --name            save or restore original file name and time stamp\n"
                   1701:     " -q --quiet           output no warnings\n"
                   1702:     " -r --recursive       recursively compress files in directories\n"
                   1703:     " -S .suf              use suffix .suf instead of .gz\n"
                   1704:     "    --suffix .suf\n"
                   1705:     " -t --test            test compressed file\n"
                   1706:     " -v --verbose         print extra statistics\n"
                   1707:     " -V --version         display program version\n"
                   1708:     " -1 --fast            fastest (worst) compression\n"
                   1709:     " -2 .. -8             set compression level\n"
                   1710:     " -9 --best            best (slowest) compression\n",
1.11      mrg      1711: #else
                   1712:     ,
                   1713: #endif
1.1       mrg      1714:            getprogname());
                   1715:        exit(0);
                   1716: }
                   1717:
                   1718: /* display the version of NetBSD gzip */
                   1719: static void
                   1720: display_version(void)
                   1721: {
                   1722:
                   1723:        fprintf(stderr, "%s\n", gzip_version);
                   1724:        exit(0);
                   1725: }
1.10      mrg      1726:
1.24      tsutsui  1727: #ifndef NO_BZIP2_SUPPORT
1.10      mrg      1728: #include "unbzip2.c"
1.24      tsutsui  1729: #endif
                   1730: #ifndef NO_COMPRESS_SUPPORT
1.22      mrg      1731: #include "zuncompress.c"
1.24      tsutsui  1732: #endif

CVSweb <webmaster@jp.NetBSD.org>