]> git.cworth.org Git - gzip/blob - gzip.c
Imported Debian patch 1.3.5-10
[gzip] / gzip.c
1 /* gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
2  * Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
3  * Copyright (C) 1992-1993 Jean-loup Gailly
4  * The unzip code was written and put in the public domain by Mark Adler.
5  * Portions of the lzw code are derived from the public domain 'compress'
6  * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies,
7  * Ken Turkowski, Dave Mack and Peter Jannesen.
8  *
9  * See the license_msg below and the file COPYING for the software license.
10  * See the file algorithm.doc for the compression algorithms and file formats.
11  */
12
13 static char  *license_msg[] = {
14 "Copyright 2002 Free Software Foundation",
15 "Copyright 1992-1993 Jean-loup Gailly",
16 "This program comes with ABSOLUTELY NO WARRANTY.",
17 "You may redistribute copies of this program",
18 "under the terms of the GNU General Public License.",
19 "For more information about these matters, see the file named COPYING.",
20 0};
21
22 /* Compress files with zip algorithm and 'compress' interface.
23  * See usage() and help() functions below for all options.
24  * Outputs:
25  *        file.gz:   compressed file with same mode, owner, and utimes
26  *     or stdout with -c option or if stdin used as input.
27  * If the output file name had to be truncated, the original name is kept
28  * in the compressed file.
29  * On MSDOS, file.tmp -> file.tmz. On VMS, file.tmp -> file.tmp-gz.
30  *
31  * Using gz on MSDOS would create too many file name conflicts. For
32  * example, foo.txt -> foo.tgz (.tgz must be reserved as shorthand for
33  * tar.gz). Similarly, foo.dir and foo.doc would both be mapped to foo.dgz.
34  * I also considered 12345678.txt -> 12345txt.gz but this truncates the name
35  * too heavily. There is no ideal solution given the MSDOS 8+3 limitation. 
36  *
37  * For the meaning of all compilation flags, see comments in Makefile.in.
38  */
39
40 #ifdef RCSID
41 static char rcsid[] = "$Id: gzip.c,v 0.24 1993/06/24 10:52:07 jloup Exp $";
42 #endif
43
44 #include <config.h>
45 #include <ctype.h>
46 #include <sys/types.h>
47 #include <signal.h>
48 #include <sys/stat.h>
49 #include <errno.h>
50
51 #include "tailor.h"
52 #include "gzip.h"
53 #include "lzw.h"
54 #include "revision.h"
55 #include "getopt.h"
56
57                 /* configuration */
58
59 #ifdef HAVE_TIME_H
60 #  include <time.h>
61 #else
62 #  include <sys/time.h>
63 #endif
64
65 #ifdef HAVE_FCNTL_H
66 #  include <fcntl.h>
67 #endif
68
69 #ifdef HAVE_LIMITS_H
70 #  include <limits.h>
71 #endif
72
73 #ifdef HAVE_UNISTD_H
74 #  include <unistd.h>
75 #endif
76
77 #if defined STDC_HEADERS || defined HAVE_STDLIB_H
78 #  include <stdlib.h>
79 #else
80    extern int errno;
81 #endif
82
83 #ifdef HAVE_DIRENT_H
84 #  include <dirent.h>
85 #  define NAMLEN(direct) strlen((direct)->d_name)
86 #  define DIR_OPT "DIRENT"
87 #else
88 #  define dirent direct
89 #  define NAMLEN(direct) ((direct)->d_namlen)
90 #  ifdef HAVE_SYS_NDIR_H
91 #    include <sys/ndir.h>
92 #    define DIR_OPT "SYS_NDIR"
93 #  endif
94 #  ifdef HAVE_SYS_DIR_H
95 #    include <sys/dir.h>
96 #    define DIR_OPT "SYS_DIR"
97 #  endif
98 #  ifdef HAVE_NDIR_H
99 #    include <ndir.h>
100 #    define DIR_OPT "NDIR"
101 #  endif
102 #  ifndef DIR_OPT
103 #    define DIR_OPT "NO_DIR"
104 #  endif
105 #endif
106 #ifndef NO_DIR
107 # define NO_DIR 0
108 #endif
109
110 #ifdef CLOSEDIR_VOID
111 # define CLOSEDIR(d) (closedir(d), 0)
112 #else
113 # define CLOSEDIR(d) closedir(d)
114 #endif
115
116 #if !defined(HAVE_LSTAT) && !defined(lstat)
117 # define lstat(name, buf) stat(name, buf)
118 #endif
119
120 #ifdef HAVE_UTIME
121 #  ifdef HAVE_UTIME_H
122 #    include <utime.h>
123 #    define TIME_OPT "UTIME"
124 #  else
125 #    ifdef HAVE_SYS_UTIME_H
126 #      include <sys/utime.h>
127 #      define TIME_OPT "SYS_UTIME"
128 #    else
129        struct utimbuf {
130          time_t actime;
131          time_t modtime;
132        };
133 #      define TIME_OPT "STRUCT_UTIMBUF"
134 #    endif
135 #  endif
136 #else
137 #  define TIME_OPT "NO_UTIME"
138 #endif
139
140 #if !defined(S_ISDIR) && defined(S_IFDIR)
141 #  define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
142 #endif
143 #if !defined(S_ISREG) && defined(S_IFREG)
144 #  define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
145 #endif
146
147 typedef RETSIGTYPE (*sig_type) OF((int));
148
149 #ifndef O_BINARY
150 #  define  O_BINARY  0  /* creation mode for open() */
151 #endif
152
153 #ifndef O_CREAT
154    /* Pure BSD system? */
155 #  include <sys/file.h>
156 #  ifndef O_CREAT
157 #    define O_CREAT FCREAT
158 #  endif
159 #  ifndef O_EXCL
160 #    define O_EXCL FEXCL
161 #  endif
162 #endif
163
164 #ifndef S_IRUSR
165 #  define S_IRUSR 0400
166 #endif
167 #ifndef S_IWUSR
168 #  define S_IWUSR 0200
169 #endif
170 #define RW_USER (S_IRUSR | S_IWUSR)  /* creation mode for open() */
171
172 #ifndef MAX_PATH_LEN
173 #  define MAX_PATH_LEN   1024 /* max pathname length */
174 #endif
175
176 #ifndef SEEK_END
177 #  define SEEK_END 2
178 #endif
179
180 #ifndef CHAR_BIT
181 #  define CHAR_BIT 8
182 #endif
183
184 #ifdef off_t
185   off_t lseek OF((int fd, off_t offset, int whence));
186 #endif
187
188 #ifndef OFF_T_MIN
189 #define OFF_T_MIN (~ (off_t) 0 << (sizeof (off_t) * CHAR_BIT - 1))
190 #endif
191
192 #ifndef OFF_T_MAX
193 #define OFF_T_MAX (~ (off_t) 0 - OFF_T_MIN)
194 #endif
195
196 /* Separator for file name parts (see shorten_name()) */
197 #ifdef NO_MULTIPLE_DOTS
198 #  define PART_SEP "-"
199 #else
200 #  define PART_SEP "."
201 #endif
202
203                 /* global buffers */
204
205 DECLARE(uch, inbuf,  INBUFSIZ +INBUF_EXTRA);
206 DECLARE(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
207 DECLARE(ush, d_buf,  DIST_BUFSIZE);
208 DECLARE(uch, window, 2L*WSIZE);
209 #ifndef MAXSEG_64K
210     DECLARE(ush, tab_prefix, 1L<<BITS);
211 #else
212     DECLARE(ush, tab_prefix0, 1L<<(BITS-1));
213     DECLARE(ush, tab_prefix1, 1L<<(BITS-1));
214 #endif
215
216                 /* local variables */
217
218 int ascii = 0;        /* convert end-of-lines to local OS conventions */
219 int to_stdout = 0;    /* output to stdout (-c) */
220 int decompress = 0;   /* decompress (-d) */
221 int force = 0;        /* don't ask questions, compress links (-f) */
222 int no_name = -1;     /* don't save or restore the original file name */
223 int no_time = -1;     /* don't save or restore the original file time */
224 int recursive = 0;    /* recurse through directories (-r) */
225 int list = 0;         /* list the file contents (-l) */
226 int verbose = 0;      /* be verbose (-v) */
227 int quiet = 0;        /* be very quiet (-q) */
228 int do_lzw = 0;       /* generate output compatible with old compress (-Z) */
229 int test = 0;         /* test .gz file integrity */
230 int foreground;       /* set if program run in foreground */
231 char *progname;       /* program name */
232 int maxbits = BITS;   /* max bits per code for LZW */
233 int method = DEFLATED;/* compression method */
234 int level = 6;        /* compression level */
235 int exit_code = OK;   /* program exit code */
236 int save_orig_name;   /* set if original name must be saved */
237 int last_member;      /* set for .zip and .Z files */
238 int part_nb;          /* number of parts in .gz file */
239 time_t time_stamp;      /* original time stamp (modification time) */
240 off_t ifile_size;      /* input file size, -1 for devices (debug only) */
241 char *env;            /* contents of GZIP env variable */
242 char **args = NULL;   /* argv pointer if GZIP env variable defined */
243 char *z_suffix;       /* default suffix (can be set with --suffix) */
244 size_t z_len;         /* strlen(z_suffix) */
245
246 off_t bytes_in;             /* number of input bytes */
247 off_t bytes_out;            /* number of output bytes */
248 off_t total_in;             /* input bytes for all files */
249 off_t total_out;            /* output bytes for all files */
250 char ifname[MAX_PATH_LEN]; /* input file name */
251 char ofname[MAX_PATH_LEN]; /* output file name */
252 int  remove_ofname = 0;    /* remove output file on error */
253 struct stat istat;         /* status for input file */
254 int  ifd;                  /* input file descriptor */
255 int  ofd;                  /* output file descriptor */
256 unsigned insize;           /* valid bytes in inbuf */
257 unsigned inptr;            /* index of next byte to be processed in inbuf */
258 unsigned outcnt;           /* bytes in output buffer */
259 int rsync = 0;             /* make ryncable chunks */
260
261 struct option longopts[] =
262 {
263  /* { name  has_arg  *flag  val } */
264     {"ascii",      0, 0, 'a'}, /* ascii text mode */
265     {"to-stdout",  0, 0, 'c'}, /* write output on standard output */
266     {"stdout",     0, 0, 'c'}, /* write output on standard output */
267     {"decompress", 0, 0, 'd'}, /* decompress */
268     {"uncompress", 0, 0, 'd'}, /* decompress */
269  /* {"encrypt",    0, 0, 'e'},    encrypt */
270     {"force",      0, 0, 'f'}, /* force overwrite of output file */
271     {"help",       0, 0, 'h'}, /* give help */
272  /* {"pkzip",      0, 0, 'k'},    force output in pkzip format */
273     {"list",       0, 0, 'l'}, /* list .gz file contents */
274     {"license",    0, 0, 'L'}, /* display software license */
275     {"no-name",    0, 0, 'n'}, /* don't save or restore original name & time */
276     {"name",       0, 0, 'N'}, /* save or restore original name & time */
277     {"quiet",      0, 0, 'q'}, /* quiet mode */
278     {"silent",     0, 0, 'q'}, /* quiet mode */
279     {"recursive",  0, 0, 'r'}, /* recurse through directories */
280     {"suffix",     1, 0, 'S'}, /* use given suffix instead of .gz */
281     {"test",       0, 0, 't'}, /* test compressed file integrity */
282     {"no-time",    0, 0, 'T'}, /* don't save or restore the time stamp */
283     {"verbose",    0, 0, 'v'}, /* verbose mode */
284     {"version",    0, 0, 'V'}, /* display version number */
285     {"fast",       0, 0, '1'}, /* compress faster */
286     {"best",       0, 0, '9'}, /* compress better */
287     {"lzw",        0, 0, 'Z'}, /* make output compatible with old compress */
288     {"bits",       1, 0, 'b'}, /* max number of bits per code (implies -Z) */
289     {"rsyncable",  0, 0, 'R'}, /* make rsync-friendly archive */
290     { 0, 0, 0, 0 }
291 };
292
293 /* local functions */
294
295 local void usage        OF((void));
296 local void help         OF((void));
297 local void license      OF((void));
298 local void version      OF((void));
299 local int input_eof     OF((void));
300 local void treat_stdin  OF((void));
301 local void treat_file   OF((char *iname));
302 local int create_outfile OF((void));
303 local int  do_stat      OF((char *name, struct stat *sbuf));
304 local char *get_suffix  OF((char *name));
305 local int  get_istat    OF((char *iname, struct stat *sbuf));
306 local int  make_ofname  OF((void));
307 local int  same_file    OF((struct stat *stat1, struct stat *stat2));
308 local int name_too_long OF((char *name, struct stat *statb));
309 local void shorten_name  OF((char *name));
310 local int  get_method   OF((int in));
311 local void do_list      OF((int ifd, int method));
312 local int  check_ofname OF((void));
313 local void copy_stat    OF((struct stat *ifstat));
314 local void do_exit      OF((int exitcode));
315       int main          OF((int argc, char **argv));
316 int (*work) OF((int infile, int outfile)) = zip; /* function to call */
317
318 #if ! NO_DIR
319 local void treat_dir    OF((char *dir));
320 #endif
321 #ifdef HAVE_UTIME
322 local void reset_times  OF((char *name, struct stat *statb));
323 #endif
324
325 #define strequ(s1, s2) (strcmp((s1),(s2)) == 0)
326
327 /* ======================================================================== */
328 local void usage()
329 {
330     printf ("usage: %s [-%scdfhlLnN%stvV19] [-S suffix] [file ...]\n",
331             progname,
332             O_BINARY ? "a" : "", NO_DIR ? "" : "r");
333 }
334
335 /* ======================================================================== */
336 local void help()
337 {
338     static char  *help_msg[] = {
339 #if O_BINARY
340  " -a --ascii       ascii text; convert end-of-lines using local conventions",
341 #endif
342  " -c --stdout      write on standard output, keep original files unchanged",
343  " -d --decompress  decompress",
344 /* -e --encrypt     encrypt */
345  " -f --force       force overwrite of output file and compress links",
346  " -h --help        give this help",
347 /* -k --pkzip       force output in pkzip format */
348  " -l --list        list compressed file contents",
349  " -L --license     display software license",
350 #ifdef UNDOCUMENTED
351  " -m --no-time     do not save or restore the original modification time",
352  " -M --time        save or restore the original modification time",
353 #endif
354  " -n --no-name     do not save or restore the original name and time stamp",
355  " -N --name        save or restore the original name and time stamp",
356  " -q --quiet       suppress all warnings",
357 #if ! NO_DIR
358  " -r --recursive   operate recursively on directories",
359 #endif
360  " -S .suf  --suffix .suf     use suffix .suf on compressed files",
361  " -t --test        test compressed file integrity",
362  " -v --verbose     verbose mode",
363  " -V --version     display version number",
364  " -1 --fast        compress faster",
365  " -9 --best        compress better",
366 #ifdef LZW
367  " -Z --lzw         produce output compatible with old compress",
368  " -b --bits maxbits   max number of bits per code (implies -Z)",
369 #endif
370  "    --rsyncable   Make rsync-friendly archive",
371  " file...          files to (de)compress. If none given, use standard input.",
372  "Report bugs to <bug-gzip@gnu.org>.",
373   0};
374     char **p = help_msg;
375
376     printf ("%s %s\n(%s)\n", progname, VERSION, REVDATE);
377     usage();
378     while (*p) printf ("%s\n", *p++);
379 }
380
381 /* ======================================================================== */
382 local void license()
383 {
384     char **p = license_msg;
385
386     printf ("%s %s\n(%s)\n", progname, VERSION, REVDATE);
387     while (*p) printf ("%s\n", *p++);
388 }
389
390 /* ======================================================================== */
391 local void version()
392 {
393     license ();
394     printf ("Compilation options:\n%s %s ", DIR_OPT, TIME_OPT);
395 #ifdef STDC_HEADERS
396     printf ("STDC_HEADERS ");
397 #endif
398 #ifdef HAVE_UNISTD_H
399     printf ("HAVE_UNISTD_H ");
400 #endif
401 #ifdef HAVE_MEMORY_H
402     printf ("HAVE_MEMORY_H ");
403 #endif
404 #ifdef HAVE_STRING_H
405     printf ("HAVE_STRING_H ");
406 #endif
407 #ifdef HAVE_LSTAT
408     printf ("HAVE_LSTAT ");
409 #endif
410 #ifdef NO_MULTIPLE_DOTS
411     printf ("NO_MULTIPLE_DOTS ");
412 #endif
413 #ifdef HAVE_CHOWN
414     printf ("HAVE_CHOWN ");
415 #endif
416 #ifdef PROTO
417     printf ("PROTO ");
418 #endif
419 #ifdef ASMV
420     printf ("ASMV ");
421 #endif
422 #ifdef DEBUG
423     printf ("DEBUG ");
424 #endif
425 #ifdef DYN_ALLOC
426     printf ("DYN_ALLOC ");
427 #endif
428 #ifdef MAXSEG_64K
429     printf ("MAXSEG_64K");
430 #endif
431     printf ("\n");
432     printf ("Written by Jean-loup Gailly.\n");
433 }
434
435 local void progerror (string)
436     char *string;
437 {
438     int e = errno;
439     fprintf(stderr, "%s: ", progname);
440     errno = e;
441     perror(string);
442     exit_code = ERROR;
443 }
444
445 /* ======================================================================== */
446 int main (argc, argv)
447     int argc;
448     char **argv;
449 {
450     int file_count;     /* number of files to precess */
451     int proglen;        /* length of progname */
452     int optc;           /* current option */
453
454     EXPAND(argc, argv); /* wild card expansion if necessary */
455
456     progname = base_name (argv[0]);
457     proglen = strlen(progname);
458
459     /* Suppress .exe for MSDOS, OS/2 and VMS: */
460     if (proglen > 4 && strequ(progname+proglen-4, ".exe")) {
461         progname[proglen-4] = '\0';
462     }
463
464     /* Add options in GZIP environment variable if there is one */
465     env = add_envopt(&argc, &argv, OPTIONS_VAR);
466     if (env != NULL) args = argv;
467
468     foreground = signal(SIGINT, SIG_IGN) != SIG_IGN;
469     if (foreground) {
470         (void) signal (SIGINT, (sig_type)abort_gzip);
471     }
472 #ifdef SIGTERM
473     if (signal(SIGTERM, SIG_IGN) != SIG_IGN) {
474         (void) signal(SIGTERM, (sig_type)abort_gzip);
475     }
476 #endif
477 #ifdef SIGHUP
478     if (signal(SIGHUP, SIG_IGN) != SIG_IGN) {
479         (void) signal(SIGHUP,  (sig_type)abort_gzip);
480     }
481 #endif
482
483 #ifndef GNU_STANDARD
484     /* For compatibility with old compress, use program name as an option.
485      * If you compile with -DGNU_STANDARD, this program will behave as
486      * gzip even if it is invoked under the name gunzip or zcat.
487      *
488      * Systems which do not support links can still use -d or -dc.
489      * Ignore an .exe extension for MSDOS, OS/2 and VMS.
490      */
491     if (  strncmp(progname, "un",  2) == 0     /* ungzip, uncompress */
492        || strncmp(progname, "gun", 3) == 0) {  /* gunzip */
493         decompress = 1;
494     } else if (strequ(progname+1, "cat")       /* zcat, pcat, gcat */
495             || strequ(progname, "gzcat")) {    /* gzcat */
496         decompress = to_stdout = 1;
497     }
498 #endif
499
500     z_suffix = Z_SUFFIX;
501     z_len = strlen(z_suffix);
502
503     while ((optc = getopt_long (argc, argv, "ab:cdfhH?lLmMnNqrS:tvVZ123456789",
504                                 longopts, (int *)0)) != -1) {
505         switch (optc) {
506         case 'a':
507             ascii = 1; break;
508         case 'b':
509             maxbits = atoi(optarg);
510             for (; *optarg; optarg++)
511               if (! ('0' <= *optarg && *optarg <= '9'))
512                 {
513                   fprintf (stderr, "%s: -b operand is not an integer\n",
514                            progname);
515                   usage ();
516                   do_exit (ERROR);
517                 }
518             break;
519         case 'c':
520             to_stdout = 1; break;
521         case 'd':
522             decompress = 1; break;
523         case 'f':
524             force++; break;
525         case 'h': case 'H': case '?':
526             help(); do_exit(OK); break;
527         case 'l':
528             list = decompress = to_stdout = 1; break;
529         case 'L':
530             license(); do_exit(OK); break;
531         case 'm': /* undocumented, may change later */
532             no_time = 1; break;
533         case 'M': /* undocumented, may change later */
534             no_time = 0; break;
535         case 'n':
536             no_name = no_time = 1; break;
537         case 'N':
538             no_name = no_time = 0; break;
539         case 'q':
540             quiet = 1; verbose = 0; break;
541         case 'r':
542 #if NO_DIR
543             fprintf(stderr, "%s: -r not supported on this system\n", progname);
544             usage();
545             do_exit(ERROR); break;
546 #else
547             recursive = 1; break;
548 #endif
549         case 'R':
550             rsync = 1; break;
551
552         case 'S':
553 #ifdef NO_MULTIPLE_DOTS
554             if (*optarg == '.') optarg++;
555 #endif
556             z_len = strlen(optarg);
557             z_suffix = optarg;
558             break;
559         case 't':
560             test = decompress = to_stdout = 1;
561             break;
562         case 'v':
563             verbose++; quiet = 0; break;
564         case 'V':
565             version(); do_exit(OK); break;
566         case 'Z':
567 #ifdef LZW
568             do_lzw = 1; break;
569 #else
570             fprintf(stderr, "%s: -Z not supported in this version\n",
571                     progname);
572             usage();
573             do_exit(ERROR); break;
574 #endif
575         case '1':  case '2':  case '3':  case '4':
576         case '5':  case '6':  case '7':  case '8':  case '9':
577             level = optc - '0';
578             break;
579         default:
580             /* Error message already emitted by getopt_long. */
581             usage();
582             do_exit(ERROR);
583         }
584     } /* loop on all arguments */
585
586 #ifdef SIGPIPE
587     /* Ignore "Broken Pipe" message with --quiet */
588     if (quiet && signal (SIGPIPE, SIG_IGN) != SIG_IGN)
589       signal (SIGPIPE, (sig_type) abort_gzip);
590 #endif
591
592     /* By default, save name and timestamp on compression but do not
593      * restore them on decompression.
594      */
595     if (no_time < 0) no_time = decompress;
596     if (no_name < 0) no_name = decompress;
597
598     file_count = argc - optind;
599
600 #if O_BINARY
601 #else
602     if (ascii && !quiet) {
603         fprintf(stderr, "%s: option --ascii ignored on this system\n",
604                 progname);
605     }
606 #endif
607     if ((z_len == 0 && !decompress) || z_len > MAX_SUFFIX) {
608         fprintf(stderr, "%s: incorrect suffix '%s'\n",
609                 progname, z_suffix);
610         do_exit(ERROR);
611     }
612     if (do_lzw && !decompress) work = lzw;
613
614     /* Allocate all global buffers (for DYN_ALLOC option) */
615     ALLOC(uch, inbuf,  INBUFSIZ +INBUF_EXTRA);
616     ALLOC(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
617     ALLOC(ush, d_buf,  DIST_BUFSIZE);
618     ALLOC(uch, window, 2L*WSIZE);
619 #ifndef MAXSEG_64K
620     ALLOC(ush, tab_prefix, 1L<<BITS);
621 #else
622     ALLOC(ush, tab_prefix0, 1L<<(BITS-1));
623     ALLOC(ush, tab_prefix1, 1L<<(BITS-1));
624 #endif
625
626     /* And get to work */
627     if (file_count != 0) {
628         if (to_stdout && !test && !list && (!decompress || !ascii)) {
629             SET_BINARY_MODE(fileno(stdout));
630         }
631         while (optind < argc) {
632             treat_file(argv[optind++]);
633         }
634     } else {  /* Standard input */
635         treat_stdin();
636     }
637     if (list && !quiet && file_count > 1) {
638         do_list(-1, -1); /* print totals */
639     }
640     do_exit(exit_code);
641     return exit_code; /* just to avoid lint warning */
642 }
643
644 /* Return nonzero when at end of file on input.  */
645 local int
646 input_eof ()
647 {
648   if (!decompress || last_member)
649     return 1;
650
651   if (inptr == insize)
652     {
653       if (insize != INBUFSIZ || fill_inbuf (1) == EOF)
654         return 1;
655
656       /* Unget the char that fill_inbuf got.  */
657       inptr = 0;
658     }
659
660   return 0;
661 }
662
663 /* ========================================================================
664  * Compress or decompress stdin
665  */
666 local void treat_stdin()
667 {
668     if (!force && !list &&
669         isatty(fileno((FILE *)(decompress ? stdin : stdout)))) {
670         /* Do not send compressed data to the terminal or read it from
671          * the terminal. We get here when user invoked the program
672          * without parameters, so be helpful. According to the GNU standards:
673          *
674          *   If there is one behavior you think is most useful when the output
675          *   is to a terminal, and another that you think is most useful when
676          *   the output is a file or a pipe, then it is usually best to make
677          *   the default behavior the one that is useful with output to a
678          *   terminal, and have an option for the other behavior.
679          *
680          * Here we use the --force option to get the other behavior.
681          */
682         fprintf(stderr,
683     "%s: compressed data not %s a terminal. Use -f to force %scompression.\n",
684                 progname, decompress ? "read from" : "written to",
685                 decompress ? "de" : "");
686         fprintf(stderr,"For help, type: %s -h\n", progname);
687         do_exit(ERROR);
688     }
689
690     if (decompress || !ascii) {
691         SET_BINARY_MODE(fileno(stdin));
692     }
693     if (!test && !list && (!decompress || !ascii)) {
694         SET_BINARY_MODE(fileno(stdout));
695     }
696     strcpy(ifname, "stdin");
697     strcpy(ofname, "stdout");
698
699     /* Get the time stamp on the input file. */
700     time_stamp = 0; /* time unknown by default */
701
702 #ifndef NO_STDIN_FSTAT
703     if (list || !no_time) {
704         if (fstat(fileno(stdin), &istat) != 0) {
705             progerror("standard input");
706             do_exit(ERROR);
707         }
708 # ifdef NO_PIPE_TIMESTAMP
709         if (S_ISREG(istat.st_mode))
710 # endif
711             time_stamp = istat.st_mtime;
712 #endif /* NO_STDIN_FSTAT */
713     }
714     ifile_size = -1L; /* convention for unknown size */
715
716     clear_bufs(); /* clear input and output buffers */
717     to_stdout = 1;
718     part_nb = 0;
719
720     if (decompress) {
721         method = get_method(ifd);
722         if (method < 0) {
723             do_exit(exit_code); /* error message already emitted */
724         }
725     }
726     if (list) {
727         do_list(ifd, method);
728         return;
729     }
730
731     /* Actually do the compression/decompression. Loop over zipped members.
732      */
733     for (;;) {
734         if ((*work)(fileno(stdin), fileno(stdout)) != OK) return;
735
736         if (input_eof ())
737           break;
738
739         method = get_method(ifd);
740         if (method < 0) return; /* error message already emitted */
741         bytes_out = 0;            /* required for length check */
742     }
743
744     if (verbose) {
745         if (test) {
746             fprintf(stderr, " OK\n");
747
748         } else if (!decompress) {
749             display_ratio(bytes_in-(bytes_out-header_bytes), bytes_in, stderr);
750             fprintf(stderr, "\n");
751 #ifdef DISPLAY_STDIN_RATIO
752         } else {
753             display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out,stderr);
754             fprintf(stderr, "\n");
755 #endif
756         }
757     }
758 }
759
760 /* ========================================================================
761  * Compress or decompress the given file
762  */
763 local void treat_file(iname)
764     char *iname;
765 {
766     /* Accept "-" as synonym for stdin */
767     if (strequ(iname, "-")) {
768         int cflag = to_stdout;
769         treat_stdin();
770         to_stdout = cflag;
771         return;
772     }
773
774     /* Check if the input file is present, set ifname and istat: */
775     if (get_istat(iname, &istat) != OK) return;
776
777     /* If the input name is that of a directory, recurse or ignore: */
778     if (S_ISDIR(istat.st_mode)) {
779 #if ! NO_DIR
780         if (recursive) {
781             struct stat st;
782             st = istat;
783             treat_dir(iname);
784             /* Warning: ifname is now garbage */
785 #  ifndef NO_UTIME
786             reset_times (iname, &st);
787 #  endif
788         } else
789 #endif
790         WARN((stderr,"%s: %s is a directory -- ignored\n", progname, ifname));
791         return;
792     }
793     if (!S_ISREG(istat.st_mode)) {
794         WARN((stderr,
795               "%s: %s is not a directory or a regular file - ignored\n",
796               progname, ifname));
797         return;
798     }
799     if (istat.st_nlink > 1 && !to_stdout && !force) {
800         WARN((stderr, "%s: %s has %lu other link%c -- unchanged\n",
801               progname, ifname, (unsigned long) istat.st_nlink - 1,
802               istat.st_nlink > 2 ? 's' : ' '));
803         return;
804     }
805
806     ifile_size = istat.st_size;
807     time_stamp = no_time && !list ? 0 : istat.st_mtime;
808
809     /* Generate output file name. For -r and (-t or -l), skip files
810      * without a valid gzip suffix (check done in make_ofname).
811      */
812     if (to_stdout && !list && !test) {
813         strcpy(ofname, "stdout");
814
815     } else if (make_ofname() != OK) {
816         return;
817     }
818
819     /* Open the input file and determine compression method. The mode
820      * parameter is ignored but required by some systems (VMS) and forbidden
821      * on other systems (MacOS).
822      */
823     ifd = OPEN(ifname, ascii && !decompress ? O_RDONLY : O_RDONLY | O_BINARY,
824                RW_USER);
825     if (ifd == -1) {
826         progerror(ifname);
827         return;
828     }
829     clear_bufs(); /* clear input and output buffers */
830     part_nb = 0;
831
832     if (decompress) {
833         method = get_method(ifd); /* updates ofname if original given */
834         if (method < 0) {
835             close(ifd);
836             return;               /* error message already emitted */
837         }
838     }
839     if (list) {
840         do_list(ifd, method);
841         close(ifd);
842         return;
843     }
844
845     /* If compressing to a file, check if ofname is not ambiguous
846      * because the operating system truncates names. Otherwise, generate
847      * a new ofname and save the original name in the compressed file.
848      */
849     if (to_stdout) {
850         ofd = fileno(stdout);
851         /* keep remove_ofname as zero */
852     } else {
853         if (create_outfile() != OK) return;
854
855         if (!decompress && save_orig_name && !verbose && !quiet) {
856             fprintf(stderr, "%s: %s compressed to %s\n",
857                     progname, ifname, ofname);
858         }
859     }
860     /* Keep the name even if not truncated except with --no-name: */
861     if (!save_orig_name) save_orig_name = !no_name;
862
863     if (verbose) {
864         fprintf(stderr, "%s:\t", ifname);
865     }
866
867     /* Actually do the compression/decompression. Loop over zipped members.
868      */
869     for (;;) {
870         if ((*work)(ifd, ofd) != OK) {
871             method = -1; /* force cleanup */
872             break;
873         }
874
875         if (input_eof ())
876           break;
877
878         method = get_method(ifd);
879         if (method < 0) break;    /* error message already emitted */
880         bytes_out = 0;            /* required for length check */
881     }
882
883     close(ifd);
884     if (!to_stdout) {
885          /* Copy modes, times, ownership, and remove the input file */
886          copy_stat(&istat);
887          if (close(ofd))
888             write_error();
889     }
890     if (method == -1) {
891         if (!to_stdout) xunlink (ofname);
892         return;
893     }
894     /* Display statistics */
895     if(verbose) {
896         if (test) {
897             fprintf(stderr, " OK");
898         } else if (decompress) {
899             display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out,stderr);
900         } else {
901             display_ratio(bytes_in-(bytes_out-header_bytes), bytes_in, stderr);
902         }
903         if (!test && !to_stdout) {
904             fprintf(stderr, " -- replaced with %s", ofname);
905         }
906         fprintf(stderr, "\n");
907     }
908 }
909
910 /* ========================================================================
911  * Create the output file. Return OK or ERROR.
912  * Try several times if necessary to avoid truncating the z_suffix. For
913  * example, do not create a compressed file of name "1234567890123."
914  * Sets save_orig_name to true if the file name has been truncated.
915  * IN assertions: the input file has already been open (ifd is set) and
916  *   ofname has already been updated if there was an original name.
917  * OUT assertions: ifd and ofd are closed in case of error.
918  */
919 local int create_outfile()
920 {
921     struct stat ostat; /* stat for ofname */
922     int flags = O_WRONLY | O_CREAT | O_EXCL | O_BINARY;
923
924     if (ascii && decompress) {
925         flags &= ~O_BINARY; /* force ascii text mode */
926     }
927     for (;;) {
928         /* Make sure that ofname is not an existing file */
929         if (check_ofname() != OK) {
930             close(ifd);
931             return ERROR;
932         }
933         /* Create the output file */
934         remove_ofname = 1;
935         ofd = OPEN(ofname, flags, RW_USER);
936         if (ofd == -1) {
937             progerror(ofname);
938             close(ifd);
939             return ERROR;
940         }
941
942         /* Check for name truncation on new file (1234567890123.gz) */
943 #ifdef NO_FSTAT
944         if (stat(ofname, &ostat) != 0) {
945 #else
946         if (fstat(ofd, &ostat) != 0) {
947 #endif
948             progerror(ofname);
949             close(ifd); close(ofd);
950             xunlink (ofname);
951             return ERROR;
952         }
953         if (!name_too_long(ofname, &ostat)) return OK;
954
955         if (decompress) {
956             /* name might be too long if an original name was saved */
957             WARN((stderr, "%s: %s: warning, name truncated\n",
958                   progname, ofname));
959             return OK;
960         }
961         close(ofd);
962         xunlink (ofname);
963 #ifdef NO_MULTIPLE_DOTS
964         /* Should never happen, see check_ofname() */
965         fprintf(stderr, "%s: %s: name too long\n", progname, ofname);
966         do_exit(ERROR);
967 #endif
968         shorten_name(ofname);
969     }
970 }
971
972 /* ========================================================================
973  * Use lstat if available, except for -c or -f. Use stat otherwise.
974  * This allows links when not removing the original file.
975  */
976 local int do_stat(name, sbuf)
977     char *name;
978     struct stat *sbuf;
979 {
980     errno = 0;
981     if (!to_stdout && !force) {
982         return lstat(name, sbuf);
983     }
984     return stat(name, sbuf);
985 }
986
987 /* ========================================================================
988  * Return a pointer to the 'z' suffix of a file name, or NULL. For all
989  * systems, ".gz", ".z", ".Z", ".taz", ".tgz", "-gz", "-z" and "_z" are
990  * accepted suffixes, in addition to the value of the --suffix option.
991  * ".tgz" is a useful convention for tar.z files on systems limited
992  * to 3 characters extensions. On such systems, ".?z" and ".??z" are
993  * also accepted suffixes. For Unix, we do not want to accept any
994  * .??z suffix as indicating a compressed file; some people use .xyz
995  * to denote volume data.
996  *   On systems allowing multiple versions of the same file (such as VMS),
997  * this function removes any version suffix in the given name.
998  */
999 local char *get_suffix(name)
1000     char *name;
1001 {
1002     int nlen, slen;
1003     char suffix[MAX_SUFFIX+3]; /* last chars of name, forced to lower case */
1004     static char *known_suffixes[] =
1005        {NULL, ".gz", ".z", ".taz", ".tgz", "-gz", "-z", "_z",
1006 #ifdef MAX_EXT_CHARS
1007           "z",
1008 #endif
1009           NULL};
1010     char **suf = known_suffixes;
1011
1012     *suf = z_suffix;
1013     if (strequ(z_suffix, "z")) suf++; /* check long suffixes first */
1014
1015 #ifdef SUFFIX_SEP
1016     /* strip a version number from the file name */
1017     {
1018         char *v = strrchr(name, SUFFIX_SEP);
1019         if (v != NULL) *v = '\0';
1020     }
1021 #endif
1022     nlen = strlen(name);
1023     if (nlen <= MAX_SUFFIX+2) {
1024         strcpy(suffix, name);
1025     } else {
1026         strcpy(suffix, name+nlen-MAX_SUFFIX-2);
1027     }
1028     strlwr(suffix);
1029     slen = strlen(suffix);
1030     do {
1031        int s = strlen(*suf);
1032        if (slen > s && suffix[slen-s-1] != PATH_SEP
1033            && strequ(suffix + slen - s, *suf)) {
1034            return name+nlen-s;
1035        }
1036     } while (*++suf != NULL);
1037
1038     return NULL;
1039 }
1040
1041
1042 /* ========================================================================
1043  * Set ifname to the input file name (with a suffix appended if necessary)
1044  * and istat to its stats. For decompression, if no file exists with the
1045  * original name, try adding successively z_suffix, .gz, .z, -z and .Z.
1046  * For MSDOS, we try only z_suffix and z.
1047  * Return OK or ERROR.
1048  */
1049 local int get_istat(iname, sbuf)
1050     char *iname;
1051     struct stat *sbuf;
1052 {
1053     int ilen;  /* strlen(ifname) */
1054     int z_suffix_errno = 0;
1055     static char *suffixes[] = {NULL, ".gz", ".z", "-z", ".Z", NULL};
1056     char **suf = suffixes;
1057     char *s;
1058 #ifdef NO_MULTIPLE_DOTS
1059     char *dot; /* pointer to ifname extension, or NULL */
1060 #endif
1061
1062     *suf = z_suffix;
1063
1064     if (sizeof ifname - 1 <= strlen (iname))
1065         goto name_too_long;
1066
1067     strcpy(ifname, iname);
1068
1069     /* If input file exists, return OK. */
1070     if (do_stat(ifname, sbuf) == 0) return OK;
1071
1072     if (!decompress || errno != ENOENT) {
1073         progerror(ifname);
1074         return ERROR;
1075     }
1076     /* file.ext doesn't exist, try adding a suffix (after removing any
1077      * version number for VMS).
1078      */
1079     s = get_suffix(ifname);
1080     if (s != NULL) {
1081         progerror(ifname); /* ifname already has z suffix and does not exist */
1082         return ERROR;
1083     }
1084 #ifdef NO_MULTIPLE_DOTS
1085     dot = strrchr(ifname, '.');
1086     if (dot == NULL) {
1087         strcat(ifname, ".");
1088         dot = strrchr(ifname, '.');
1089     }
1090 #endif
1091     ilen = strlen(ifname);
1092     if (strequ(z_suffix, ".gz")) suf++;
1093
1094     /* Search for all suffixes */
1095     do {
1096         char *s0 = s = *suf;
1097         strcpy (ifname, iname);
1098 #ifdef NO_MULTIPLE_DOTS
1099         if (*s == '.') s++;
1100         if (*dot == '\0') strcpy (dot, ".");
1101 #endif
1102 #ifdef MAX_EXT_CHARS
1103         if (MAX_EXT_CHARS < strlen (s) + strlen (dot + 1))
1104           dot[MAX_EXT_CHARS + 1 - strlen (s)] = '\0';
1105 #endif
1106         if (sizeof ifname <= ilen + strlen (s))
1107           goto name_too_long;
1108         strcat(ifname, s);
1109         if (do_stat(ifname, sbuf) == 0) return OK;
1110         if (strequ (s0, z_suffix))
1111           z_suffix_errno = errno;
1112     } while (*++suf != NULL);
1113
1114     /* No suffix found, complain using z_suffix: */
1115     strcpy(ifname, iname);
1116 #ifdef NO_MULTIPLE_DOTS
1117     if (*dot == '\0') strcpy(dot, ".");
1118 #endif
1119 #ifdef MAX_EXT_CHARS
1120     if (MAX_EXT_CHARS < z_len + strlen (dot + 1))
1121       dot[MAX_EXT_CHARS + 1 - z_len] = '\0';
1122 #endif
1123     strcat(ifname, z_suffix);
1124     errno = z_suffix_errno;
1125     progerror(ifname);
1126     return ERROR;
1127       
1128  name_too_long:
1129     fprintf (stderr, "%s: %s: file name too long\n", progname, iname);
1130     exit_code = ERROR;
1131     return ERROR;
1132 }
1133
1134 /* ========================================================================
1135  * Generate ofname given ifname. Return OK, or WARNING if file must be skipped.
1136  * Sets save_orig_name to true if the file name has been truncated.
1137  */
1138 local int make_ofname()
1139 {
1140     char *suff;            /* ofname z suffix */
1141
1142     strcpy(ofname, ifname);
1143     /* strip a version number if any and get the gzip suffix if present: */
1144     suff = get_suffix(ofname);
1145
1146     if (decompress) {
1147         if (suff == NULL) {
1148             /* With -t or -l, try all files (even without .gz suffix)
1149              * except with -r (behave as with just -dr).
1150              */
1151             if (!recursive && (list || test)) return OK;
1152
1153             /* Avoid annoying messages with -r */
1154             if (verbose || (!recursive && !quiet)) {
1155                 WARN((stderr,"%s: %s: unknown suffix -- ignored\n",
1156                       progname, ifname));
1157             }
1158             return WARNING;
1159         }
1160         /* Make a special case for .tgz and .taz: */
1161         strlwr(suff);
1162         if (strequ(suff, ".tgz") || strequ(suff, ".taz")) {
1163             strcpy(suff, ".tar");
1164         } else {
1165             *suff = '\0'; /* strip the z suffix */
1166         }
1167         /* ofname might be changed later if infile contains an original name */
1168
1169     } else if (suff != NULL) {
1170         /* Avoid annoying messages with -r (see treat_dir()) */
1171         if (verbose || (!recursive && !quiet)) {
1172             WARN((stderr, "%s: %s already has %s suffix -- unchanged\n",
1173                   progname, ifname, suff));
1174         }
1175         return WARNING;
1176     } else {
1177         save_orig_name = 0;
1178
1179 #ifdef NO_MULTIPLE_DOTS
1180         suff = strrchr(ofname, '.');
1181         if (suff == NULL) {
1182             if (sizeof ofname <= strlen (ofname) + 1)
1183                 goto name_too_long;
1184             strcat(ofname, ".");
1185 #  ifdef MAX_EXT_CHARS
1186             if (strequ(z_suffix, "z")) {
1187                 if (sizeof ofname <= strlen (ofname) + 2)
1188                     goto name_too_long;
1189                 strcat(ofname, "gz"); /* enough room */
1190                 return OK;
1191             }
1192         /* On the Atari and some versions of MSDOS, name_too_long()
1193          * does not work correctly because of a bug in stat(). So we
1194          * must truncate here.
1195          */
1196         } else if (strlen(suff)-1 + z_len > MAX_SUFFIX) {
1197             suff[MAX_SUFFIX+1-z_len] = '\0';
1198             save_orig_name = 1;
1199 #  endif
1200         }
1201 #endif /* NO_MULTIPLE_DOTS */
1202         if (sizeof ofname <= strlen (ofname) + z_len)
1203             goto name_too_long;
1204         strcat(ofname, z_suffix);
1205
1206     } /* decompress ? */
1207     return OK;
1208
1209  name_too_long:
1210     WARN ((stderr, "%s: %s: file name too long\n", progname, ifname));
1211     return WARNING;
1212 }
1213
1214
1215 /* ========================================================================
1216  * Check the magic number of the input file and update ofname if an
1217  * original name was given and to_stdout is not set.
1218  * Return the compression method, -1 for error, -2 for warning.
1219  * Set inptr to the offset of the next byte to be processed.
1220  * Updates time_stamp if there is one and --no-time is not used.
1221  * This function may be called repeatedly for an input file consisting
1222  * of several contiguous gzip'ed members.
1223  * IN assertions: there is at least one remaining compressed member.
1224  *   If the member is a zip file, it must be the only one.
1225  */
1226 local int get_method(in)
1227     int in;        /* input file descriptor */
1228 {
1229     uch flags;     /* compression flags */
1230     char magic[2]; /* magic header */
1231     int imagic1;   /* like magic[1], but can represent EOF */
1232     ulg stamp;     /* time stamp */
1233
1234     /* If --force and --stdout, zcat == cat, so do not complain about
1235      * premature end of file: use try_byte instead of get_byte.
1236      */
1237     if (force && to_stdout) {
1238         magic[0] = (char)try_byte();
1239         imagic1 = try_byte ();
1240         magic[1] = (char) imagic1;
1241         /* If try_byte returned EOF, magic[1] == (char) EOF.  */
1242     } else {
1243         magic[0] = (char)get_byte();
1244         magic[1] = (char)get_byte();
1245         imagic1 = 0; /* avoid lint warning */
1246     }
1247     method = -1;                 /* unknown yet */
1248     part_nb++;                   /* number of parts in gzip file */
1249     header_bytes = 0;
1250     last_member = RECORD_IO;
1251     /* assume multiple members in gzip file except for record oriented I/O */
1252
1253     if (memcmp(magic, GZIP_MAGIC, 2) == 0
1254         || memcmp(magic, OLD_GZIP_MAGIC, 2) == 0) {
1255
1256         method = (int)get_byte();
1257         if (method != DEFLATED) {
1258             fprintf(stderr,
1259                     "%s: %s: unknown method %d -- not supported\n",
1260                     progname, ifname, method);
1261             exit_code = ERROR;
1262             return -1;
1263         }
1264         work = unzip;
1265         flags  = (uch)get_byte();
1266
1267         if ((flags & ENCRYPTED) != 0) {
1268             fprintf(stderr,
1269                     "%s: %s is encrypted -- not supported\n",
1270                     progname, ifname);
1271             exit_code = ERROR;
1272             return -1;
1273         }
1274         if ((flags & CONTINUATION) != 0) {
1275             fprintf(stderr,
1276                     "%s: %s is a a multi-part gzip file -- not supported\n",
1277                     progname, ifname);
1278             exit_code = ERROR;
1279             if (force <= 1) return -1;
1280         }
1281         if ((flags & RESERVED) != 0) {
1282             fprintf(stderr,
1283                     "%s: %s has flags 0x%x -- not supported\n",
1284                     progname, ifname, flags);
1285             exit_code = ERROR;
1286             if (force <= 1) return -1;
1287         }
1288         stamp  = (ulg)get_byte();
1289         stamp |= ((ulg)get_byte()) << 8;
1290         stamp |= ((ulg)get_byte()) << 16;
1291         stamp |= ((ulg)get_byte()) << 24;
1292         if (stamp != 0 && !no_time) time_stamp = stamp;
1293
1294         (void)get_byte();  /* Ignore extra flags for the moment */
1295         (void)get_byte();  /* Ignore OS type for the moment */
1296
1297         if ((flags & CONTINUATION) != 0) {
1298             unsigned part = (unsigned)get_byte();
1299             part |= ((unsigned)get_byte())<<8;
1300             if (verbose) {
1301                 fprintf(stderr,"%s: %s: part number %u\n",
1302                         progname, ifname, part);
1303             }
1304         }
1305         if ((flags & EXTRA_FIELD) != 0) {
1306             unsigned len = (unsigned)get_byte();
1307             len |= ((unsigned)get_byte())<<8;
1308             if (verbose) {
1309                 fprintf(stderr,"%s: %s: extra field of %u bytes ignored\n",
1310                         progname, ifname, len);
1311             }
1312             while (len--) (void)get_byte();
1313         }
1314
1315         /* Get original file name if it was truncated */
1316         if ((flags & ORIG_NAME) != 0) {
1317             if (no_name || (to_stdout && !list) || part_nb > 1) {
1318                 /* Discard the old name */
1319                 char c; /* dummy used for NeXTstep 3.0 cc optimizer bug */
1320                 do {c=get_byte();} while (c != 0);
1321             } else {
1322                 /* Copy the base name. Keep a directory prefix intact. */
1323                 char *p = base_name (ofname);
1324                 char *base = p;
1325                 char *base2;
1326                 for (;;) {
1327                     *p = (char)get_char();
1328                     if (*p++ == '\0') break;
1329                     if (p >= ofname+sizeof(ofname)) {
1330                         error("corrupted input -- file name too large");
1331                     }
1332                 }
1333                 base2 = base_name (base);
1334                 strcpy(base, base2);
1335                 /* If necessary, adapt the name to local OS conventions: */
1336                 if (!list) {
1337                    MAKE_LEGAL_NAME(base);
1338                    if (base) list=0; /* avoid warning about unused variable */
1339                 }
1340             } /* no_name || to_stdout */
1341         } /* ORIG_NAME */
1342
1343         /* Discard file comment if any */
1344         if ((flags & COMMENT) != 0) {
1345             while (get_char() != 0) /* null */ ;
1346         }
1347         if (part_nb == 1) {
1348             header_bytes = inptr + 2*sizeof(long); /* include crc and size */
1349         }
1350
1351     } else if (memcmp(magic, PKZIP_MAGIC, 2) == 0 && inptr == 2
1352             && memcmp((char*)inbuf, PKZIP_MAGIC, 4) == 0) {
1353         /* To simplify the code, we support a zip file when alone only.
1354          * We are thus guaranteed that the entire local header fits in inbuf.
1355          */
1356         inptr = 0;
1357         work = unzip;
1358         if (check_zipfile(in) != OK) return -1;
1359         /* check_zipfile may get ofname from the local header */
1360         last_member = 1;
1361
1362     } else if (memcmp(magic, PACK_MAGIC, 2) == 0) {
1363         work = unpack;
1364         method = PACKED;
1365
1366     } else if (memcmp(magic, LZW_MAGIC, 2) == 0) {
1367         work = unlzw;
1368         method = COMPRESSED;
1369         last_member = 1;
1370
1371     } else if (memcmp(magic, LZH_MAGIC, 2) == 0) {
1372         work = unlzh;
1373         method = LZHED;
1374         last_member = 1;
1375
1376     } else if (force && to_stdout && !list) { /* pass input unchanged */
1377         method = STORED;
1378         work = copy;
1379         inptr = 0;
1380         last_member = 1;
1381     }
1382     if (method >= 0) return method;
1383
1384     if (part_nb == 1) {
1385         fprintf(stderr, "\n%s: %s: not in gzip format\n", progname, ifname);
1386         exit_code = ERROR;
1387         return -1;
1388     } else {
1389         if (magic[0] == 0)
1390           {
1391             int inbyte;
1392             for (inbyte = imagic1;  inbyte == 0;  inbyte = try_byte ())
1393               continue;
1394             if (inbyte == EOF)
1395               {
1396                 if (verbose)
1397                   WARN ((stderr, "\n%s: %s: decompression OK, trailing zero bytes ignored\n",
1398                          progname, ifname));
1399                 return -3;
1400               }
1401           }
1402
1403         WARN((stderr, "\n%s: %s: decompression OK, trailing garbage ignored\n",
1404               progname, ifname));
1405         return -2;
1406     }
1407 }
1408
1409 /* ========================================================================
1410  * Display the characteristics of the compressed file.
1411  * If the given method is < 0, display the accumulated totals.
1412  * IN assertions: time_stamp, header_bytes and ifile_size are initialized.
1413  */
1414 local void do_list(ifd, method)
1415     int ifd;     /* input file descriptor */
1416     int method;  /* compression method */
1417 {
1418     ulg crc;  /* original crc */
1419     static int first_time = 1;
1420     static char* methods[MAX_METHODS] = {
1421         "store",  /* 0 */
1422         "compr",  /* 1 */
1423         "pack ",  /* 2 */
1424         "lzh  ",  /* 3 */
1425         "", "", "", "", /* 4 to 7 reserved */
1426         "defla"}; /* 8 */
1427     char *date;
1428     int positive_off_t_width = 1;
1429     off_t o;
1430
1431     for (o = OFF_T_MAX;  9 < o;  o /= 10) {
1432         positive_off_t_width++;
1433     }
1434
1435     if (first_time && method >= 0) {
1436         first_time = 0;
1437         if (verbose)  {
1438             printf("method  crc     date  time  ");
1439         }
1440         if (!quiet) {
1441             printf("%*.*s %*.*s  ratio uncompressed_name\n",
1442                    positive_off_t_width, positive_off_t_width, "compressed",
1443                    positive_off_t_width, positive_off_t_width, "uncompressed");
1444         }
1445     } else if (method < 0) {
1446         if (total_in <= 0 || total_out <= 0) return;
1447         if (verbose) {
1448             printf("                            ");
1449         }
1450         if (verbose || !quiet) {
1451             fprint_off(stdout, total_in, positive_off_t_width);
1452             printf(" ");
1453             fprint_off(stdout, total_out, positive_off_t_width);
1454             printf(" ");
1455         }
1456         display_ratio(total_out-(total_in-header_bytes), total_out, stdout);
1457         /* header_bytes is not meaningful but used to ensure the same
1458          * ratio if there is a single file.
1459          */
1460         printf(" (totals)\n");
1461         return;
1462     }
1463     crc = (ulg)~0; /* unknown */
1464     bytes_out = -1L;
1465     bytes_in = ifile_size;
1466
1467 #if RECORD_IO == 0
1468     if (method == DEFLATED && !last_member) {
1469         /* Get the crc and uncompressed size for gzip'ed (not zip'ed) files.
1470          * If the lseek fails, we could use read() to get to the end, but
1471          * --list is used to get quick results.
1472          * Use "gunzip < foo.gz | wc -c" to get the uncompressed size if
1473          * you are not concerned about speed.
1474          */
1475         bytes_in = lseek(ifd, (off_t)(-8), SEEK_END);
1476         if (bytes_in != -1L) {
1477             uch buf[8];
1478             bytes_in += 8L;
1479             if (read(ifd, (char*)buf, sizeof(buf)) != sizeof(buf)) {
1480                 read_error();
1481             }
1482             crc       = LG(buf);
1483             bytes_out = LG(buf+4);
1484         }
1485     }
1486 #endif /* RECORD_IO */
1487     date = ctime((time_t*)&time_stamp) + 4; /* skip the day of the week */
1488     date[12] = '\0';               /* suppress the 1/100sec and the year */
1489     if (verbose) {
1490         printf("%5s %08lx %11s ", methods[method], crc, date);
1491     }
1492     fprint_off(stdout, bytes_in, positive_off_t_width);
1493     printf(" ");
1494     fprint_off(stdout, bytes_out, positive_off_t_width);
1495     printf(" ");
1496     if (bytes_in  == -1L) {
1497         total_in = -1L;
1498         bytes_in = bytes_out = header_bytes = 0;
1499     } else if (total_in >= 0) {
1500         total_in  += bytes_in;
1501     }
1502     if (bytes_out == -1L) {
1503         total_out = -1L;
1504         bytes_in = bytes_out = header_bytes = 0;
1505     } else if (total_out >= 0) {
1506         total_out += bytes_out;
1507     }
1508     display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out, stdout);
1509     printf(" %s\n", ofname);
1510 }
1511
1512 /* ========================================================================
1513  * Return true if the two stat structures correspond to the same file.
1514  */
1515 local int same_file(stat1, stat2)
1516     struct stat *stat1;
1517     struct stat *stat2;
1518 {
1519     return stat1->st_ino   == stat2->st_ino
1520         && stat1->st_dev   == stat2->st_dev
1521 #ifdef NO_ST_INO
1522         /* Can't rely on st_ino and st_dev, use other fields: */
1523         && stat1->st_mode  == stat2->st_mode
1524         && stat1->st_uid   == stat2->st_uid
1525         && stat1->st_gid   == stat2->st_gid
1526         && stat1->st_size  == stat2->st_size
1527         && stat1->st_atime == stat2->st_atime
1528         && stat1->st_mtime == stat2->st_mtime
1529         && stat1->st_ctime == stat2->st_ctime
1530 #endif
1531             ;
1532 }
1533
1534 /* ========================================================================
1535  * Return true if a file name is ambiguous because the operating system
1536  * truncates file names.
1537  */
1538 local int name_too_long(name, statb)
1539     char *name;           /* file name to check */
1540     struct stat *statb;   /* stat buf for this file name */
1541 {
1542     int s = strlen(name);
1543     char c = name[s-1];
1544     struct stat tstat; /* stat for truncated name */
1545     int res;
1546
1547     tstat = *statb;      /* Just in case OS does not fill all fields */
1548     name[s-1] = '\0';
1549     res = lstat(name, &tstat) == 0 && same_file(statb, &tstat);
1550     name[s-1] = c;
1551     Trace((stderr, " too_long(%s) => %d\n", name, res));
1552     return res;
1553 }
1554
1555 /* ========================================================================
1556  * Shorten the given name by one character, or replace a .tar extension
1557  * with .tgz. Truncate the last part of the name which is longer than
1558  * MIN_PART characters: 1234.678.012.gz -> 123.678.012.gz. If the name
1559  * has only parts shorter than MIN_PART truncate the longest part.
1560  * For decompression, just remove the last character of the name.
1561  *
1562  * IN assertion: for compression, the suffix of the given name is z_suffix.
1563  */
1564 local void shorten_name(name)
1565     char *name;
1566 {
1567     int len;                 /* length of name without z_suffix */
1568     char *trunc = NULL;      /* character to be truncated */
1569     int plen;                /* current part length */
1570     int min_part = MIN_PART; /* current minimum part length */
1571     char *p;
1572
1573     len = strlen(name);
1574     if (decompress) {
1575         if (len <= 1) error("name too short");
1576         name[len-1] = '\0';
1577         return;
1578     }
1579     p = get_suffix(name);
1580     if (p == NULL) error("can't recover suffix\n");
1581     *p = '\0';
1582     save_orig_name = 1;
1583
1584     /* compress 1234567890.tar to 1234567890.tgz */
1585     if (len > 4 && strequ(p-4, ".tar")) {
1586         strcpy(p-4, ".tgz");
1587         return;
1588     }
1589     /* Try keeping short extensions intact:
1590      * 1234.678.012.gz -> 123.678.012.gz
1591      */
1592     do {
1593         p = strrchr(name, PATH_SEP);
1594         p = p ? p+1 : name;
1595         while (*p) {
1596             plen = strcspn(p, PART_SEP);
1597             p += plen;
1598             if (plen > min_part) trunc = p-1;
1599             if (*p) p++;
1600         }
1601     } while (trunc == NULL && --min_part != 0);
1602
1603     if (trunc != NULL) {
1604         do {
1605             trunc[0] = trunc[1];
1606         } while (*trunc++);
1607         trunc--;
1608     } else {
1609         trunc = strrchr(name, PART_SEP[0]);
1610         if (trunc == NULL) error("internal error in shorten_name");
1611         if (trunc[1] == '\0') trunc--; /* force truncation */
1612     }
1613     strcpy(trunc, z_suffix);
1614 }
1615
1616 /* ========================================================================
1617  * If compressing to a file, check if ofname is not ambiguous
1618  * because the operating system truncates names. Otherwise, generate
1619  * a new ofname and save the original name in the compressed file.
1620  * If the compressed file already exists, ask for confirmation.
1621  *    The check for name truncation is made dynamically, because different
1622  * file systems on the same OS might use different truncation rules (on SVR4
1623  * s5 truncates to 14 chars and ufs does not truncate).
1624  *    This function returns -1 if the file must be skipped, and
1625  * updates save_orig_name if necessary.
1626  * IN assertions: save_orig_name is already set if ofname has been
1627  * already truncated because of NO_MULTIPLE_DOTS. The input file has
1628  * already been open and istat is set.
1629  */
1630 local int check_ofname()
1631 {
1632     struct stat ostat; /* stat for ofname */
1633
1634 #ifdef ENAMETOOLONG
1635     /* Check for strictly conforming Posix systems (which return ENAMETOOLONG
1636      * instead of silently truncating filenames).
1637      */
1638     errno = 0;
1639     while (lstat(ofname, &ostat) != 0) {
1640         if (errno != ENAMETOOLONG) return 0; /* ofname does not exist */
1641         shorten_name(ofname);
1642     }
1643 #else
1644     if (lstat(ofname, &ostat) != 0) return 0;
1645 #endif
1646     /* Check for name truncation on existing file. Do this even on systems
1647      * defining ENAMETOOLONG, because on most systems the strict Posix
1648      * behavior is disabled by default (silent name truncation allowed).
1649      */
1650     if (!decompress && name_too_long(ofname, &ostat)) {
1651         shorten_name(ofname);
1652         if (lstat(ofname, &ostat) != 0) return 0;
1653     }
1654
1655     /* Check that the input and output files are different (could be
1656      * the same by name truncation or links).
1657      */
1658     if (same_file(&istat, &ostat)) {
1659         if (strequ(ifname, ofname)) {
1660             fprintf(stderr, "%s: %s: cannot %scompress onto itself\n",
1661                     progname, ifname, decompress ? "de" : "");
1662         } else {
1663             fprintf(stderr, "%s: %s and %s are the same file\n",
1664                     progname, ifname, ofname);
1665         }
1666         exit_code = ERROR;
1667         return ERROR;
1668     }
1669     /* Ask permission to overwrite the existing file */
1670     if (!force) {
1671         int ok = 0;
1672         fprintf(stderr, "%s: %s already exists;", progname, ofname);
1673         if (foreground && isatty(fileno(stdin))) {
1674             fprintf(stderr, " do you wish to overwrite (y or n)? ");
1675             fflush(stderr);
1676             ok = yesno();
1677         }
1678         if (!ok) {
1679             fprintf(stderr, "\tnot overwritten\n");
1680             if (exit_code == OK) exit_code = WARNING;
1681             return ERROR;
1682         }
1683     }
1684     if (xunlink (ofname)) {
1685         progerror(ofname);
1686         return ERROR;
1687     }
1688     return OK;
1689 }
1690
1691
1692 #ifndef NO_UTIME
1693 /* ========================================================================
1694  * Set the access and modification times from the given stat buffer.
1695  */
1696 local void reset_times (name, statb)
1697     char *name;
1698     struct stat *statb;
1699 {
1700     struct utimbuf      timep;
1701
1702     /* Copy the time stamp */
1703     timep.actime  = statb->st_atime;
1704     timep.modtime = statb->st_mtime;
1705
1706     /* Some systems (at least OS/2) do not support utime on directories */
1707     if (utime(name, &timep) && !S_ISDIR(statb->st_mode)) {
1708         int e = errno;
1709         WARN((stderr, "%s: ", progname));
1710         if (!quiet) {
1711             errno = e;
1712             perror(ofname);
1713         }
1714     }
1715 }
1716 #endif
1717
1718
1719 /* ========================================================================
1720  * Copy modes, times, ownership from input file to output file.
1721  * IN assertion: to_stdout is false.
1722  */
1723 local void copy_stat(ifstat)
1724     struct stat *ifstat;
1725 {
1726 #ifndef NO_UTIME
1727     if (decompress && time_stamp != 0 && ifstat->st_mtime != time_stamp) {
1728         ifstat->st_mtime = time_stamp;
1729         if (verbose > 1) {
1730             fprintf(stderr, "%s: time stamp restored\n", ofname);
1731         }
1732     }
1733     reset_times(ofname, ifstat);
1734 #endif
1735     /* Copy the protection modes */
1736     if (fchmod(ofd, ifstat->st_mode & 07777)) {
1737         int e = errno;
1738         WARN((stderr, "%s: ", progname));
1739         if (!quiet) {
1740             errno = e;
1741             perror(ofname);
1742         }
1743     }
1744 #ifndef NO_CHOWN
1745     fchown(ofd, ifstat->st_uid, ifstat->st_gid);  /* Copy ownership */
1746 #endif
1747     remove_ofname = 0;
1748     /* It's now safe to remove the input file: */
1749     if (xunlink (ifname)) {
1750         int e = errno;
1751         WARN((stderr, "%s: ", progname));
1752         if (!quiet) {
1753             errno = e;
1754             perror(ifname);
1755         }
1756     }
1757 }
1758
1759 #if ! NO_DIR
1760
1761 /* ========================================================================
1762  * Recurse through the given directory. This code is taken from ncompress.
1763  */
1764 local void treat_dir(dir)
1765     char *dir;
1766 {
1767     struct dirent *dp;
1768     DIR      *dirp;
1769     char     nbuf[MAX_PATH_LEN];
1770     int      len;
1771
1772     dirp = opendir(dir);
1773     
1774     if (dirp == NULL) {
1775         progerror(dir);
1776         return ;
1777     }
1778     /*
1779      ** WARNING: the following algorithm could occasionally cause
1780      ** compress to produce error warnings of the form "<filename>.gz
1781      ** already has .gz suffix - ignored". This occurs when the
1782      ** .gz output file is inserted into the directory below
1783      ** readdir's current pointer.
1784      ** These warnings are harmless but annoying, so they are suppressed
1785      ** with option -r (except when -v is on). An alternative
1786      ** to allowing this would be to store the entire directory
1787      ** list in memory, then compress the entries in the stored
1788      ** list. Given the depth-first recursive algorithm used here,
1789      ** this could use up a tremendous amount of memory. I don't
1790      ** think it's worth it. -- Dave Mack
1791      ** (An other alternative might be two passes to avoid depth-first.)
1792      */
1793     
1794     while ((errno = 0, dp = readdir(dirp)) != NULL) {
1795
1796         if (strequ(dp->d_name,".") || strequ(dp->d_name,"..")) {
1797             continue;
1798         }
1799         len = strlen(dir);
1800         if (len + NAMLEN(dp) + 1 < MAX_PATH_LEN - 1) {
1801             strcpy(nbuf,dir);
1802             if (len != 0 /* dir = "" means current dir on Amiga */
1803 #ifdef PATH_SEP2
1804                 && dir[len-1] != PATH_SEP2
1805 #endif
1806 #ifdef PATH_SEP3
1807                 && dir[len-1] != PATH_SEP3
1808 #endif
1809             ) {
1810                 nbuf[len++] = PATH_SEP;
1811             }
1812             strcpy(nbuf+len, dp->d_name);
1813             treat_file(nbuf);
1814         } else {
1815             fprintf(stderr,"%s: %s/%s: pathname too long\n",
1816                     progname, dir, dp->d_name);
1817             exit_code = ERROR;
1818         }
1819     }
1820     if (errno != 0)
1821         progerror(dir);
1822     if (CLOSEDIR(dirp) != 0)
1823         progerror(dir);
1824 }
1825 #endif /* ! NO_DIR */
1826
1827 /* ========================================================================
1828  * Free all dynamically allocated variables and exit with the given code.
1829  */
1830 local void do_exit(exitcode)
1831     int exitcode;
1832 {
1833     static int in_exit = 0;
1834
1835     if (in_exit) exit(exitcode);
1836     in_exit = 1;
1837     if (env != NULL)  free(env),  env  = NULL;
1838     if (args != NULL) free((char*)args), args = NULL;
1839     FREE(inbuf);
1840     FREE(outbuf);
1841     FREE(d_buf);
1842     FREE(window);
1843 #ifndef MAXSEG_64K
1844     FREE(tab_prefix);
1845 #else
1846     FREE(tab_prefix0);
1847     FREE(tab_prefix1);
1848 #endif
1849     exit(exitcode);
1850 }
1851
1852 /* ========================================================================
1853  * Signal and error handler.
1854  */
1855 RETSIGTYPE abort_gzip()
1856 {
1857    if (remove_ofname) {
1858        close(ofd);
1859        xunlink (ofname);
1860    }
1861    do_exit(ERROR);
1862 }