]> git.cworth.org Git - gzip/blob - gzip.c
Imported Debian patch 1.3.5-13
[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, 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             /* don't use WARN -- it will cause an exit_code of 2 */
1173             fprintf(stderr, "%s: %s already has %s suffix -- unchanged\n",
1174                   progname, ifname, suff);
1175         }
1176         return WARNING;
1177     } else {
1178         save_orig_name = 0;
1179
1180 #ifdef NO_MULTIPLE_DOTS
1181         suff = strrchr(ofname, '.');
1182         if (suff == NULL) {
1183             if (sizeof ofname <= strlen (ofname) + 1)
1184                 goto name_too_long;
1185             strcat(ofname, ".");
1186 #  ifdef MAX_EXT_CHARS
1187             if (strequ(z_suffix, "z")) {
1188                 if (sizeof ofname <= strlen (ofname) + 2)
1189                     goto name_too_long;
1190                 strcat(ofname, "gz"); /* enough room */
1191                 return OK;
1192             }
1193         /* On the Atari and some versions of MSDOS, name_too_long()
1194          * does not work correctly because of a bug in stat(). So we
1195          * must truncate here.
1196          */
1197         } else if (strlen(suff)-1 + z_len > MAX_SUFFIX) {
1198             suff[MAX_SUFFIX+1-z_len] = '\0';
1199             save_orig_name = 1;
1200 #  endif
1201         }
1202 #endif /* NO_MULTIPLE_DOTS */
1203         if (sizeof ofname <= strlen (ofname) + z_len)
1204             goto name_too_long;
1205         strcat(ofname, z_suffix);
1206
1207     } /* decompress ? */
1208     return OK;
1209
1210  name_too_long:
1211     WARN ((stderr, "%s: %s: file name too long\n", progname, ifname));
1212     return WARNING;
1213 }
1214
1215
1216 /* ========================================================================
1217  * Check the magic number of the input file and update ofname if an
1218  * original name was given and to_stdout is not set.
1219  * Return the compression method, -1 for error, -2 for warning.
1220  * Set inptr to the offset of the next byte to be processed.
1221  * Updates time_stamp if there is one and --no-time is not used.
1222  * This function may be called repeatedly for an input file consisting
1223  * of several contiguous gzip'ed members.
1224  * IN assertions: there is at least one remaining compressed member.
1225  *   If the member is a zip file, it must be the only one.
1226  */
1227 local int get_method(in)
1228     int in;        /* input file descriptor */
1229 {
1230     uch flags;     /* compression flags */
1231     char magic[2]; /* magic header */
1232     int imagic1;   /* like magic[1], but can represent EOF */
1233     ulg stamp;     /* time stamp */
1234
1235     /* If --force and --stdout, zcat == cat, so do not complain about
1236      * premature end of file: use try_byte instead of get_byte.
1237      */
1238     if (force && to_stdout) {
1239         magic[0] = (char)try_byte();
1240         imagic1 = try_byte ();
1241         magic[1] = (char) imagic1;
1242         /* If try_byte returned EOF, magic[1] == (char) EOF.  */
1243     } else {
1244         magic[0] = (char)get_byte();
1245         magic[1] = (char)get_byte();
1246         imagic1 = 0; /* avoid lint warning */
1247     }
1248     method = -1;                 /* unknown yet */
1249     part_nb++;                   /* number of parts in gzip file */
1250     header_bytes = 0;
1251     last_member = RECORD_IO;
1252     /* assume multiple members in gzip file except for record oriented I/O */
1253
1254     if (memcmp(magic, GZIP_MAGIC, 2) == 0
1255         || memcmp(magic, OLD_GZIP_MAGIC, 2) == 0) {
1256
1257         method = (int)get_byte();
1258         if (method != DEFLATED) {
1259             fprintf(stderr,
1260                     "%s: %s: unknown method %d -- not supported\n",
1261                     progname, ifname, method);
1262             exit_code = ERROR;
1263             return -1;
1264         }
1265         work = unzip;
1266         flags  = (uch)get_byte();
1267
1268         if ((flags & ENCRYPTED) != 0) {
1269             fprintf(stderr,
1270                     "%s: %s is encrypted -- not supported\n",
1271                     progname, ifname);
1272             exit_code = ERROR;
1273             return -1;
1274         }
1275         if ((flags & CONTINUATION) != 0) {
1276             fprintf(stderr,
1277                     "%s: %s is a a multi-part gzip file -- not supported\n",
1278                     progname, ifname);
1279             exit_code = ERROR;
1280             if (force <= 1) return -1;
1281         }
1282         if ((flags & RESERVED) != 0) {
1283             fprintf(stderr,
1284                     "%s: %s has flags 0x%x -- not supported\n",
1285                     progname, ifname, flags);
1286             exit_code = ERROR;
1287             if (force <= 1) return -1;
1288         }
1289         stamp  = (ulg)get_byte();
1290         stamp |= ((ulg)get_byte()) << 8;
1291         stamp |= ((ulg)get_byte()) << 16;
1292         stamp |= ((ulg)get_byte()) << 24;
1293         if (stamp != 0 && !no_time) time_stamp = stamp;
1294
1295         (void)get_byte();  /* Ignore extra flags for the moment */
1296         (void)get_byte();  /* Ignore OS type for the moment */
1297
1298         if ((flags & CONTINUATION) != 0) {
1299             unsigned part = (unsigned)get_byte();
1300             part |= ((unsigned)get_byte())<<8;
1301             if (verbose) {
1302                 fprintf(stderr,"%s: %s: part number %u\n",
1303                         progname, ifname, part);
1304             }
1305         }
1306         if ((flags & EXTRA_FIELD) != 0) {
1307             unsigned len = (unsigned)get_byte();
1308             len |= ((unsigned)get_byte())<<8;
1309             if (verbose) {
1310                 fprintf(stderr,"%s: %s: extra field of %u bytes ignored\n",
1311                         progname, ifname, len);
1312             }
1313             while (len--) (void)get_byte();
1314         }
1315
1316         /* Get original file name if it was truncated */
1317         if ((flags & ORIG_NAME) != 0) {
1318             if (no_name || (to_stdout && !list) || part_nb > 1) {
1319                 /* Discard the old name */
1320                 char c; /* dummy used for NeXTstep 3.0 cc optimizer bug */
1321                 do {c=get_byte();} while (c != 0);
1322             } else {
1323                 /* Copy the base name. Keep a directory prefix intact. */
1324                 char *p = base_name (ofname);
1325                 char *base = p;
1326                 char *base2;
1327                 for (;;) {
1328                     *p = (char)get_char();
1329                     if (*p++ == '\0') break;
1330                     if (p >= ofname+sizeof(ofname)) {
1331                         error("corrupted input -- file name too large");
1332                     }
1333                 }
1334                 base2 = base_name (base);
1335                 strcpy(base, base2);
1336                 /* If necessary, adapt the name to local OS conventions: */
1337                 if (!list) {
1338                    MAKE_LEGAL_NAME(base);
1339                    if (base) list=0; /* avoid warning about unused variable */
1340                 }
1341             } /* no_name || to_stdout */
1342         } /* ORIG_NAME */
1343
1344         /* Discard file comment if any */
1345         if ((flags & COMMENT) != 0) {
1346             while (get_char() != 0) /* null */ ;
1347         }
1348         if (part_nb == 1) {
1349             header_bytes = inptr + 2*sizeof(long); /* include crc and size */
1350         }
1351
1352     } else if (memcmp(magic, PKZIP_MAGIC, 2) == 0 && inptr == 2
1353             && memcmp((char*)inbuf, PKZIP_MAGIC, 4) == 0) {
1354         /* To simplify the code, we support a zip file when alone only.
1355          * We are thus guaranteed that the entire local header fits in inbuf.
1356          */
1357         inptr = 0;
1358         work = unzip;
1359         if (check_zipfile(in) != OK) return -1;
1360         /* check_zipfile may get ofname from the local header */
1361         last_member = 1;
1362
1363     } else if (memcmp(magic, PACK_MAGIC, 2) == 0) {
1364         work = unpack;
1365         method = PACKED;
1366
1367     } else if (memcmp(magic, LZW_MAGIC, 2) == 0) {
1368         work = unlzw;
1369         method = COMPRESSED;
1370         last_member = 1;
1371
1372     } else if (memcmp(magic, LZH_MAGIC, 2) == 0) {
1373         work = unlzh;
1374         method = LZHED;
1375         last_member = 1;
1376
1377     } else if (force && to_stdout && !list) { /* pass input unchanged */
1378         method = STORED;
1379         work = copy;
1380         inptr = 0;
1381         last_member = 1;
1382     }
1383     if (method >= 0) return method;
1384
1385     if (part_nb == 1) {
1386         fprintf(stderr, "\n%s: %s: not in gzip format\n", progname, ifname);
1387         exit_code = ERROR;
1388         return -1;
1389     } else {
1390         if (magic[0] == 0)
1391           {
1392             int inbyte;
1393             for (inbyte = imagic1;  inbyte == 0;  inbyte = try_byte ())
1394               continue;
1395             if (inbyte == EOF)
1396               {
1397                 if (verbose)
1398                   WARN ((stderr, "\n%s: %s: decompression OK, trailing zero bytes ignored\n",
1399                          progname, ifname));
1400                 return -3;
1401               }
1402           }
1403
1404         WARN((stderr, "\n%s: %s: decompression OK, trailing garbage ignored\n",
1405               progname, ifname));
1406         return -2;
1407     }
1408 }
1409
1410 /* ========================================================================
1411  * Display the characteristics of the compressed file.
1412  * If the given method is < 0, display the accumulated totals.
1413  * IN assertions: time_stamp, header_bytes and ifile_size are initialized.
1414  */
1415 local void do_list(ifd, method)
1416     int ifd;     /* input file descriptor */
1417     int method;  /* compression method */
1418 {
1419     ulg crc;  /* original crc */
1420     static int first_time = 1;
1421     static char* methods[MAX_METHODS] = {
1422         "store",  /* 0 */
1423         "compr",  /* 1 */
1424         "pack ",  /* 2 */
1425         "lzh  ",  /* 3 */
1426         "", "", "", "", /* 4 to 7 reserved */
1427         "defla"}; /* 8 */
1428     char *date;
1429     int positive_off_t_width = 1;
1430     off_t o;
1431
1432     for (o = OFF_T_MAX;  9 < o;  o /= 10) {
1433         positive_off_t_width++;
1434     }
1435
1436     if (first_time && method >= 0) {
1437         first_time = 0;
1438         if (verbose)  {
1439             printf("method  crc     date  time  ");
1440         }
1441         if (!quiet) {
1442             printf("%*.*s %*.*s  ratio uncompressed_name\n",
1443                    positive_off_t_width, positive_off_t_width, "compressed",
1444                    positive_off_t_width, positive_off_t_width, "uncompressed");
1445         }
1446     } else if (method < 0) {
1447         if (total_in <= 0 || total_out <= 0) return;
1448         if (verbose) {
1449             printf("                            ");
1450         }
1451         if (verbose || !quiet) {
1452             fprint_off(stdout, total_in, positive_off_t_width);
1453             printf(" ");
1454             fprint_off(stdout, total_out, positive_off_t_width);
1455             printf(" ");
1456         }
1457         display_ratio(total_out-(total_in-header_bytes), total_out, stdout);
1458         /* header_bytes is not meaningful but used to ensure the same
1459          * ratio if there is a single file.
1460          */
1461         printf(" (totals)\n");
1462         return;
1463     }
1464     crc = (ulg)~0; /* unknown */
1465     bytes_out = -1L;
1466     bytes_in = ifile_size;
1467
1468 #if RECORD_IO == 0
1469     if (method == DEFLATED && !last_member) {
1470         /* Get the crc and uncompressed size for gzip'ed (not zip'ed) files.
1471          * If the lseek fails, we could use read() to get to the end, but
1472          * --list is used to get quick results.
1473          * Use "gunzip < foo.gz | wc -c" to get the uncompressed size if
1474          * you are not concerned about speed.
1475          */
1476         bytes_in = lseek(ifd, (off_t)(-8), SEEK_END);
1477         if (bytes_in != -1L) {
1478             uch buf[8];
1479             bytes_in += 8L;
1480             if (read(ifd, (char*)buf, sizeof(buf)) != sizeof(buf)) {
1481                 read_error();
1482             }
1483             crc       = LG(buf);
1484             bytes_out = LG(buf+4);
1485         }
1486     }
1487 #endif /* RECORD_IO */
1488     date = ctime((time_t*)&time_stamp) + 4; /* skip the day of the week */
1489     date[12] = '\0';               /* suppress the 1/100sec and the year */
1490     if (verbose) {
1491         printf("%5s %08lx %11s ", methods[method], crc, date);
1492     }
1493     fprint_off(stdout, bytes_in, positive_off_t_width);
1494     printf(" ");
1495     fprint_off(stdout, bytes_out, positive_off_t_width);
1496     printf(" ");
1497     if (bytes_in  == -1L) {
1498         total_in = -1L;
1499         bytes_in = bytes_out = header_bytes = 0;
1500     } else if (total_in >= 0) {
1501         total_in  += bytes_in;
1502     }
1503     if (bytes_out == -1L) {
1504         total_out = -1L;
1505         bytes_in = bytes_out = header_bytes = 0;
1506     } else if (total_out >= 0) {
1507         total_out += bytes_out;
1508     }
1509     display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out, stdout);
1510     printf(" %s\n", ofname);
1511 }
1512
1513 /* ========================================================================
1514  * Return true if the two stat structures correspond to the same file.
1515  */
1516 local int same_file(stat1, stat2)
1517     struct stat *stat1;
1518     struct stat *stat2;
1519 {
1520     return stat1->st_ino   == stat2->st_ino
1521         && stat1->st_dev   == stat2->st_dev
1522 #ifdef NO_ST_INO
1523         /* Can't rely on st_ino and st_dev, use other fields: */
1524         && stat1->st_mode  == stat2->st_mode
1525         && stat1->st_uid   == stat2->st_uid
1526         && stat1->st_gid   == stat2->st_gid
1527         && stat1->st_size  == stat2->st_size
1528         && stat1->st_atime == stat2->st_atime
1529         && stat1->st_mtime == stat2->st_mtime
1530         && stat1->st_ctime == stat2->st_ctime
1531 #endif
1532             ;
1533 }
1534
1535 /* ========================================================================
1536  * Return true if a file name is ambiguous because the operating system
1537  * truncates file names.
1538  */
1539 local int name_too_long(name, statb)
1540     char *name;           /* file name to check */
1541     struct stat *statb;   /* stat buf for this file name */
1542 {
1543     int s = strlen(name);
1544     char c = name[s-1];
1545     struct stat tstat; /* stat for truncated name */
1546     int res;
1547
1548     tstat = *statb;      /* Just in case OS does not fill all fields */
1549     name[s-1] = '\0';
1550     res = lstat(name, &tstat) == 0 && same_file(statb, &tstat);
1551     name[s-1] = c;
1552     Trace((stderr, " too_long(%s) => %d\n", name, res));
1553     return res;
1554 }
1555
1556 /* ========================================================================
1557  * Shorten the given name by one character, or replace a .tar extension
1558  * with .tgz. Truncate the last part of the name which is longer than
1559  * MIN_PART characters: 1234.678.012.gz -> 123.678.012.gz. If the name
1560  * has only parts shorter than MIN_PART truncate the longest part.
1561  * For decompression, just remove the last character of the name.
1562  *
1563  * IN assertion: for compression, the suffix of the given name is z_suffix.
1564  */
1565 local void shorten_name(name)
1566     char *name;
1567 {
1568     int len;                 /* length of name without z_suffix */
1569     char *trunc = NULL;      /* character to be truncated */
1570     int plen;                /* current part length */
1571     int min_part = MIN_PART; /* current minimum part length */
1572     char *p;
1573
1574     len = strlen(name);
1575     if (decompress) {
1576         if (len <= 1) error("name too short");
1577         name[len-1] = '\0';
1578         return;
1579     }
1580     p = get_suffix(name);
1581     if (p == NULL) error("can't recover suffix\n");
1582     *p = '\0';
1583     save_orig_name = 1;
1584
1585     /* compress 1234567890.tar to 1234567890.tgz */
1586     if (len > 4 && strequ(p-4, ".tar")) {
1587         strcpy(p-4, ".tgz");
1588         return;
1589     }
1590     /* Try keeping short extensions intact:
1591      * 1234.678.012.gz -> 123.678.012.gz
1592      */
1593     do {
1594         p = strrchr(name, PATH_SEP);
1595         p = p ? p+1 : name;
1596         while (*p) {
1597             plen = strcspn(p, PART_SEP);
1598             p += plen;
1599             if (plen > min_part) trunc = p-1;
1600             if (*p) p++;
1601         }
1602     } while (trunc == NULL && --min_part != 0);
1603
1604     if (trunc != NULL) {
1605         do {
1606             trunc[0] = trunc[1];
1607         } while (*trunc++);
1608         trunc--;
1609     } else {
1610         trunc = strrchr(name, PART_SEP[0]);
1611         if (trunc == NULL) error("internal error in shorten_name");
1612         if (trunc[1] == '\0') trunc--; /* force truncation */
1613     }
1614     strcpy(trunc, z_suffix);
1615 }
1616
1617 /* ========================================================================
1618  * If compressing to a file, check if ofname is not ambiguous
1619  * because the operating system truncates names. Otherwise, generate
1620  * a new ofname and save the original name in the compressed file.
1621  * If the compressed file already exists, ask for confirmation.
1622  *    The check for name truncation is made dynamically, because different
1623  * file systems on the same OS might use different truncation rules (on SVR4
1624  * s5 truncates to 14 chars and ufs does not truncate).
1625  *    This function returns -1 if the file must be skipped, and
1626  * updates save_orig_name if necessary.
1627  * IN assertions: save_orig_name is already set if ofname has been
1628  * already truncated because of NO_MULTIPLE_DOTS. The input file has
1629  * already been open and istat is set.
1630  */
1631 local int check_ofname()
1632 {
1633     struct stat ostat; /* stat for ofname */
1634
1635 #ifdef ENAMETOOLONG
1636     /* Check for strictly conforming Posix systems (which return ENAMETOOLONG
1637      * instead of silently truncating filenames).
1638      */
1639     errno = 0;
1640     while (lstat(ofname, &ostat) != 0) {
1641         if (errno != ENAMETOOLONG) return 0; /* ofname does not exist */
1642         shorten_name(ofname);
1643     }
1644 #else
1645     if (lstat(ofname, &ostat) != 0) return 0;
1646 #endif
1647     /* Check for name truncation on existing file. Do this even on systems
1648      * defining ENAMETOOLONG, because on most systems the strict Posix
1649      * behavior is disabled by default (silent name truncation allowed).
1650      */
1651     if (!decompress && name_too_long(ofname, &ostat)) {
1652         shorten_name(ofname);
1653         if (lstat(ofname, &ostat) != 0) return 0;
1654     }
1655
1656     /* Check that the input and output files are different (could be
1657      * the same by name truncation or links).
1658      */
1659     if (same_file(&istat, &ostat)) {
1660         if (strequ(ifname, ofname)) {
1661             fprintf(stderr, "%s: %s: cannot %scompress onto itself\n",
1662                     progname, ifname, decompress ? "de" : "");
1663         } else {
1664             fprintf(stderr, "%s: %s and %s are the same file\n",
1665                     progname, ifname, ofname);
1666         }
1667         exit_code = ERROR;
1668         return ERROR;
1669     }
1670     /* Ask permission to overwrite the existing file */
1671     if (!force) {
1672         int ok = 0;
1673         fprintf(stderr, "%s: %s already exists;", progname, ofname);
1674         if (foreground && isatty(fileno(stdin))) {
1675             fprintf(stderr, " do you wish to overwrite (y or n)? ");
1676             fflush(stderr);
1677             ok = yesno();
1678         }
1679         if (!ok) {
1680             fprintf(stderr, "\tnot overwritten\n");
1681             if (exit_code == OK) exit_code = WARNING;
1682             return ERROR;
1683         }
1684     }
1685     if (xunlink (ofname)) {
1686         progerror(ofname);
1687         return ERROR;
1688     }
1689     return OK;
1690 }
1691
1692
1693 #ifndef NO_UTIME
1694 /* ========================================================================
1695  * Set the access and modification times from the given stat buffer.
1696  */
1697 local void reset_times (name, statb)
1698     char *name;
1699     struct stat *statb;
1700 {
1701     struct utimbuf      timep;
1702
1703     /* Copy the time stamp */
1704     timep.actime  = statb->st_atime;
1705     timep.modtime = statb->st_mtime;
1706
1707     /* Some systems (at least OS/2) do not support utime on directories */
1708     if (utime(name, &timep) && !S_ISDIR(statb->st_mode)) {
1709         int e = errno;
1710         WARN((stderr, "%s: ", progname));
1711         if (!quiet) {
1712             errno = e;
1713             perror(ofname);
1714         }
1715     }
1716 }
1717 #endif
1718
1719
1720 /* ========================================================================
1721  * Copy modes, times, ownership from input file to output file.
1722  * IN assertion: to_stdout is false.
1723  */
1724 local void copy_stat(ifstat)
1725     struct stat *ifstat;
1726 {
1727 #ifndef NO_UTIME
1728     if (decompress && time_stamp != 0 && ifstat->st_mtime != time_stamp) {
1729         ifstat->st_mtime = time_stamp;
1730         if (verbose > 1) {
1731             fprintf(stderr, "%s: time stamp restored\n", ofname);
1732         }
1733     }
1734     reset_times(ofname, ifstat);
1735 #endif
1736     /* Copy the protection modes */
1737     if (fchmod(ofd, ifstat->st_mode & 07777)) {
1738         int e = errno;
1739         WARN((stderr, "%s: ", progname));
1740         if (!quiet) {
1741             errno = e;
1742             perror(ofname);
1743         }
1744     }
1745 #ifndef NO_CHOWN
1746     fchown(ofd, ifstat->st_uid, ifstat->st_gid);  /* Copy ownership */
1747 #endif
1748     remove_ofname = 0;
1749     /* It's now safe to remove the input file: */
1750     if (xunlink (ifname)) {
1751         int e = errno;
1752         WARN((stderr, "%s: ", progname));
1753         if (!quiet) {
1754             errno = e;
1755             perror(ifname);
1756         }
1757     }
1758 }
1759
1760 #if ! NO_DIR
1761
1762 /* ========================================================================
1763  * Recurse through the given directory. This code is taken from ncompress.
1764  */
1765 local void treat_dir(dir)
1766     char *dir;
1767 {
1768     struct dirent *dp;
1769     DIR      *dirp;
1770     char     nbuf[MAX_PATH_LEN];
1771     int      len;
1772
1773     dirp = opendir(dir);
1774     
1775     if (dirp == NULL) {
1776         progerror(dir);
1777         return ;
1778     }
1779     /*
1780      ** WARNING: the following algorithm could occasionally cause
1781      ** compress to produce error warnings of the form "<filename>.gz
1782      ** already has .gz suffix - ignored". This occurs when the
1783      ** .gz output file is inserted into the directory below
1784      ** readdir's current pointer.
1785      ** These warnings are harmless but annoying, so they are suppressed
1786      ** with option -r (except when -v is on). An alternative
1787      ** to allowing this would be to store the entire directory
1788      ** list in memory, then compress the entries in the stored
1789      ** list. Given the depth-first recursive algorithm used here,
1790      ** this could use up a tremendous amount of memory. I don't
1791      ** think it's worth it. -- Dave Mack
1792      ** (An other alternative might be two passes to avoid depth-first.)
1793      */
1794     
1795     while ((errno = 0, dp = readdir(dirp)) != NULL) {
1796
1797         if (strequ(dp->d_name,".") || strequ(dp->d_name,"..")) {
1798             continue;
1799         }
1800         len = strlen(dir);
1801         if (len + NAMLEN(dp) + 1 < MAX_PATH_LEN - 1) {
1802             strcpy(nbuf,dir);
1803             if (len != 0 /* dir = "" means current dir on Amiga */
1804 #ifdef PATH_SEP2
1805                 && dir[len-1] != PATH_SEP2
1806 #endif
1807 #ifdef PATH_SEP3
1808                 && dir[len-1] != PATH_SEP3
1809 #endif
1810             ) {
1811                 nbuf[len++] = PATH_SEP;
1812             }
1813             strcpy(nbuf+len, dp->d_name);
1814             treat_file(nbuf);
1815         } else {
1816             fprintf(stderr,"%s: %s/%s: pathname too long\n",
1817                     progname, dir, dp->d_name);
1818             exit_code = ERROR;
1819         }
1820     }
1821     if (errno != 0)
1822         progerror(dir);
1823     if (CLOSEDIR(dirp) != 0)
1824         progerror(dir);
1825 }
1826 #endif /* ! NO_DIR */
1827
1828 /* ========================================================================
1829  * Free all dynamically allocated variables and exit with the given code.
1830  */
1831 local void do_exit(exitcode)
1832     int exitcode;
1833 {
1834     static int in_exit = 0;
1835
1836     if (in_exit) exit(exitcode);
1837     in_exit = 1;
1838     if (env != NULL)  free(env),  env  = NULL;
1839     if (args != NULL) free((char*)args), args = NULL;
1840     FREE(inbuf);
1841     FREE(outbuf);
1842     FREE(d_buf);
1843     FREE(window);
1844 #ifndef MAXSEG_64K
1845     FREE(tab_prefix);
1846 #else
1847     FREE(tab_prefix0);
1848     FREE(tab_prefix1);
1849 #endif
1850     exit(exitcode);
1851 }
1852
1853 /* ========================================================================
1854  * Close and unlink the output file if appropriate.  This routine must be
1855  * async-signal-safe.
1856  */
1857 local void do_remove() {
1858    if (remove_ofname) {
1859        close(ofd);
1860        xunlink (ofname);
1861    }
1862 }
1863
1864 /* ========================================================================
1865  * Error handler.
1866  */
1867 RETSIGTYPE abort_gzip()
1868 {
1869         do_remove();
1870         do_exit(ERROR);
1871 }
1872
1873 /* ========================================================================
1874  * Signal handler.
1875  */
1876 RETSIGTYPE abort_gzip_signal()
1877 {
1878         do_remove();
1879         _exit(ERROR);
1880 }
1881