Annotation of coherent/g/usr/bin/gzip/gzip.c, revision 1.1.1.1

1.1       root        1: /* gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
                      2:  * Copyright (C) 1992-1993 Jean-loup Gailly
                      3:  * The unzip code was written and put in the public domain by Mark Adler.
                      4:  * Portions of the lzw code are derived from the public domain 'compress'
                      5:  * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies,
                      6:  * Ken Turkowski, Dave Mack and Peter Jannesen.
                      7:  *
                      8:  * See the license_msg below and the file COPYING for the software license.
                      9:  * See the file algorithm.doc for the compression algorithms and file formats.
                     10:  */
                     11: 
                     12: static char  *license_msg[] = {
                     13: "   Copyright (C) 1992-1993 Jean-loup Gailly",
                     14: "   This program is free software; you can redistribute it and/or modify",
                     15: "   it under the terms of the GNU General Public License as published by",
                     16: "   the Free Software Foundation; either version 2, or (at your option)",
                     17: "   any later version.",
                     18: "",
                     19: "   This program is distributed in the hope that it will be useful,",
                     20: "   but WITHOUT ANY WARRANTY; without even the implied warranty of",
                     21: "   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the",
                     22: "   GNU General Public License for more details.",
                     23: "",
                     24: "   You should have received a copy of the GNU General Public License",
                     25: "   along with this program; if not, write to the Free Software",
                     26: "   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.",
                     27: 0};
                     28: 
                     29: /* Compress files with zip algorithm and 'compress' interface.
                     30:  * See usage() and help() functions below for all options.
                     31:  * Outputs:
                     32:  *        file.z:   compressed file with same mode, owner, and utimes
                     33:  *        file.Z:   same with -Z option (old compress format)
                     34:  *     or stdout with -c option or if stdin used as input.
                     35:  * If the OS does not support file names with multiple dots (MSDOS, VMS) or
                     36:  * if the output file name had to be truncated, the original name is kept
                     37:  * in the compressed .z file. (Feature not available in old compress format.)
                     38:  * On MSDOS, file.tmp -> file.tmz. On VMS, file.tmp -> file.tmp-z.
                     39:  *
                     40:  * For the meaning of all compilation flags, see comments in Makefile.in.
                     41:  */
                     42: 
                     43: #ifndef lint
                     44: static char rcsid[] = "$Id: gzip.c,v 0.14 1993/02/24 18:23:13 jloup Exp $";
                     45: #endif
                     46: 
                     47: #include "tailor.h"
                     48: #include "gzip.h"
                     49: #include "lzw.h"
                     50: #include "revision.h"
                     51: #include "getopt.h"
                     52: 
                     53: #include <stdio.h>
                     54: #include <ctype.h>
                     55: #include <sys/types.h>
                     56: #include <signal.h>
                     57: #include <sys/stat.h>
                     58: #include <errno.h>
                     59: 
                     60:                /* configuration */
                     61: 
                     62: #ifndef NO_FCNTL_H
                     63: #  include <fcntl.h>
                     64: #endif
                     65: 
                     66: #ifdef HAVE_UNISTD_H
                     67: #  include <unistd.h>
                     68: #endif
                     69: 
                     70: #if defined(STDC_HEADERS) || !defined(NO_STDLIB_H)
                     71: #  include <stdlib.h>
                     72: #else
                     73:    extern int errno;
                     74: #endif
                     75: 
                     76: #if defined(DIRENT) || defined(_POSIX_VERSION)
                     77: #  include <dirent.h>
                     78:    typedef struct dirent dir_type;
                     79: #  define NLENGTH(dirent) ((int)strlen((dirent)->d_name))
                     80: #  define DIR_OPT "DIRENT"
                     81: #else
                     82: #  define NLENGTH(dirent) ((dirent)->d_namlen)
                     83: #  ifdef SYSDIR
                     84: #    include <sys/dir.h>
                     85:      typedef struct direct dir_type;
                     86: #    define DIR_OPT "SYSDIR"
                     87: #  else
                     88: #    ifdef SYSNDIR
                     89: #      include <sys/ndir.h>
                     90:        typedef struct direct dir_type;
                     91: #      define DIR_OPT "SYSNDIR"
                     92: #    else
                     93: #      ifdef NDIR
                     94: #        include <ndir.h>
                     95:          typedef struct direct dir_type;
                     96: #        define DIR_OPT "NDIR"
                     97: #      else
                     98: #        define NO_DIR
                     99: #        define DIR_OPT "NO_DIR"
                    100: #      endif
                    101: #    endif
                    102: #  endif
                    103: #endif
                    104: 
                    105: #ifndef NO_UTIME
                    106: #  ifndef NO_UTIME_H
                    107: #    include <utime.h>
                    108: #    define TIME_OPT "UTIME"
                    109: #  else
                    110: #    ifdef HAVE_SYS_UTIME_H
                    111: #      include <sys/utime.h>
                    112: #      define TIME_OPT "SYS_UTIME"
                    113: #    else
                    114:        struct utimbuf {
                    115:          time_t actime;
                    116:          time_t modtime;
                    117:        };
                    118: #      define TIME_OPT ""
                    119: #    endif
                    120: #  endif
                    121: #else
                    122: #  define TIME_OPT "NO_UTIME"
                    123: #endif
                    124: 
                    125: #if !defined(S_ISDIR) && defined(S_IFDIR)
                    126: #  define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
                    127: #endif
                    128: #if !defined(S_ISREG) && defined(S_IFREG)
                    129: #  define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
                    130: #endif
                    131: 
                    132: typedef RETSIGTYPE (*sig_type)();
                    133: 
                    134: #ifndef        O_BINARY
                    135: #  define  O_BINARY  0  /* creation mode for open() */
                    136: #endif
                    137: 
                    138: #define RW_USER 0600    /* creation mode for open() */
                    139: 
                    140: #ifndef MAX_PATH_LEN
                    141: #  define MAX_PATH_LEN   1024 /* max pathname length */
                    142: #endif
                    143: 
                    144: #define MAX_HEADER_LEN   16
                    145: /* max length of a compressed file header, fixed part only */
                    146: 
                    147:                /* global buffers */
                    148: 
                    149: DECLARE(uch, inbuf,  INBUFSIZ +INBUF_EXTRA);
                    150: DECLARE(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
                    151: DECLARE(ush, d_buf,  DIST_BUFSIZE);
                    152: DECLARE(uch, window, 2L*WSIZE);
                    153: #ifndef MAXSEG_64K
                    154:     DECLARE(ush, tab_prefix, 1L<<BITS);
                    155: #else
                    156:     DECLARE(ush, tab_prefix0, 1L<<(BITS-1));
                    157:     DECLARE(ush, tab_prefix1, 1L<<(BITS-1));
                    158: #endif
                    159: 
                    160:                /* local variables */
                    161: 
                    162: int to_stdout = 0;    /* output to stdout (-c) */
                    163: int decompress = 0;   /* decompress (-d) */
                    164: int force = 0;        /* don't ask questions, compress links (-f) */
                    165: int recursive = 0;    /* recurse through directories (-r) */
                    166: int verbose = 0;      /* be verbose (-v) */
                    167: int quiet = 0;        /* be very quiet (-q) */
                    168: int do_lzw = 0;       /* generate output compatible with old compress (-Z) */
                    169: int test = 0;         /* test .z file integrity */
                    170: int foreground;       /* set if program run in foreground */
                    171: char *progname;       /* program name */
                    172: int maxbits = BITS;   /* max bits per code for LZW */
                    173: int method = DEFLATED;/* compression method */
                    174: int level = 5;        /* compression level */
                    175: int exit_code = OK;   /* program exit code */
                    176: int save_orig_name;   /* set if original name must be saved */
                    177: int text_mode;        /* set if original file is a text file (in variable
                    178:                         record format for VMS). Must stay 0 if unknown. */
                    179: 
                    180: int last_member;      /* set for .zip and .Z files */
                    181: int part_nb;          /* number of parts in .z file */
                    182: ulg time_stamp;       /* original time stamp (modification time) */
                    183: long ifile_size;      /* input file size, -1 for devices (debug only) */
                    184: char *env;            /* contents of GZIP env variable */
                    185: char **args = NULL;   /* argv pointer if GZIP env variable defined */
                    186: 
                    187: long bytes_in;             /* number of input bytes */
                    188: long bytes_out;            /* number of output bytes */
                    189: char ifname[MAX_PATH_LEN]; /* input filename */
                    190: char ofname[MAX_PATH_LEN]; /* output filename */
                    191: int  remove_ofname = 0;           /* remove output file on error */
                    192: struct stat istat;         /* status for input file */
                    193: int  ifd;                  /* input file descriptor */
                    194: int  ofd;                  /* output file descriptor */
                    195: unsigned insize;           /* valid bytes in inbuf */
                    196: unsigned inptr;            /* index of next byte to be processed in inbuf */
                    197: unsigned outcnt;           /* bytes in output buffer */
                    198: 
                    199: struct option longopts[] =
                    200: {
                    201:  /* { name  has_arg  *flag  val } */
                    202:  /* {"ascii",      0, 0, 'a'},  ascii text mode */
                    203:     {"stdout",     0, 0, 'c'}, /* write output on standard output */
                    204:     {"decompress", 0, 0, 'd'}, /* decompress */
                    205:  /* {"encrypt",    0, 0, 'e'},    encrypt */
                    206:     {"force",      0, 0, 'f'}, /* force overwrite of output file */
                    207:     {"help",       0, 0, 'h'}, /* give help */
                    208:  /* {"pkzip",      0, 0, 'k'},    force output in pkzip format */
                    209:  /* {"list",       0, 0, 'l'},    list .z file contents */
                    210:     {"license",    0, 0, 'L'}, /* display software license */
                    211:     {"quiet",      0, 0, 'q'}, /* quiet mode */
                    212:     {"recurse",    0, 0, 'r'}, /* recurse through directories */
                    213:     {"test",       0, 0, 't'}, /* test compressed file integrity */
                    214:     {"verbose",    0, 0, 'v'}, /* verbose mode */
                    215:     {"version",    0, 0, 'V'}, /* display version number */
                    216:     {"fast",       0, 0, '1'}, /* compress faster */
                    217:     {"best",       0, 0, '9'}, /* compress better */
                    218:     {"lzw",        0, 0, 'Z'}, /* make output compatible with old compress */
                    219:     {"bits",       1, 0, 'b'}, /* max number of bits per code (implies -Z) */
                    220:     { 0, 0, 0, 0 }
                    221: };
                    222: 
                    223: /* local functions */
                    224: 
                    225: local void usage        OF((void));
                    226: local void help         OF((void));
                    227: local void license      OF((void));
                    228: local void version      OF((void));
                    229: local void treat_stdin  OF((void));
                    230: local void treat_file   OF((char *iname));
                    231: local int create_outfile OF((void));
                    232: local int  do_stat      OF((char *name, struct stat *sbuf));
                    233: local char *get_suffix  OF((char *name));
                    234: local int  get_istat    OF((char *iname, struct stat *sbuf));
                    235: local int  make_ofname  OF((void));
                    236: local int  same_file    OF((struct stat *stat1, struct stat *stat2));
                    237: local int name_too_long OF((char *name, struct stat *statb));
                    238: local int  get_method   OF((int in));
                    239: local int  check_ofname OF((void));
                    240: local void copy_stat    OF((struct stat *ifstat));
                    241: local void treat_dir    OF((char *dir));
                    242: local void do_exit      OF((int exitcode));
                    243:       int main          OF((int argc, char **argv));
                    244: 
                    245: void (*work) OF((int infile, int outfile)) = zip; /* function to call */
                    246: 
                    247: #define strequ(s1, s2) (strcmp((s1),(s2)) == 0)
                    248: 
                    249: /* ======================================================================== */
                    250: local void usage()
                    251: {
                    252:     fprintf(stderr,
                    253: #ifdef LZW
                    254: #  ifdef NO_DIR
                    255:             "usage: %s [-cdfhLtvVZ19] [-b maxbits] [file ...]\n",
                    256: #  else
                    257:             "usage: %s [-cdfhLrtvVZ19] [-b maxbits] [file ...]\n",
                    258: #  endif
                    259: #else /* !LZW */
                    260: #  ifdef NO_DIR
                    261:             "usage: %s [-cdfhLtvV19] [file ...]\n",
                    262: #  else
                    263:             "usage: %s [-cdfhLrtvV19] [file ...]\n",
                    264: #  endif
                    265: #endif /* LZW */
                    266:              progname);
                    267: }
                    268: /* ======================================================================== */
                    269: local void help()
                    270: {
                    271:     static char  *help_msg[] = {
                    272: /* -a --ascii       ascii text; convert end-of-lines to local OS conventions */
                    273:  " -c --stdout      write on standard output, keep original files unchanged",
                    274:  " -d --decompress  decompress",
                    275: /* -e --encrypt     encrypt */
                    276:  " -f --force       force overwrite of output file and compress links",
                    277:  " -h --help        give this help",
                    278: /* -k --pkzip       force output in pkzip format */
                    279: /* -l --list        list .z file contents */
                    280:  " -L --license     display software license",
                    281:  " -q --quiet       suppress all warnings",
                    282: #ifndef NO_DIR
                    283:  " -r --recurse     recurse through directories",
                    284: #endif
                    285:  " -t --test        test compressed file integrity",
                    286:  " -v --verbose     verbose mode",
                    287:  " -V --version     display version number",
                    288:  " -1 --fast        compress faster",
                    289:  " -9 --best        compress better",
                    290: #ifdef LZW
                    291:  " -Z --lzw         produce output compatible with old compress",
                    292:  " -b --bits maxbits   max number of bits per code (implies -Z)",
                    293: #endif
                    294:  " file...          files to (de)compress. If none given, use standard input.",
                    295:   0};
                    296:     char **p = help_msg;
                    297: 
                    298:     fprintf(stderr,"%s %s (%s)\n", progname, VERSION, REVDATE);
                    299:     usage();
                    300:     while (*p) fprintf(stderr, "%s\n", *p++);
                    301: }
                    302: 
                    303: /* ======================================================================== */
                    304: local void license()
                    305: {
                    306:     char **p = license_msg;
                    307: 
                    308:     fprintf(stderr,"%s %s (%s)\n", progname, VERSION, REVDATE);
                    309:     while (*p) fprintf(stderr, "%s\n", *p++);
                    310: }
                    311: 
                    312: /* ======================================================================== */
                    313: local void version()
                    314: {
                    315:     fprintf(stderr,"%s %s (%s)\n", progname, VERSION, REVDATE);
                    316: 
                    317:     fprintf(stderr, "Compilation options:\n%s %s ", DIR_OPT, TIME_OPT);
                    318: #ifdef STDC_HEADERS
                    319:     fprintf(stderr, "STDC_HEADERS ");
                    320: #endif
                    321: #ifdef HAVE_UNISTD_H
                    322:     fprintf(stderr, "HAVE_UNISTD_H ");
                    323: #endif
                    324: #ifdef NO_MEMORY_H
                    325:     fprintf(stderr, "NO_MEMORY_H ");
                    326: #endif
                    327: #ifdef NO_STRING_H
                    328:     fprintf(stderr, "NO_STRING_H ");
                    329: #endif
                    330: #ifdef NO_SYMLINK
                    331:     fprintf(stderr, "NO_SYMLINK ");
                    332: #endif
                    333: #ifdef NO_MULTIPLE_DOTS
                    334:     fprintf(stderr, "NO_MULTIPLE_DOTS ");
                    335: #endif
                    336: #ifdef NO_CHOWN
                    337:     fprintf(stderr, "NO_CHOWN ");
                    338: #endif
                    339: #ifdef PROTO
                    340:     fprintf(stderr, "PROTO ");
                    341: #endif
                    342: #ifdef ASMV
                    343:     fprintf(stderr, "ASMV ");
                    344: #endif
                    345: #ifdef DEBUG
                    346:     fprintf(stderr, "DEBUG ");
                    347: #endif
                    348: #ifdef DYN_ALLOC
                    349:     fprintf(stderr, "DYN_ALLOC ");
                    350: #endif
                    351: #ifdef MAXSEG_64K
                    352:     fprintf(stderr, "MAXSEG_64K");
                    353: #endif
                    354:     fprintf(stderr, "\n");
                    355: }
                    356: 
                    357: /* ======================================================================== */
                    358: int main (argc, argv)
                    359:     int argc;
                    360:     char **argv;
                    361: {
                    362:     int file_count = 0; /* number of files to precess */
                    363:     int proglen;        /* length of progname */
                    364:     int optc;           /* current option */
                    365: 
                    366:     EXPAND(argc, argv); /* wild card expansion if necessary */
                    367: 
                    368:     /* Add options in GZIP environment variable if there is one */
                    369:     env = add_envopt(&argc, &argv, OPTIONS_VAR);
                    370:     if (env != NULL) args = argv;
                    371: 
                    372:     foreground = signal(SIGINT, SIG_IGN) != SIG_IGN;
                    373:     if (foreground) {
                    374:        signal (SIGINT, (sig_type)abort_gzip);
                    375:     }
                    376: #ifdef SIGTERM
                    377:     signal(SIGTERM, (sig_type)abort_gzip);
                    378: #endif
                    379: #ifdef SIGHUP
                    380:     signal(SIGHUP,  (sig_type)abort_gzip);
                    381: #endif
                    382: 
                    383:     progname = basename(argv[0]);
                    384:     proglen = strlen(progname);
                    385:     /* Suppress .exe for MSDOS, OS/2 and VMS: */
                    386:     if (proglen > 4 && strequ(progname+proglen-4, ".exe")) {
                    387:         progname[proglen-4] = '\0';
                    388:     }
                    389: 
                    390:     /* For compatibility with old compress, use program name as an option.
                    391:      * Systems which do not support links can still use -d or -dc.
                    392:      * Ignore an .exe extension for MSDOS, OS/2 and VMS.
                    393:      */
                    394:     if (  strncmp(progname, "un",  2) == 0     /* ungzip, uncompress */
                    395:        || strncmp(progname, "gun", 3) == 0) {  /* gunzip */
                    396:        decompress = 1;
                    397:     } else if (strequ(progname+1, "cat")       /* zcat, pcat */
                    398:            || strequ(progname, "gzcat")) {    /* gzcat */
                    399:        decompress = to_stdout = 1;
                    400:     }
                    401: 
                    402:     while ((optc = getopt_long (argc, argv, "b:cdfhLqrtvVZ123456789",
                    403:                                longopts, (int *)0)) != EOF) {
                    404:        switch (optc) {
                    405:        case 'b':
                    406:            maxbits = atoi(optarg);
                    407:            break;
                    408:        case 'c':
                    409:            to_stdout = 1; break;
                    410:        case 'd':
                    411:            decompress = 1; break;
                    412:        case 'f':
                    413:            force++; break;
                    414:        case 'h':
                    415:            help(); do_exit(OK); break;
                    416:        case 'L':
                    417:            license(); do_exit(OK); break;
                    418:        case 'q':
                    419:            quiet = 1; verbose = 0; break;
                    420:        case 'r':
                    421: #ifdef NO_DIR
                    422:            fprintf(stderr, "-r not supported on this system\n");
                    423:            usage();
                    424:            do_exit(ERROR); break;
                    425: #else
                    426:            recursive = 1; break;
                    427: #endif
                    428:        case 't':
                    429:            test = decompress = to_stdout = 1;
                    430:            break;
                    431:        case 'v':
                    432:            verbose++; quiet = 0; break;
                    433:        case 'V':
                    434:            version(); break;
                    435:        case 'Z':
                    436: #ifdef LZW
                    437:            do_lzw = 1; break;
                    438: #else
                    439:            fprintf(stderr, "-Z not supported in this version\n");
                    440:            usage();
                    441:            do_exit(ERROR); break;
                    442: #endif
                    443:        case '1':  case '2':  case '3':  case '4':
                    444:        case '5':  case '6':  case '7':  case '8':  case '9':
                    445:            level = optc - '0';
                    446:            break;
                    447:        default:
                    448:            /* Error message already emitted by getopt_long. */
                    449:            usage();
                    450:            do_exit(ERROR);
                    451:        }
                    452:     } /* loop on all arguments */
                    453: 
                    454:     file_count = argc - optind;
                    455: 
                    456:     if (do_lzw && !decompress) work = lzw;
                    457: 
                    458:     /* Allocate all global buffers (for DYN_ALLOC option) */
                    459:     ALLOC(uch, inbuf,  INBUFSIZ +INBUF_EXTRA);
                    460:     ALLOC(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
                    461:     ALLOC(ush, d_buf,  DIST_BUFSIZE);
                    462:     ALLOC(uch, window, 2L*WSIZE);
                    463: #ifndef MAXSEG_64K
                    464:     ALLOC(ush, tab_prefix, 1L<<BITS);
                    465: #else
                    466:     ALLOC(ush, tab_prefix0, 1L<<(BITS-1));
                    467:     ALLOC(ush, tab_prefix1, 1L<<(BITS-1));
                    468: #endif
                    469: 
                    470:     /* And get to work */
                    471:     if (file_count != 0) {
                    472:        if (to_stdout && !test) {
                    473:            SET_BINARY_MODE(fileno(stdout));
                    474:        }
                    475:         while (optind < argc) {
                    476:            treat_file(argv[optind++]);
                    477:        }
                    478:     } else {  /* Standard input */
                    479:        treat_stdin();
                    480:     }
                    481:     do_exit(exit_code);
                    482:     return exit_code; /* just to avoid lint warning */
                    483: }
                    484: 
                    485: /* ========================================================================
                    486:  * Compress or decompress stdin
                    487:  */
                    488: local void treat_stdin()
                    489: {
                    490:     if (isatty(fileno((FILE *)(decompress ? stdin : stdout)))) {
                    491:        /* Do not send compressed data to the terminal or read it from
                    492:         * the terminal. We get here when user invoked the program
                    493:         * without parameters, so be helpful.
                    494:         */
                    495:        fprintf(stderr,
                    496:              "Compressed data not %s a terminal. Redirect %s file or pipe.\n",
                    497:                decompress ? "read from" : "written to",
                    498:                decompress ? "from" : "to");
                    499:        fprintf(stderr,"For help, type: %s -h\n", progname);
                    500:        do_exit(ERROR);
                    501:     }
                    502:     SET_BINARY_MODE(fileno(stdin));
                    503:     if (!test) SET_BINARY_MODE(fileno(stdout));
                    504: 
                    505:     strcpy(ifname, "stdin");
                    506:     strcpy(ofname, "stdout");
                    507: 
                    508:     /* Get the time stamp on the input file */
                    509: #ifdef NO_STDIN_FSTAT
                    510:     time_stamp = 0; /* time unknown */
                    511:     text_mode  = 0; /* type unknown */
                    512: #else
                    513:     if (fstat(fileno(stdin), &istat) != 0) {
                    514:        error("fstat(stdin)");
                    515:     } 
                    516:     time_stamp = istat.st_mtime;
                    517:     text_mode = TEXT_MODE(istat);
                    518: #endif
                    519:     ifile_size = -1L; /* convention for unknown size */
                    520: 
                    521:     clear_bufs(); /* clear input and output buffers */
                    522:     to_stdout = 1;
                    523:     part_nb = 0;
                    524: 
                    525:     if (decompress) {
                    526:        method = get_method(ifd);
                    527:        if (method < 0) {
                    528:            do_exit(exit_code); /* error message already emitted */
                    529:        }
                    530:     }
                    531: 
                    532:     /* Actually do the compression/decompression. Loop over zipped members.
                    533:      */
                    534:     for (;;) {
                    535:        (*work)(fileno(stdin), fileno(stdout));
                    536: 
                    537:        if (!decompress || last_member || inptr == insize) break;
                    538:        /* end of file */
                    539: 
                    540:        method = get_method(ifd);
                    541:        if (method == -1) return; /* error message already emitted */
                    542:        bytes_out = 0;            /* required for length check */
                    543:     }
                    544: 
                    545:     if (verbose) {
                    546:        if (test) {
                    547:            fprintf(stderr, " OK");
                    548: 
                    549:        } else if (!decompress) {
                    550:            fprintf(stderr, "Compression: ");
                    551:            display_ratio(bytes_in-bytes_out-overhead, bytes_in);
                    552:        }
                    553:        fprintf(stderr, "\n");
                    554:     }
                    555: }
                    556: 
                    557: /* ========================================================================
                    558:  * Compress or decompress the given file
                    559:  */
                    560: local void treat_file(iname)
                    561:     char *iname;
                    562: {
                    563:     /* Check if the input file is present, set ifname and istat: */
                    564:     if (get_istat(iname, &istat) != 0) return;
                    565: 
                    566:     /* If the input name is that of a directory, recurse or ignore: */
                    567:     if (S_ISDIR(istat.st_mode)) {
                    568: #ifndef NO_DIR
                    569:        if (recursive) {
                    570:            treat_dir(iname);
                    571:            /* Warning: ifname is now garbage */
                    572:        } else
                    573: #endif
                    574:        WARN((stderr,"%s is a directory -- ignored\n", ifname));
                    575:        return;
                    576:     }
                    577:     if (!S_ISREG(istat.st_mode)) {
                    578:        WARN((stderr, "%s is not a directory or a regular file - ignored\n",
                    579:              ifname));
                    580:        return;
                    581:     }
                    582:     if (istat.st_nlink > 1 && !to_stdout && !force) {
                    583:        WARN((stderr, "%s has %d other link%c -- unchanged\n", ifname,
                    584:              (int)istat.st_nlink - 1, istat.st_nlink > 2 ? 's' : ' '));
                    585:        return;
                    586:     }
                    587: 
                    588:     ifile_size = istat.st_size;
                    589:     time_stamp = istat.st_mtime;
                    590:     text_mode = TEXT_MODE(istat);
                    591: 
                    592:     /* Generate output file name */
                    593:     if (to_stdout) {
                    594:        strcpy(ofname, "stdout");
                    595: 
                    596:     } else if (make_ofname() != 0) {
                    597:        return;
                    598:     }
                    599: 
                    600:     /* Open the input file and determine compression method. The mode
                    601:      * parameter is ignored but required by some systems (VMS).
                    602:      */
                    603:     ifd = open(ifname, O_RDONLY | O_BINARY, RW_USER);
                    604:     if (ifd == -1) {
                    605:        perror(ifname);
                    606:        exit_code = ERROR;
                    607:        return;
                    608:     }
                    609:     clear_bufs(); /* clear input and output buffers */
                    610:     part_nb = 0;
                    611: 
                    612:     if (decompress) {
                    613:        method = get_method(ifd); /* updates ofname if original given */
                    614:        if (method < 0) {
                    615:            close(ifd);
                    616:            return;               /* error message already emitted */
                    617:        }
                    618:     }
                    619: 
                    620:     /* If compressing to a file, check if ofname is not ambigous
                    621:      * because the operating system truncates names. Otherwise, generate
                    622:      * a new ofname and save the original name in the compressed file.
                    623:      */
                    624:     if (to_stdout) {
                    625:        ofd = fileno(stdout);
                    626:        /* keep remove_ofname as zero */
                    627:     } else {
                    628:        if (create_outfile() == -1) return;
                    629: 
                    630:        if (save_orig_name && !verbose && !quiet) {
                    631:            fprintf(stderr, "%s compressed to %s\n", ifname, ofname);
                    632:        }
                    633:     }
                    634:     if (verbose) {
                    635:        fprintf(stderr, "%s:\t%s", ifname, (int)strlen(ifname) >= 15 ? 
                    636:                "" : ((int)strlen(ifname) >= 7 ? "\t" : "\t\t"));
                    637:     }
                    638: 
                    639:     /* Actually do the compression/decompression. Loop over zipped members.
                    640:      */
                    641:     for (;;) {
                    642:        (*work)(ifd, ofd);
                    643: 
                    644:        if (!decompress || last_member || inptr == insize) break;
                    645:        /* end of file */
                    646: 
                    647:        method = get_method(ifd);
                    648:        if (method < 0) break;    /* error message already emitted */
                    649:        bytes_out = 0;            /* required for length check */
                    650:     }
                    651: 
                    652:     close(ifd);
                    653:     if (!to_stdout && close(ofd)) {
                    654:        write_error();
                    655:     }
                    656:     if (method == -1) return;     /* error, don't display success msg */
                    657: 
                    658:     /* Display statistics */
                    659:     if(verbose) {
                    660:        if (!decompress) {
                    661:            display_ratio(bytes_in-bytes_out-overhead, bytes_in);
                    662:        }
                    663:        if (test) {
                    664:            fprintf(stderr, " OK");
                    665:        } else if (!to_stdout) {
                    666:            fprintf(stderr, " -- replaced with %s", ofname);
                    667:        }
                    668:        fprintf(stderr, "\n");
                    669:     }
                    670:     /* Copy modes, times, ownership */
                    671:     if (!to_stdout) {
                    672:        copy_stat(&istat);
                    673:     }
                    674: }
                    675: 
                    676: /* ========================================================================
                    677:  * Create the output file. Return 0 for success, -1 for error.
                    678:  * Try twice if ofname is exactly one beyond the name limit, to avoid
                    679:  * creating a compressed file of name "1234567890123."
                    680:  * We could actually loop more than once if the user gives an extra long
                    681:  * name, but I prefer generating an error then. (Posix forbids the system
                    682:  * to truncate names.) The error message is generated by check_ofname()
                    683:  * in this case.
                    684:  * IN assertions: the input file has already been open (ifd is set) and
                    685:  *   ofname has already been updated if there was an original name.
                    686:  *   text_mode has been initialized if decompressing.
                    687:  * OUT assertions: ifd and ofd are closed in case of error.
                    688:  */
                    689: local int create_outfile()
                    690: {
                    691:     struct stat        ostat; /* stat for ofname */
                    692:     int n;             /* loop counter */
                    693: 
                    694:     for (n = 1; n <= 2; n++) {
                    695:        if (check_ofname() == -1) {
                    696:            close(ifd);
                    697:            return -1;
                    698:        }
                    699:        /* Create the output file */
                    700:        remove_ofname = 1;
                    701:        if (decompress) {
                    702:            ofd = CREATE(ofname, text_mode);
                    703:        } else {
                    704:            ofd = open(ofname, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, RW_USER);
                    705:        }
                    706:        if (ofd == -1) {
                    707:            perror(ofname);
                    708:            close(ifd);
                    709:            exit_code = ERROR;
                    710:            return -1;
                    711:        }
                    712: 
                    713:        /* Check for name truncation on new file (1234567890123.z) */
                    714:        if (fstat(ofd, &ostat) != 0) {
                    715:            perror(ofname);
                    716:            fprintf(stderr, " fstat failed\n");
                    717:            close(ifd); close(ofd);
                    718:            unlink(ofname);
                    719:            exit_code = ERROR;
                    720:            return -1;
                    721:        }
                    722:        if (!name_too_long(ofname, &ostat)) return 0;
                    723: 
                    724:        if (decompress) {
                    725:            /* name might be too long if an original name was saved */
                    726:            if (!quiet) {
                    727:                fprintf(stderr, " warning, name truncated: %s\n", ofname);
                    728:            }
                    729:            return 0;
                    730:        } else {
                    731: #ifdef NO_MULTIPLE_DOTS
                    732:            /* Should never happen, see check_ofname() */
                    733:            fprintf(stderr, "ERROR: name too long: %s\n", ofname);
                    734:            do_exit(ERROR);
                    735: #else
                    736:            close(ofd);
                    737:            unlink(ofname);
                    738:            save_orig_name = 1;
                    739:            strcpy(ofname+strlen(ofname)-Z_LEN-1, Z_SUFFIX);
                    740:             /* 1234567890123.z -> 123456789012.z */
                    741: #endif
                    742:        } /* decompress ? */
                    743:     } /* for (n) */
                    744: 
                    745:     close(ifd);
                    746:     fprintf(stderr, " name too long: %s\n", ofname);
                    747:     exit_code = ERROR;
                    748:     return -1;
                    749: }
                    750: 
                    751: /* ========================================================================
                    752:  * Use lstat if available, except for -c or -f. Use stat otherwise.
                    753:  * This allows links when not removing the original file.
                    754:  */
                    755: local int do_stat(name, sbuf)
                    756:     char *name;
                    757:     struct stat *sbuf;
                    758: {
                    759: #if (defined(S_IFLNK) || defined (S_ISLNK)) && !defined(NO_SYMLINK)
                    760:     if (!to_stdout && !force) {
                    761:        return lstat(name, sbuf);
                    762:     }
                    763: #endif
                    764:     return stat(name, sbuf);
                    765: }
                    766: 
                    767: /* ========================================================================
                    768:  * Return a pointer to the 'z' suffix of a file name, or NULL.
                    769:  * For all systems, ".z", ".Z", ".taz", ".tgz", "-z" are accepted suffixes.
                    770:  * ".tgz" is a useful convention for tar.z files on systems limited
                    771:  * to 3 characters extensions. On such systems, ".?z" and ".??z" are
                    772:  * also accepted suffixes. For Unix, we do not want to accept any
                    773:  * .??z suffix as indicating a compressed file; some people use .xyz
                    774:  * to denote volume data.
                    775:  */
                    776: local char *get_suffix(name)
                    777:     char *name;
                    778: {
                    779:     int len;
                    780:     char *p = strrchr(name, '.');
                    781:     char *v;
                    782:     char suffix[10];       /* last few chars of name, forced to lower case */
                    783: 
                    784:     if (p == NULL) return NULL;
                    785:     strncpy(suffix, p, sizeof(suffix));
                    786: 
                    787: #ifdef SUFFIX_SEP
                    788:     /* strip a version number from the file name */
                    789:    if ((v = strrchr(suffix, SUFFIX_SEP)) != NULL) *v = '\0';
                    790: #endif
                    791:     strlwr(suffix);
                    792:     if (strequ(suffix, ".z") || strequ(suffix, ".zip")
                    793:        || strequ(suffix, ".tgz") || strequ(suffix, ".taz")) {
                    794:        return p;
                    795:     }
                    796:     len = strlen(suffix);
                    797:     if (len <= 2) return NULL;
                    798: 
                    799:     if (strequ(suffix+len-2, "-z")) return p+len-2;
                    800: #ifdef MAX_EXT_CHARS
                    801:     if (suffix[len-1] == 'z') return p+len-1;
                    802: #endif
                    803:     return NULL;
                    804: }
                    805: 
                    806: 
                    807: /* ========================================================================
                    808:  * Set ifname to the input file name (with .z appended if necessary)
                    809:  * and istat to its stats. Return 0 if ok, -1 if error.
                    810:  */
                    811: local int get_istat(iname, sbuf)
                    812:     char *iname;
                    813:     struct stat *sbuf;
                    814: {
                    815:     int iexists; /* set if iname exists */
                    816:     int ilen = strlen(iname);
                    817:     char *suff;
                    818: 
                    819:     strcpy(ifname, iname);
                    820:     errno = 0;
                    821: 
                    822:     /* If input file exists, return OK. */
                    823:     if (do_stat(ifname, sbuf) == 0) return 0;
                    824: 
                    825:     if (!decompress || errno != ENOENT) {
                    826:        perror(ifname);
                    827:        exit_code = ERROR;
                    828:        return -1;
                    829:     }
                    830:     /* file.ext doesn't exist, try file.ext.z and file.ext.Z. For MSDOS
                    831:      * try file.exz, for VMS try file.ext-z.
                    832:      */
                    833:     suff = get_suffix(ifname);
                    834:     if (suff != NULL) {
                    835:        perror(ifname); /* ifname already has z suffix and does not exist */
                    836:        exit_code = ERROR;
                    837:        return -1;
                    838:     }
                    839: #ifdef SUFFIX_SEP
                    840:     /* strip a version number from the input file name */
                    841:     if ((suff = strrchr(ifname, SUFFIX_SEP)) != NULL) *suff = '\0';
                    842: #endif
                    843:     if (strrchr(ifname, '.') != NULL) {
                    844:        strcat(ifname, Z_SUFFIX);
                    845:        ilen += Z_LEN;
                    846:     } else {
                    847:        strcat(ifname, ".z");
                    848:        ilen += 2;
                    849:     }
                    850:     errno = 0;
                    851:     iexists = !do_stat(ifname, sbuf);
                    852:     if (!iexists) {
                    853:        errno = 0;
                    854:        ifname[ilen-1] = 'Z';
                    855:        iexists = !do_stat(ifname, sbuf);
                    856:     }
                    857: #ifdef NO_MULTIPLE_DOTS
                    858:     /* One more try just to be nice to you */
                    859:     if (!iexists) {
                    860:        char c = ifname[ilen-2];
                    861:        errno = 0;
                    862:        strcpy(ifname+ilen-2, "z");
                    863:        iexists = !do_stat(ifname, sbuf);
                    864:        if (!iexists) {
                    865:            ifname[ilen-2] = c;
                    866:        }
                    867:     }
                    868: #endif
                    869:     if (!iexists) {
                    870:        ifname[ilen-1] = 'z';
                    871:        perror(ifname);
                    872:        exit_code = ERROR;
                    873:        return -1;
                    874:     }
                    875:     if (!S_ISREG (sbuf->st_mode)) {
                    876:        WARN((stderr, "%s: Not a regular file -- ignored\n", ifname));
                    877:        return -1;
                    878:     }
                    879:     return 0; /* ok */
                    880: }
                    881: 
                    882: /* ========================================================================
                    883:  * Generate ofname given ifname. Return 0 if ok, -1 if file must be skipped.
                    884:  * Initializes save_orig_name.
                    885:  * IN assertion: this function is not called if to_stdout is true.
                    886:  */
                    887: local int make_ofname()
                    888: {
                    889:     char *suff;            /* ofname z suffix */
                    890: 
                    891:     strcpy(ofname, ifname);
                    892:     suff = get_suffix(ofname);
                    893: 
                    894:     if (decompress) {
                    895:        if (suff == NULL) {
                    896:            WARN((stderr,"%s -- no z suffix, ignored\n", ifname));
                    897:            return -1;
                    898:        }
                    899:        /* Make a special case for .tgz and .taz: */
                    900:        strlwr(suff);
                    901:        if (strequ(suff, ".tgz") || strequ(suff, ".taz")) {
                    902:            strcpy(suff, ".tar");
                    903:        } else {
                    904:            *suff = '\0'; /* strip z suffix and optional version number */
                    905:        }
                    906:         /* ofname might be changed later if infile contains an original name */
                    907: 
                    908:     } else if (suff != NULL) {
                    909:        /* Avoid annoying messages with -r (see treat_dir()) */
                    910:        if (verbose || (!recursive && !quiet)) {
                    911:            fprintf(stderr, "%s already has %s suffix -- unchanged\n",
                    912:                    ifname, suff);
                    913:        }
                    914:        if (exit_code == OK) exit_code = WARNING;
                    915:        return -1;
                    916:     } else {
                    917:         save_orig_name = 0;
                    918: 
                    919: #ifdef SUFFIX_SEP
                    920:        /* strip a version number from the file name */
                    921:        if ((suff = strrchr(ofname, SUFFIX_SEP)) != NULL) *suff = '\0';
                    922: #endif
                    923: 
                    924: #ifdef NO_MULTIPLE_DOTS
                    925:        suff = strrchr(ofname, '.');
                    926:        if (suff != NULL) {
                    927: #  ifdef MAX_EXT_CHARS
                    928:            /* On the Atari and some versions of MSDOS, name_too_long()
                    929:             * does not work correctly because of a bug in stat(). So we
                    930:             * must truncate here.
                    931:             */
                    932:            if (strlen(suff) > MAX_EXT_CHARS) {
                    933:                strcpy(suff + MAX_EXT_CHARS, do_lzw ? "Z" : "z");
                    934:                save_orig_name = 1;
                    935:                return 0;
                    936:            }
                    937: #  endif
                    938:            strcat(ofname, Z_SUFFIX);
                    939:            return 0;
                    940:        }
                    941: #endif
                    942:        strcat(ofname, do_lzw ? ".Z" : ".z");
                    943: 
                    944:     } /* decompress ? */
                    945:     return 0;
                    946: }
                    947: 
                    948: 
                    949: /* ========================================================================
                    950:  * Check the magic number of the input file and update ofname if an
                    951:  * original name was given and to_stdout is not set.
                    952:  * Return the compression method, -1 for error, -2 for warning.
                    953:  * Set inptr to the offset of the next byte to be processed.
                    954:  * This function may be called repeatedly for an input file consisting
                    955:  * of several contiguous gzip'ed members.
                    956:  * IN assertions: there is at least one remaining compressed member.
                    957:  *   If the member is a zip file, it must be the only one.
                    958:  */
                    959: local int get_method(in)
                    960:     int in;        /* input file descriptor */
                    961: {
                    962:     uch flags;
                    963:     char magic[2]; /* magic header */
                    964: 
                    965:     magic[0] = (char)get_byte();
                    966:     magic[1] = (char)get_byte();
                    967: 
                    968:     time_stamp = istat.st_mtime; /* may be modified later for some methods */
                    969:     method = -1;                 /* unknown yet */
                    970:     part_nb++;                   /* number of parts in gzip file */
                    971:     last_member = RECORD_IO;
                    972:     /* assume multiple members in gzip file except for record oriented I/O */
                    973: 
                    974:     if (memcmp(magic, GZIP_MAGIC, 2) == 0
                    975:         || memcmp(magic, OLD_GZIP_MAGIC, 2) == 0) {
                    976: 
                    977:        work = unzip;
                    978:        method = (int)get_byte();
                    979:        flags  = (uch)get_byte();
                    980:        text_mode = flags & ASCII_FLAG;
                    981: 
                    982:        if ((flags & ENCRYPTED) != 0) {
                    983:            fprintf(stderr, "%s is encrypted -- get newer version of gzip\n",
                    984:                    ifname);
                    985:            exit_code = ERROR;
                    986:            return -1;
                    987:        }
                    988:        if ((flags & CONTINUATION) != 0) {
                    989:            fprintf(stderr,
                    990:               "%s is a a multi-part gzip file -- get newer version of gzip\n",
                    991:                    ifname);
                    992:            exit_code = ERROR;
                    993:            if (force <= 1) return -1;
                    994:        }
                    995:        if ((flags & RESERVED) != 0) {
                    996:            fprintf(stderr, "%s has flags 0x%x -- get newer version of gzip\n",
                    997:                    ifname, flags);
                    998:            exit_code = ERROR;
                    999:            if (force <= 1) return -1;
                   1000:        }
                   1001:        time_stamp  = (ulg)get_byte();
                   1002:        time_stamp |= ((ulg)get_byte()) << 8;
                   1003:        time_stamp |= ((ulg)get_byte()) << 16;
                   1004:        time_stamp |= ((ulg)get_byte()) << 24;
                   1005: 
                   1006:        (void)get_byte();  /* Ignore extra flags for the moment */
                   1007:        (void)get_byte();  /* Ignore OS type for the moment */
                   1008: 
                   1009:        if ((flags & CONTINUATION) != 0) {
                   1010:            unsigned part = (unsigned)get_byte();
                   1011:            part |= ((unsigned)get_byte())<<8;
                   1012:            if (verbose) {
                   1013:                fprintf(stderr,"%s: part number %u\n",
                   1014:                        ifname, part);
                   1015:            }
                   1016:        }
                   1017:        if ((flags & EXTRA_FIELD) != 0) {
                   1018:            unsigned len = (unsigned)get_byte();
                   1019:            len |= ((unsigned)get_byte())<<8;
                   1020:            if (verbose) {
                   1021:                fprintf(stderr,"%s: extra field of %u bytes ignored\n",
                   1022:                        ifname, len);
                   1023:            }
                   1024:            while (len--) (void)get_byte();
                   1025:        }
                   1026: 
                   1027:        /* Get original file name if it was truncated */
                   1028:        if ((flags & ORIG_NAME) != 0) {
                   1029:            if (to_stdout || part_nb > 1) {
                   1030:                /* Discard the old name */
                   1031:                while (get_byte() != 0) /* null */ ;
                   1032:            } else {
                   1033:                /* Copy the base name. Keep a directory prefix intact. */
                   1034:                char *p = basename(ofname);
                   1035:                for (;;) {
                   1036:                    *p = (char)get_byte();
                   1037:                    if (*p++ == '\0') break;
                   1038:                    if (p >= ofname+sizeof(ofname)) {
                   1039:                        error("corrupted input -- file name too large");
                   1040:                    }
                   1041:                }
                   1042:            } /* to_stdout */
                   1043:        } /* orig_name */
                   1044: 
                   1045:        /* Discard file comment if any */
                   1046:        if ((flags & COMMENT) != 0) {
                   1047:            while (get_byte() != 0) /* null */ ;
                   1048:        }
                   1049: 
                   1050:     } else if (memcmp(magic, PKZIP_MAGIC, 2) == 0 && inptr == 2
                   1051:            && memcmp(inbuf, PKZIP_MAGIC, 4) == 0) {
                   1052:        /* To simplify the code, we support a zip file when alone only.
                   1053:          * We are thus guaranteed that the entire local header fits in inbuf.
                   1054:          */
                   1055:         inptr = 0;
                   1056:        work = unzip;
                   1057:        if (check_zipfile(in) == -1) return -1;
                   1058:        /* check_zipfile may get ofname from the local header */
                   1059:        last_member = 1;
                   1060: 
                   1061:     } else if (memcmp(magic, PACK_MAGIC, 2) == 0) {
                   1062:        work = unpack;
                   1063:        method = PACKED;
                   1064:     } else if (memcmp(magic, LZW_MAGIC, 2) == 0) {
                   1065:        work = unlzw;
                   1066:        method = COMPRESSED;
                   1067:        last_member = 1;
                   1068:     }
                   1069:     if (method >= 0) return method;
                   1070:     if (part_nb == 1) {
                   1071:        fprintf(stderr, "%s is not in gzip format\n", ifname);
                   1072:        exit_code = ERROR;
                   1073:        return -1;
                   1074:     } else {
                   1075:        WARN((stderr, "trailing garbage ignored in %s\n", ifname));
                   1076:        return -2;
                   1077:     }
                   1078: }
                   1079: 
                   1080: /* ========================================================================
                   1081:  * Return true if the two stat structures correspond to the same file.
                   1082:  */
                   1083: local int same_file(stat1, stat2)
                   1084:     struct stat *stat1;
                   1085:     struct stat *stat2;
                   1086: {
                   1087:     return stat1->st_mode  == stat2->st_mode
                   1088:        && stat1->st_ino   == stat2->st_ino
                   1089:        && stat1->st_dev   == stat2->st_dev
                   1090:        && stat1->st_uid   == stat2->st_uid
                   1091:        && stat1->st_gid   == stat2->st_gid
                   1092:        && stat1->st_size  == stat2->st_size
                   1093:        && stat1->st_atime == stat2->st_atime
                   1094:        && stat1->st_mtime == stat2->st_mtime
                   1095:        && stat1->st_ctime == stat2->st_ctime;
                   1096: }
                   1097: 
                   1098: /* ========================================================================
                   1099:  * Return true if a file name is ambigous because the operating system
                   1100:  * truncates file names.
                   1101:  */
                   1102: local int name_too_long(name, statb)
                   1103:     char *name;           /* file name to check */
                   1104:     struct stat *statb;   /* stat buf for this file name */
                   1105: {
                   1106:     int s = strlen(name);
                   1107:     char c = name[s-1];
                   1108:     struct stat        tstat; /* stat for truncated name */
                   1109:     int res;
                   1110: 
                   1111:     tstat = *statb;      /* Just in case OS does not fill all fields */
                   1112:     name[s-1] = '\0';
                   1113:     res = stat(name, &tstat) == 0 && same_file(statb, &tstat);
                   1114:     name[s-1] = c;
                   1115:     return res;
                   1116: }
                   1117: 
                   1118: /* ========================================================================
                   1119:  * If compressing to a file, check if ofname is not ambigous
                   1120:  * because the operating system truncates names. Otherwise, generate
                   1121:  * a new ofname and save the original name in the compressed file.
                   1122:  * If the compressed file already exists, ask for confirmation.
                   1123:  *    The check for name truncation is made dynamically, because different
                   1124:  * file systems on the same OS might use different truncation rules (on SVR4
                   1125:  * s5 truncates to 14 chars and ufs does not truncate).
                   1126:  *    This function returns -1 if the file must be skipped, and
                   1127:  * updates save_orig_name if necessary.
                   1128:  * IN assertions: save_orig_name is already set if ofname has been
                   1129:  * already truncated because of NO_MULTIPLE_DOTS. The input file has
                   1130:  * already been open and istat is set.
                   1131:  */
                   1132: local int check_ofname()
                   1133: {
                   1134:     int s = strlen(ofname);
                   1135:     struct stat        ostat; /* stat for ofname */
                   1136: 
                   1137:     if (stat(ofname, &ostat) != 0) return 0;
                   1138: 
                   1139:     /* Check for name truncation on existing file: */
                   1140: #ifdef NO_MULTIPLE_DOTS
                   1141:     if (!decompress && name_too_long(ofname, &ostat)) {
                   1142: #else
                   1143:     if (!decompress && s > 8 && name_too_long(ofname, &ostat)) {
                   1144: #endif
                   1145:        save_orig_name = 1;
                   1146: #ifdef NO_MULTIPLE_DOTS
                   1147:        strcpy(ofname+s-Z_LEN-1, Z_SUFFIX);  /* f.extz -> f.exz  */
                   1148: #else
                   1149:        strcpy(ofname+s-4, ".z"); /* 12345678901234.z -> 123456789012.z */
                   1150: #endif
                   1151:        if (stat(ofname, &ostat) != 0) return 0;
                   1152:     } /* !decompress && name_too_long */
                   1153: 
                   1154:     /* Check that the input and output files are different (could be
                   1155:      * the same by name truncation or links).
                   1156:      */
                   1157:     if (same_file(&istat, &ostat)) {
                   1158:        fprintf(stderr, "error: %s and %s are the same file\n",
                   1159:                ifname, ofname);
                   1160:        exit_code = ERROR;
                   1161:        return -1;
                   1162:     }
                   1163:     /* Ask permission to overwrite the existing file */
                   1164:     if (!force) {
                   1165:        char response[80];
                   1166:        strcpy(response,"n");
                   1167:        fprintf(stderr, "%s already exists;", ofname);
                   1168:        if (foreground && isatty(fileno(stdin))) {
                   1169:            fprintf(stderr, " do you wish to overwrite (y or n)? ");
                   1170:            fflush(stderr);
                   1171:            (void)read(fileno(stdin), response, sizeof(response));
                   1172:        }
                   1173:        if (tolow(*response) != 'y') {
                   1174:            fprintf(stderr, "\tnot overwritten\n");
                   1175:            if (exit_code == OK) exit_code = WARNING;
                   1176:            return -1;
                   1177:        }
                   1178:     }
                   1179:     (void) chmod(ofname, 0777);
                   1180:     if (unlink(ofname)) {
                   1181:        fprintf(stderr, "Can't remove old output file\n");
                   1182:        perror(ofname);
                   1183:        exit_code = ERROR;
                   1184:        return -1;
                   1185:     }
                   1186:     return 0;
                   1187: }
                   1188: 
                   1189: 
                   1190: /* ========================================================================
                   1191:  * Copy modes, times, ownership.
                   1192:  * IN assertion: to_stdout is false.
                   1193:  */
                   1194: local void copy_stat(ifstat)
                   1195:     struct stat *ifstat;
                   1196: {
                   1197: #ifndef NO_UTIME
                   1198:     struct utimbuf     timep;
                   1199: 
                   1200:     /* Copy the time stamp */
                   1201:     timep.actime = ifstat->st_atime;
                   1202:     timep.modtime = ifstat->st_mtime;
                   1203: 
                   1204:     if (decompress && timep.modtime != time_stamp && time_stamp != 0) {
                   1205:        timep.modtime = time_stamp;
                   1206:        if (verbose) {
                   1207:            fprintf(stderr, " (time stamp restored)\n");
                   1208:        }
                   1209:     }
                   1210:     if (utime(ofname, &timep)) {
                   1211:        if (!quiet) perror(ofname);
                   1212:        WARN((stderr, " utime error (ignored)\n"));
                   1213:     }
                   1214: #endif
                   1215:     /* Copy the protection modes */
                   1216:     if (chmod(ofname, ifstat->st_mode & 07777)) {
                   1217:        if (!quiet) perror(ofname);
                   1218:        WARN((stderr, " chmod error (ignored)\n"));
                   1219:     }
                   1220: #ifndef NO_CHOWN
                   1221:     chown(ofname, ifstat->st_uid, ifstat->st_gid);  /* Copy ownership */
                   1222: #endif
                   1223:     remove_ofname = 0;
                   1224:     /* It's now safe to remove the input file: */
                   1225:     (void) chmod(ifname, 0777);
                   1226:     if (unlink(ifname)) {
                   1227:        if (!quiet) perror(ifname);
                   1228:        WARN((stderr, " unlink error (ignored)\n"));
                   1229:     }
                   1230: }
                   1231: 
                   1232: #ifndef NO_DIR
                   1233: 
                   1234: /* ========================================================================
                   1235:  * Recurse through the given directory. This code is taken from ncompress.
                   1236:  */
                   1237: local void treat_dir(dir)
                   1238:     char *dir;
                   1239: {
                   1240:     dir_type *dp;
                   1241:     DIR      *dirp;
                   1242:     char     nbuf[MAX_PATH_LEN];
                   1243: 
                   1244:     dirp = opendir(dir);
                   1245:     
                   1246:     if (dirp == NULL) {
                   1247:        fprintf(stderr, "%s unreadable\n", dir);
                   1248:        exit_code = ERROR;
                   1249:        return ;
                   1250:     }
                   1251:     /*
                   1252:      ** WARNING: the following algorithm could occasionally cause
                   1253:      ** compress to produce error warnings of the form "<filename>.z
                   1254:      ** already has .z suffix - ignored". This occurs when the
                   1255:      ** .z output file is inserted into the directory below
                   1256:      ** readdir's current pointer.
                   1257:      ** These warnings are harmless but annoying, so they are suppressed
                   1258:      ** with option -r (except when -v is on). An alternative
                   1259:      ** to allowing this would be to store the entire directory
                   1260:      ** list in memory, then compress the entries in the stored
                   1261:      ** list. Given the depth-first recursive algorithm used here,
                   1262:      ** this could use up a tremendous amount of memory. I don't
                   1263:      ** think it's worth it. -- Dave Mack
                   1264:      ** (An other alternative might be two passes to avoid depth-first.)
                   1265:      */
                   1266:     
                   1267:     while ((dp = readdir(dirp)) != NULL) {
                   1268: 
                   1269:        if (strequ(dp->d_name,".") || strequ(dp->d_name,"..")) {
                   1270:            continue;
                   1271:        }
                   1272:        if (((int)strlen(dir) + NLENGTH(dp) + 1) < (MAX_PATH_LEN - 1)) {
                   1273:            strcpy(nbuf,dir);
                   1274:            if (strlen(dir) != 0) { /* dir = "" means current dir on Amiga */
                   1275: #ifdef OTHER_PATH_SEP
                   1276:                if (dir[strlen(dir)-1] != OTHER_PATH_SEP)
                   1277: #endif
                   1278:                strcat(nbuf,"/");
                   1279:            }
                   1280:            strcat(nbuf,dp->d_name);
                   1281:            treat_file(nbuf);
                   1282:        } else {
                   1283:            fprintf(stderr,"Pathname too long: %s/%s\n", dir, dp->d_name);
                   1284:            exit_code = ERROR;
                   1285:        }
                   1286:     }
                   1287:     closedir(dirp);
                   1288: }
                   1289: #endif /* ? NO_DIR */
                   1290: 
                   1291: /* ========================================================================
                   1292:  * Free all dynamically allocated variables and exit with the given code.
                   1293:  */
                   1294: local void do_exit(exitcode)
                   1295:     int exitcode;
                   1296: {
                   1297:     if (env != NULL)  free(env),  env  = NULL;
                   1298:     if (args != NULL) free(args), args = NULL;
                   1299:     FREE(inbuf);
                   1300:     FREE(outbuf);
                   1301:     FREE(d_buf);
                   1302:     FREE(window);
                   1303: #ifndef MAXSEG_64K
                   1304:     FREE(tab_prefix);
                   1305: #else
                   1306:     FREE(tab_prefix0);
                   1307:     FREE(tab_prefix1);
                   1308: #endif
                   1309:     exit(exitcode);
                   1310: }
                   1311: 
                   1312: /* ========================================================================
                   1313:  * Signal and error handler.
                   1314:  */
                   1315: RETSIGTYPE abort_gzip()
                   1316: {
                   1317:    if (remove_ofname) {
                   1318:        close(ofd);
                   1319:        unlink (ofname);
                   1320:    }
                   1321:    do_exit(ERROR);
                   1322: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.