]> git.cworth.org Git - gzip/blob - gzip.c
Imported Debian patch 1.3.5-14
[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_signal);
471     }
472 #ifdef SIGTERM
473     if (signal(SIGTERM, SIG_IGN) != SIG_IGN) {
474         (void) signal(SIGTERM, (sig_type)abort_gzip_signal);
475     }
476 #endif
477 #ifdef SIGHUP
478     if (signal(SIGHUP, SIG_IGN) != SIG_IGN) {
479         (void) signal(SIGHUP,  (sig_type)abort_gzip_signal);
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_signal);
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, and ownership */
886          copy_stat(&istat);
887          if (close(ofd))
888             write_error();
889          remove_ofname = 0;
890
891          /* It's now safe to remove the input file: */
892          if (xunlink (ifname)) {
893            int e = errno;
894            WARN((stderr, "%s: ", progname));
895            if (!quiet) {
896              errno = e;
897              perror(ifname);
898            }
899          }
900     }
901     if (method == -1) {
902         if (!to_stdout) xunlink (ofname);
903         return;
904     }
905     /* Display statistics */
906     if(verbose) {
907         if (test) {
908             fprintf(stderr, " OK");
909         } else if (decompress) {
910             display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out,stderr);
911         } else {
912             display_ratio(bytes_in-(bytes_out-header_bytes), bytes_in, stderr);
913         }
914         if (!test && !to_stdout) {
915             fprintf(stderr, " -- replaced with %s", ofname);
916         }
917         fprintf(stderr, "\n");
918     }
919 }
920
921 /* ========================================================================
922  * Create the output file. Return OK or ERROR.
923  * Try several times if necessary to avoid truncating the z_suffix. For
924  * example, do not create a compressed file of name "1234567890123."
925  * Sets save_orig_name to true if the file name has been truncated.
926  * IN assertions: the input file has already been open (ifd is set) and
927  *   ofname has already been updated if there was an original name.
928  * OUT assertions: ifd and ofd are closed in case of error.
929  */
930 local int create_outfile()
931 {
932     struct stat ostat; /* stat for ofname */
933     int flags = O_WRONLY | O_CREAT | O_EXCL | O_BINARY;
934
935     if (ascii && decompress) {
936         flags &= ~O_BINARY; /* force ascii text mode */
937     }
938     for (;;) {
939         /* Make sure that ofname is not an existing file */
940         if (check_ofname() != OK) {
941             close(ifd);
942             return ERROR;
943         }
944         /* Create the output file */
945         remove_ofname = 1;
946         ofd = OPEN(ofname, flags, RW_USER);
947         if (ofd == -1) {
948             progerror(ofname);
949             close(ifd);
950             return ERROR;
951         }
952
953         /* Check for name truncation on new file (1234567890123.gz) */
954 #ifdef NO_FSTAT
955         if (stat(ofname, &ostat) != 0) {
956 #else
957         if (fstat(ofd, &ostat) != 0) {
958 #endif
959             progerror(ofname);
960             close(ifd); close(ofd);
961             xunlink (ofname);
962             return ERROR;
963         }
964         if (!name_too_long(ofname, &ostat)) return OK;
965
966         if (decompress) {
967             /* name might be too long if an original name was saved */
968             WARN((stderr, "%s: %s: warning, name truncated\n",
969                   progname, ofname));
970             return OK;
971         }
972         close(ofd);
973         xunlink (ofname);
974 #ifdef NO_MULTIPLE_DOTS
975         /* Should never happen, see check_ofname() */
976         fprintf(stderr, "%s: %s: name too long\n", progname, ofname);
977         do_exit(ERROR);
978 #endif
979         shorten_name(ofname);
980     }
981 }
982
983 /* ========================================================================
984  * Use lstat if available, except for -c or -f. Use stat otherwise.
985  * This allows links when not removing the original file.
986  */
987 local int do_stat(name, sbuf)
988     char *name;
989     struct stat *sbuf;
990 {
991     errno = 0;
992     if (!to_stdout && !force) {
993         return lstat(name, sbuf);
994     }
995     return stat(name, sbuf);
996 }
997
998 /* ========================================================================
999  * Return a pointer to the 'z' suffix of a file name, or NULL. For all
1000  * systems, ".gz", ".z", ".Z", ".taz", ".tgz", "-gz", "-z" and "_z" are
1001  * accepted suffixes, in addition to the value of the --suffix option.
1002  * ".tgz" is a useful convention for tar.z files on systems limited
1003  * to 3 characters extensions. On such systems, ".?z" and ".??z" are
1004  * also accepted suffixes. For Unix, we do not want to accept any
1005  * .??z suffix as indicating a compressed file; some people use .xyz
1006  * to denote volume data.
1007  *   On systems allowing multiple versions of the same file (such as VMS),
1008  * this function removes any version suffix in the given name.
1009  */
1010 local char *get_suffix(name)
1011     char *name;
1012 {
1013     int nlen, slen;
1014     char suffix[MAX_SUFFIX+3]; /* last chars of name, forced to lower case */
1015     static char *known_suffixes[] =
1016        {NULL, ".gz", ".z", ".taz", ".tgz", "-gz", "-z", "_z",
1017 #ifdef MAX_EXT_CHARS
1018           "z",
1019 #endif
1020           NULL};
1021     char **suf = known_suffixes;
1022
1023     *suf = z_suffix;
1024     if (strequ(z_suffix, "z")) suf++; /* check long suffixes first */
1025
1026 #ifdef SUFFIX_SEP
1027     /* strip a version number from the file name */
1028     {
1029         char *v = strrchr(name, SUFFIX_SEP);
1030         if (v != NULL) *v = '\0';
1031     }
1032 #endif
1033     nlen = strlen(name);
1034     if (nlen <= MAX_SUFFIX+2) {
1035         strcpy(suffix, name);
1036     } else {
1037         strcpy(suffix, name+nlen-MAX_SUFFIX-2);
1038     }
1039     strlwr(suffix);
1040     slen = strlen(suffix);
1041     do {
1042        int s = strlen(*suf);
1043        if (slen > s && suffix[slen-s-1] != PATH_SEP
1044            && strequ(suffix + slen - s, *suf)) {
1045            return name+nlen-s;
1046        }
1047     } while (*++suf != NULL);
1048
1049     return NULL;
1050 }
1051
1052
1053 /* ========================================================================
1054  * Set ifname to the input file name (with a suffix appended if necessary)
1055  * and istat to its stats. For decompression, if no file exists with the
1056  * original name, try adding successively z_suffix, .gz, .z, -z and .Z.
1057  * For MSDOS, we try only z_suffix and z.
1058  * Return OK or ERROR.
1059  */
1060 local int get_istat(iname, sbuf)
1061     char *iname;
1062     struct stat *sbuf;
1063 {
1064     int ilen;  /* strlen(ifname) */
1065     int z_suffix_errno = 0;
1066     static char *suffixes[] = {NULL, ".gz", ".z", "-z", ".Z", NULL};
1067     char **suf = suffixes;
1068     char *s;
1069 #ifdef NO_MULTIPLE_DOTS
1070     char *dot; /* pointer to ifname extension, or NULL */
1071 #endif
1072
1073     *suf = z_suffix;
1074
1075     if (sizeof ifname - 1 <= strlen (iname))
1076         goto name_too_long;
1077
1078     strcpy(ifname, iname);
1079
1080     /* If input file exists, return OK. */
1081     if (do_stat(ifname, sbuf) == 0) return OK;
1082
1083     if (!decompress || errno != ENOENT) {
1084         progerror(ifname);
1085         return ERROR;
1086     }
1087     /* file.ext doesn't exist, try adding a suffix (after removing any
1088      * version number for VMS).
1089      */
1090     s = get_suffix(ifname);
1091     if (s != NULL) {
1092         progerror(ifname); /* ifname already has z suffix and does not exist */
1093         return ERROR;
1094     }
1095 #ifdef NO_MULTIPLE_DOTS
1096     dot = strrchr(ifname, '.');
1097     if (dot == NULL) {
1098         strcat(ifname, ".");
1099         dot = strrchr(ifname, '.');
1100     }
1101 #endif
1102     ilen = strlen(ifname);
1103     if (strequ(z_suffix, ".gz")) suf++;
1104
1105     /* Search for all suffixes */
1106     do {
1107         char *s0 = s = *suf;
1108         strcpy (ifname, iname);
1109 #ifdef NO_MULTIPLE_DOTS
1110         if (*s == '.') s++;
1111         if (*dot == '\0') strcpy (dot, ".");
1112 #endif
1113 #ifdef MAX_EXT_CHARS
1114         if (MAX_EXT_CHARS < strlen (s) + strlen (dot + 1))
1115           dot[MAX_EXT_CHARS + 1 - strlen (s)] = '\0';
1116 #endif
1117         if (sizeof ifname <= ilen + strlen (s))
1118           goto name_too_long;
1119         strcat(ifname, s);
1120         if (do_stat(ifname, sbuf) == 0) return OK;
1121         if (strequ (s0, z_suffix))
1122           z_suffix_errno = errno;
1123     } while (*++suf != NULL);
1124
1125     /* No suffix found, complain using z_suffix: */
1126     strcpy(ifname, iname);
1127 #ifdef NO_MULTIPLE_DOTS
1128     if (*dot == '\0') strcpy(dot, ".");
1129 #endif
1130 #ifdef MAX_EXT_CHARS
1131     if (MAX_EXT_CHARS < z_len + strlen (dot + 1))
1132       dot[MAX_EXT_CHARS + 1 - z_len] = '\0';
1133 #endif
1134     strcat(ifname, z_suffix);
1135     errno = z_suffix_errno;
1136     progerror(ifname);
1137     return ERROR;
1138       
1139  name_too_long:
1140     fprintf (stderr, "%s: %s: file name too long\n", progname, iname);
1141     exit_code = ERROR;
1142     return ERROR;
1143 }
1144
1145 /* ========================================================================
1146  * Generate ofname given ifname. Return OK, or WARNING if file must be skipped.
1147  * Sets save_orig_name to true if the file name has been truncated.
1148  */
1149 local int make_ofname()
1150 {
1151     char *suff;            /* ofname z suffix */
1152
1153     strcpy(ofname, ifname);
1154     /* strip a version number if any and get the gzip suffix if present: */
1155     suff = get_suffix(ofname);
1156
1157     if (decompress) {
1158         if (suff == NULL) {
1159             /* With -t or -l, try all files (even without .gz suffix)
1160              * except with -r (behave as with just -dr).
1161              */
1162             if (!recursive && (list || test)) return OK;
1163
1164             /* Avoid annoying messages with -r */
1165             if (verbose || (!recursive && !quiet)) {
1166                 WARN((stderr,"%s: %s: unknown suffix -- ignored\n",
1167                       progname, ifname));
1168             }
1169             return WARNING;
1170         }
1171         /* Make a special case for .tgz and .taz: */
1172         strlwr(suff);
1173         if (strequ(suff, ".tgz") || strequ(suff, ".taz")) {
1174             strcpy(suff, ".tar");
1175         } else {
1176             *suff = '\0'; /* strip the z suffix */
1177         }
1178         /* ofname might be changed later if infile contains an original name */
1179
1180     } else if (suff != NULL) {
1181         /* Avoid annoying messages with -r (see treat_dir()) */
1182         if (verbose || (!recursive && !quiet)) {
1183             /* don't use WARN -- it will cause an exit_code of 2 */
1184             fprintf(stderr, "%s: %s already has %s suffix -- unchanged\n",
1185                   progname, ifname, suff);
1186         }
1187         return WARNING;
1188     } else {
1189         save_orig_name = 0;
1190
1191 #ifdef NO_MULTIPLE_DOTS
1192         suff = strrchr(ofname, '.');
1193         if (suff == NULL) {
1194             if (sizeof ofname <= strlen (ofname) + 1)
1195                 goto name_too_long;
1196             strcat(ofname, ".");
1197 #  ifdef MAX_EXT_CHARS
1198             if (strequ(z_suffix, "z")) {
1199                 if (sizeof ofname <= strlen (ofname) + 2)
1200                     goto name_too_long;
1201                 strcat(ofname, "gz"); /* enough room */
1202                 return OK;
1203             }
1204         /* On the Atari and some versions of MSDOS, name_too_long()
1205          * does not work correctly because of a bug in stat(). So we
1206          * must truncate here.
1207          */
1208         } else if (strlen(suff)-1 + z_len > MAX_SUFFIX) {
1209             suff[MAX_SUFFIX+1-z_len] = '\0';
1210             save_orig_name = 1;
1211 #  endif
1212         }
1213 #endif /* NO_MULTIPLE_DOTS */
1214         if (sizeof ofname <= strlen (ofname) + z_len)
1215             goto name_too_long;
1216         strcat(ofname, z_suffix);
1217
1218     } /* decompress ? */
1219     return OK;
1220
1221  name_too_long:
1222     WARN ((stderr, "%s: %s: file name too long\n", progname, ifname));
1223     return WARNING;
1224 }
1225
1226
1227 /* ========================================================================
1228  * Check the magic number of the input file and update ofname if an
1229  * original name was given and to_stdout is not set.
1230  * Return the compression method, -1 for error, -2 for warning.
1231  * Set inptr to the offset of the next byte to be processed.
1232  * Updates time_stamp if there is one and --no-time is not used.
1233  * This function may be called repeatedly for an input file consisting
1234  * of several contiguous gzip'ed members.
1235  * IN assertions: there is at least one remaining compressed member.
1236  *   If the member is a zip file, it must be the only one.
1237  */
1238 local int get_method(in)
1239     int in;        /* input file descriptor */
1240 {
1241     uch flags;     /* compression flags */
1242     char magic[2]; /* magic header */
1243     int imagic1;   /* like magic[1], but can represent EOF */
1244     ulg stamp;     /* time stamp */
1245
1246     /* If --force and --stdout, zcat == cat, so do not complain about
1247      * premature end of file: use try_byte instead of get_byte.
1248      */
1249     if (force && to_stdout) {
1250         magic[0] = (char)try_byte();
1251         imagic1 = try_byte ();
1252         magic[1] = (char) imagic1;
1253         /* If try_byte returned EOF, magic[1] == (char) EOF.  */
1254     } else {
1255         magic[0] = (char)get_byte();
1256         magic[1] = (char)get_byte();
1257         imagic1 = 0; /* avoid lint warning */
1258     }
1259     method = -1;                 /* unknown yet */
1260     part_nb++;                   /* number of parts in gzip file */
1261     header_bytes = 0;
1262     last_member = RECORD_IO;
1263     /* assume multiple members in gzip file except for record oriented I/O */
1264
1265     if (memcmp(magic, GZIP_MAGIC, 2) == 0
1266         || memcmp(magic, OLD_GZIP_MAGIC, 2) == 0) {
1267
1268         method = (int)get_byte();
1269         if (method != DEFLATED) {
1270             fprintf(stderr,
1271                     "%s: %s: unknown method %d -- not supported\n",
1272                     progname, ifname, method);
1273             exit_code = ERROR;
1274             return -1;
1275         }
1276         work = unzip;
1277         flags  = (uch)get_byte();
1278
1279         if ((flags & ENCRYPTED) != 0) {
1280             fprintf(stderr,
1281                     "%s: %s is encrypted -- not supported\n",
1282                     progname, ifname);
1283             exit_code = ERROR;
1284             return -1;
1285         }
1286         if ((flags & CONTINUATION) != 0) {
1287             fprintf(stderr,
1288                     "%s: %s is a a multi-part gzip file -- not supported\n",
1289                     progname, ifname);
1290             exit_code = ERROR;
1291             if (force <= 1) return -1;
1292         }
1293         if ((flags & RESERVED) != 0) {
1294             fprintf(stderr,
1295                     "%s: %s has flags 0x%x -- not supported\n",
1296                     progname, ifname, flags);
1297             exit_code = ERROR;
1298             if (force <= 1) return -1;
1299         }
1300         stamp  = (ulg)get_byte();
1301         stamp |= ((ulg)get_byte()) << 8;
1302         stamp |= ((ulg)get_byte()) << 16;
1303         stamp |= ((ulg)get_byte()) << 24;
1304         if (stamp != 0 && !no_time) time_stamp = stamp;
1305
1306         (void)get_byte();  /* Ignore extra flags for the moment */
1307         (void)get_byte();  /* Ignore OS type for the moment */
1308
1309         if ((flags & CONTINUATION) != 0) {
1310             unsigned part = (unsigned)get_byte();
1311             part |= ((unsigned)get_byte())<<8;
1312             if (verbose) {
1313                 fprintf(stderr,"%s: %s: part number %u\n",
1314                         progname, ifname, part);
1315             }
1316         }
1317         if ((flags & EXTRA_FIELD) != 0) {
1318             unsigned len = (unsigned)get_byte();
1319             len |= ((unsigned)get_byte())<<8;
1320             if (verbose) {
1321                 fprintf(stderr,"%s: %s: extra field of %u bytes ignored\n",
1322                         progname, ifname, len);
1323             }
1324             while (len--) (void)get_byte();
1325         }
1326
1327         /* Get original file name if it was truncated */
1328         if ((flags & ORIG_NAME) != 0) {
1329             if (no_name || (to_stdout && !list) || part_nb > 1) {
1330                 /* Discard the old name */
1331                 char c; /* dummy used for NeXTstep 3.0 cc optimizer bug */
1332                 do {c=get_byte();} while (c != 0);
1333             } else {
1334                 /* Copy the base name. Keep a directory prefix intact. */
1335                 char *p = base_name (ofname);
1336                 char *base = p;
1337                 char *base2;
1338                 for (;;) {
1339                     *p = (char)get_char();
1340                     if (*p++ == '\0') break;
1341                     if (p >= ofname+sizeof(ofname)) {
1342                         error("corrupted input -- file name too large");
1343                     }
1344                 }
1345                 base2 = base_name (base);
1346                 strcpy(base, base2);
1347                 /* If necessary, adapt the name to local OS conventions: */
1348                 if (!list) {
1349                    MAKE_LEGAL_NAME(base);
1350                    if (base) list=0; /* avoid warning about unused variable */
1351                 }
1352             } /* no_name || to_stdout */
1353         } /* ORIG_NAME */
1354
1355         /* Discard file comment if any */
1356         if ((flags & COMMENT) != 0) {
1357             while (get_char() != 0) /* null */ ;
1358         }
1359         if (part_nb == 1) {
1360             header_bytes = inptr + 2*sizeof(long); /* include crc and size */
1361         }
1362
1363     } else if (memcmp(magic, PKZIP_MAGIC, 2) == 0 && inptr == 2
1364             && memcmp((char*)inbuf, PKZIP_MAGIC, 4) == 0) {
1365         /* To simplify the code, we support a zip file when alone only.
1366          * We are thus guaranteed that the entire local header fits in inbuf.
1367          */
1368         inptr = 0;
1369         work = unzip;
1370         if (check_zipfile(in) != OK) return -1;
1371         /* check_zipfile may get ofname from the local header */
1372         last_member = 1;
1373
1374     } else if (memcmp(magic, PACK_MAGIC, 2) == 0) {
1375         work = unpack;
1376         method = PACKED;
1377
1378     } else if (memcmp(magic, LZW_MAGIC, 2) == 0) {
1379         work = unlzw;
1380         method = COMPRESSED;
1381         last_member = 1;
1382
1383     } else if (memcmp(magic, LZH_MAGIC, 2) == 0) {
1384         work = unlzh;
1385         method = LZHED;
1386         last_member = 1;
1387
1388     } else if (force && to_stdout && !list) { /* pass input unchanged */
1389         method = STORED;
1390         work = copy;
1391         inptr = 0;
1392         last_member = 1;
1393     }
1394     if (method >= 0) return method;
1395
1396     if (part_nb == 1) {
1397         fprintf(stderr, "\n%s: %s: not in gzip format\n", progname, ifname);
1398         exit_code = ERROR;
1399         return -1;
1400     } else {
1401         if (magic[0] == 0)
1402           {
1403             int inbyte;
1404             for (inbyte = imagic1;  inbyte == 0;  inbyte = try_byte ())
1405               continue;
1406             if (inbyte == EOF)
1407               {
1408                 if (verbose)
1409                   WARN ((stderr, "\n%s: %s: decompression OK, trailing zero bytes ignored\n",
1410                          progname, ifname));
1411                 return -3;
1412               }
1413           }
1414
1415         WARN((stderr, "\n%s: %s: decompression OK, trailing garbage ignored\n",
1416               progname, ifname));
1417         return -2;
1418     }
1419 }
1420
1421 /* ========================================================================
1422  * Display the characteristics of the compressed file.
1423  * If the given method is < 0, display the accumulated totals.
1424  * IN assertions: time_stamp, header_bytes and ifile_size are initialized.
1425  */
1426 local void do_list(ifd, method)
1427     int ifd;     /* input file descriptor */
1428     int method;  /* compression method */
1429 {
1430     ulg crc;  /* original crc */
1431     static int first_time = 1;
1432     static char* methods[MAX_METHODS] = {
1433         "store",  /* 0 */
1434         "compr",  /* 1 */
1435         "pack ",  /* 2 */
1436         "lzh  ",  /* 3 */
1437         "", "", "", "", /* 4 to 7 reserved */
1438         "defla"}; /* 8 */
1439     char *date;
1440     int positive_off_t_width = 1;
1441     off_t o;
1442
1443     for (o = OFF_T_MAX;  9 < o;  o /= 10) {
1444         positive_off_t_width++;
1445     }
1446
1447     if (first_time && method >= 0) {
1448         first_time = 0;
1449         if (verbose)  {
1450             printf("method  crc     date  time  ");
1451         }
1452         if (!quiet) {
1453             printf("%*.*s %*.*s  ratio uncompressed_name\n",
1454                    positive_off_t_width, positive_off_t_width, "compressed",
1455                    positive_off_t_width, positive_off_t_width, "uncompressed");
1456         }
1457     } else if (method < 0) {
1458         if (total_in <= 0 || total_out <= 0) return;
1459         if (verbose) {
1460             printf("                            ");
1461         }
1462         if (verbose || !quiet) {
1463             fprint_off(stdout, total_in, positive_off_t_width);
1464             printf(" ");
1465             fprint_off(stdout, total_out, positive_off_t_width);
1466             printf(" ");
1467         }
1468         display_ratio(total_out-(total_in-header_bytes), total_out, stdout);
1469         /* header_bytes is not meaningful but used to ensure the same
1470          * ratio if there is a single file.
1471          */
1472         printf(" (totals)\n");
1473         return;
1474     }
1475     crc = (ulg)~0; /* unknown */
1476     bytes_out = -1L;
1477     bytes_in = ifile_size;
1478
1479 #if RECORD_IO == 0
1480     if (method == DEFLATED && !last_member) {
1481         /* Get the crc and uncompressed size for gzip'ed (not zip'ed) files.
1482          * If the lseek fails, we could use read() to get to the end, but
1483          * --list is used to get quick results.
1484          * Use "gunzip < foo.gz | wc -c" to get the uncompressed size if
1485          * you are not concerned about speed.
1486          */
1487         bytes_in = lseek(ifd, (off_t)(-8), SEEK_END);
1488         if (bytes_in != -1L) {
1489             uch buf[8];
1490             bytes_in += 8L;
1491             if (read(ifd, (char*)buf, sizeof(buf)) != sizeof(buf)) {
1492                 read_error();
1493             }
1494             crc       = LG(buf);
1495             bytes_out = LG(buf+4);
1496         }
1497     }
1498 #endif /* RECORD_IO */
1499     date = ctime((time_t*)&time_stamp) + 4; /* skip the day of the week */
1500     date[12] = '\0';               /* suppress the 1/100sec and the year */
1501     if (verbose) {
1502         printf("%5s %08lx %11s ", methods[method], crc, date);
1503     }
1504     fprint_off(stdout, bytes_in, positive_off_t_width);
1505     printf(" ");
1506     fprint_off(stdout, bytes_out, positive_off_t_width);
1507     printf(" ");
1508     if (bytes_in  == -1L) {
1509         total_in = -1L;
1510         bytes_in = bytes_out = header_bytes = 0;
1511     } else if (total_in >= 0) {
1512         total_in  += bytes_in;
1513     }
1514     if (bytes_out == -1L) {
1515         total_out = -1L;
1516         bytes_in = bytes_out = header_bytes = 0;
1517     } else if (total_out >= 0) {
1518         total_out += bytes_out;
1519     }
1520     display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out, stdout);
1521     printf(" %s\n", ofname);
1522 }
1523
1524 /* ========================================================================
1525  * Return true if the two stat structures correspond to the same file.
1526  */
1527 local int same_file(stat1, stat2)
1528     struct stat *stat1;
1529     struct stat *stat2;
1530 {
1531     return stat1->st_ino   == stat2->st_ino
1532         && stat1->st_dev   == stat2->st_dev
1533 #ifdef NO_ST_INO
1534         /* Can't rely on st_ino and st_dev, use other fields: */
1535         && stat1->st_mode  == stat2->st_mode
1536         && stat1->st_uid   == stat2->st_uid
1537         && stat1->st_gid   == stat2->st_gid
1538         && stat1->st_size  == stat2->st_size
1539         && stat1->st_atime == stat2->st_atime
1540         && stat1->st_mtime == stat2->st_mtime
1541         && stat1->st_ctime == stat2->st_ctime
1542 #endif
1543             ;
1544 }
1545
1546 /* ========================================================================
1547  * Return true if a file name is ambiguous because the operating system
1548  * truncates file names.
1549  */
1550 local int name_too_long(name, statb)
1551     char *name;           /* file name to check */
1552     struct stat *statb;   /* stat buf for this file name */
1553 {
1554     int s = strlen(name);
1555     char c = name[s-1];
1556     struct stat tstat; /* stat for truncated name */
1557     int res;
1558
1559     tstat = *statb;      /* Just in case OS does not fill all fields */
1560     name[s-1] = '\0';
1561     res = lstat(name, &tstat) == 0 && same_file(statb, &tstat);
1562     name[s-1] = c;
1563     Trace((stderr, " too_long(%s) => %d\n", name, res));
1564     return res;
1565 }
1566
1567 /* ========================================================================
1568  * Shorten the given name by one character, or replace a .tar extension
1569  * with .tgz. Truncate the last part of the name which is longer than
1570  * MIN_PART characters: 1234.678.012.gz -> 123.678.012.gz. If the name
1571  * has only parts shorter than MIN_PART truncate the longest part.
1572  * For decompression, just remove the last character of the name.
1573  *
1574  * IN assertion: for compression, the suffix of the given name is z_suffix.
1575  */
1576 local void shorten_name(name)
1577     char *name;
1578 {
1579     int len;                 /* length of name without z_suffix */
1580     char *trunc = NULL;      /* character to be truncated */
1581     int plen;                /* current part length */
1582     int min_part = MIN_PART; /* current minimum part length */
1583     char *p;
1584
1585     len = strlen(name);
1586     if (decompress) {
1587         if (len <= 1) error("name too short");
1588         name[len-1] = '\0';
1589         return;
1590     }
1591     p = get_suffix(name);
1592     if (p == NULL) error("can't recover suffix\n");
1593     *p = '\0';
1594     save_orig_name = 1;
1595
1596     /* compress 1234567890.tar to 1234567890.tgz */
1597     if (len > 4 && strequ(p-4, ".tar")) {
1598         strcpy(p-4, ".tgz");
1599         return;
1600     }
1601     /* Try keeping short extensions intact:
1602      * 1234.678.012.gz -> 123.678.012.gz
1603      */
1604     do {
1605         p = strrchr(name, PATH_SEP);
1606         p = p ? p+1 : name;
1607         while (*p) {
1608             plen = strcspn(p, PART_SEP);
1609             p += plen;
1610             if (plen > min_part) trunc = p-1;
1611             if (*p) p++;
1612         }
1613     } while (trunc == NULL && --min_part != 0);
1614
1615     if (trunc != NULL) {
1616         do {
1617             trunc[0] = trunc[1];
1618         } while (*trunc++);
1619         trunc--;
1620     } else {
1621         trunc = strrchr(name, PART_SEP[0]);
1622         if (trunc == NULL) error("internal error in shorten_name");
1623         if (trunc[1] == '\0') trunc--; /* force truncation */
1624     }
1625     strcpy(trunc, z_suffix);
1626 }
1627
1628 /* ========================================================================
1629  * If compressing to a file, check if ofname is not ambiguous
1630  * because the operating system truncates names. Otherwise, generate
1631  * a new ofname and save the original name in the compressed file.
1632  * If the compressed file already exists, ask for confirmation.
1633  *    The check for name truncation is made dynamically, because different
1634  * file systems on the same OS might use different truncation rules (on SVR4
1635  * s5 truncates to 14 chars and ufs does not truncate).
1636  *    This function returns -1 if the file must be skipped, and
1637  * updates save_orig_name if necessary.
1638  * IN assertions: save_orig_name is already set if ofname has been
1639  * already truncated because of NO_MULTIPLE_DOTS. The input file has
1640  * already been open and istat is set.
1641  */
1642 local int check_ofname()
1643 {
1644     struct stat ostat; /* stat for ofname */
1645
1646 #ifdef ENAMETOOLONG
1647     /* Check for strictly conforming Posix systems (which return ENAMETOOLONG
1648      * instead of silently truncating filenames).
1649      */
1650     errno = 0;
1651     while (lstat(ofname, &ostat) != 0) {
1652         if (errno != ENAMETOOLONG) return 0; /* ofname does not exist */
1653         shorten_name(ofname);
1654     }
1655 #else
1656     if (lstat(ofname, &ostat) != 0) return 0;
1657 #endif
1658     /* Check for name truncation on existing file. Do this even on systems
1659      * defining ENAMETOOLONG, because on most systems the strict Posix
1660      * behavior is disabled by default (silent name truncation allowed).
1661      */
1662     if (!decompress && name_too_long(ofname, &ostat)) {
1663         shorten_name(ofname);
1664         if (lstat(ofname, &ostat) != 0) return 0;
1665     }
1666
1667     /* Check that the input and output files are different (could be
1668      * the same by name truncation or links).
1669      */
1670     if (same_file(&istat, &ostat)) {
1671         if (strequ(ifname, ofname)) {
1672             fprintf(stderr, "%s: %s: cannot %scompress onto itself\n",
1673                     progname, ifname, decompress ? "de" : "");
1674         } else {
1675             fprintf(stderr, "%s: %s and %s are the same file\n",
1676                     progname, ifname, ofname);
1677         }
1678         exit_code = ERROR;
1679         return ERROR;
1680     }
1681     /* Ask permission to overwrite the existing file */
1682     if (!force) {
1683         int ok = 0;
1684         fprintf(stderr, "%s: %s already exists;", progname, ofname);
1685         if (foreground && isatty(fileno(stdin))) {
1686             fprintf(stderr, " do you wish to overwrite (y or n)? ");
1687             fflush(stderr);
1688             ok = yesno();
1689         }
1690         if (!ok) {
1691             fprintf(stderr, "\tnot overwritten\n");
1692             if (exit_code == OK) exit_code = WARNING;
1693             return ERROR;
1694         }
1695     }
1696     if (xunlink (ofname)) {
1697         progerror(ofname);
1698         return ERROR;
1699     }
1700     return OK;
1701 }
1702
1703
1704 #ifndef NO_UTIME
1705 /* ========================================================================
1706  * Set the access and modification times from the given stat buffer.
1707  */
1708 local void reset_times (name, statb)
1709     char *name;
1710     struct stat *statb;
1711 {
1712     struct utimbuf      timep;
1713
1714     /* Copy the time stamp */
1715     timep.actime  = statb->st_atime;
1716     timep.modtime = statb->st_mtime;
1717
1718     /* Some systems (at least OS/2) do not support utime on directories */
1719     if (utime(name, &timep) && !S_ISDIR(statb->st_mode)) {
1720         int e = errno;
1721         WARN((stderr, "%s: ", progname));
1722         if (!quiet) {
1723             errno = e;
1724             perror(ofname);
1725         }
1726     }
1727 }
1728 #endif
1729
1730
1731 /* ========================================================================
1732  * Copy modes, times, ownership from input file to output file.
1733  * IN assertion: to_stdout is false.
1734  */
1735 local void copy_stat(ifstat)
1736     struct stat *ifstat;
1737 {
1738 #ifndef NO_UTIME
1739     if (decompress && time_stamp != 0 && ifstat->st_mtime != time_stamp) {
1740         ifstat->st_mtime = time_stamp;
1741         if (verbose > 1) {
1742             fprintf(stderr, "%s: time stamp restored\n", ofname);
1743         }
1744     }
1745     reset_times(ofname, ifstat);
1746 #endif
1747     /* Copy the protection modes */
1748     if (fchmod(ofd, ifstat->st_mode & 07777)) {
1749         int e = errno;
1750         WARN((stderr, "%s: ", progname));
1751         if (!quiet) {
1752             errno = e;
1753             perror(ofname);
1754         }
1755     }
1756 #ifndef NO_CHOWN
1757     fchown(ofd, ifstat->st_uid, ifstat->st_gid);  /* Copy ownership */
1758 #endif
1759 }
1760
1761 #if ! NO_DIR
1762
1763 /* ========================================================================
1764  * Recurse through the given directory. This code is taken from ncompress.
1765  */
1766 local void treat_dir(dir)
1767     char *dir;
1768 {
1769     struct dirent *dp;
1770     DIR      *dirp;
1771     char     nbuf[MAX_PATH_LEN];
1772     int      len;
1773
1774     dirp = opendir(dir);
1775     
1776     if (dirp == NULL) {
1777         progerror(dir);
1778         return ;
1779     }
1780     /*
1781      ** WARNING: the following algorithm could occasionally cause
1782      ** compress to produce error warnings of the form "<filename>.gz
1783      ** already has .gz suffix - ignored". This occurs when the
1784      ** .gz output file is inserted into the directory below
1785      ** readdir's current pointer.
1786      ** These warnings are harmless but annoying, so they are suppressed
1787      ** with option -r (except when -v is on). An alternative
1788      ** to allowing this would be to store the entire directory
1789      ** list in memory, then compress the entries in the stored
1790      ** list. Given the depth-first recursive algorithm used here,
1791      ** this could use up a tremendous amount of memory. I don't
1792      ** think it's worth it. -- Dave Mack
1793      ** (An other alternative might be two passes to avoid depth-first.)
1794      */
1795     
1796     while ((errno = 0, dp = readdir(dirp)) != NULL) {
1797
1798         if (strequ(dp->d_name,".") || strequ(dp->d_name,"..")) {
1799             continue;
1800         }
1801         len = strlen(dir);
1802         if (len + NAMLEN(dp) + 1 < MAX_PATH_LEN - 1) {
1803             strcpy(nbuf,dir);
1804             if (len != 0 /* dir = "" means current dir on Amiga */
1805 #ifdef PATH_SEP2
1806                 && dir[len-1] != PATH_SEP2
1807 #endif
1808 #ifdef PATH_SEP3
1809                 && dir[len-1] != PATH_SEP3
1810 #endif
1811             ) {
1812                 nbuf[len++] = PATH_SEP;
1813             }
1814             strcpy(nbuf+len, dp->d_name);
1815             treat_file(nbuf);
1816         } else {
1817             fprintf(stderr,"%s: %s/%s: pathname too long\n",
1818                     progname, dir, dp->d_name);
1819             exit_code = ERROR;
1820         }
1821     }
1822     if (errno != 0)
1823         progerror(dir);
1824     if (CLOSEDIR(dirp) != 0)
1825         progerror(dir);
1826 }
1827 #endif /* ! NO_DIR */
1828
1829 /* ========================================================================
1830  * Free all dynamically allocated variables and exit with the given code.
1831  */
1832 local void do_exit(exitcode)
1833     int exitcode;
1834 {
1835     static int in_exit = 0;
1836
1837     if (in_exit) exit(exitcode);
1838     in_exit = 1;
1839     if (env != NULL)  free(env),  env  = NULL;
1840     if (args != NULL) free((char*)args), args = NULL;
1841     FREE(inbuf);
1842     FREE(outbuf);
1843     FREE(d_buf);
1844     FREE(window);
1845 #ifndef MAXSEG_64K
1846     FREE(tab_prefix);
1847 #else
1848     FREE(tab_prefix0);
1849     FREE(tab_prefix1);
1850 #endif
1851     exit(exitcode);
1852 }
1853
1854 /* ========================================================================
1855  * Close and unlink the output file if appropriate.  This routine must be
1856  * async-signal-safe.
1857  */
1858 local void do_remove() {
1859    if (remove_ofname) {
1860        close(ofd);
1861        xunlink (ofname);
1862    }
1863 }
1864
1865 /* ========================================================================
1866  * Error handler.
1867  */
1868 RETSIGTYPE abort_gzip()
1869 {
1870         do_remove();
1871         do_exit(ERROR);
1872 }
1873
1874 /* ========================================================================
1875  * Signal handler.
1876  */
1877 RETSIGTYPE abort_gzip_signal()
1878 {
1879         do_remove();
1880         _exit(ERROR);
1881 }
1882