Annotation of coherent/g/usr/bin/gzip/gzip.c, revision 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.