maint: depend on Gnulib's limits-h
[gzip.git] / gzip.c
blob5cd1586ab20f788b649d41ee1ccbe119ceb0a8b0
1 /* gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
3 Copyright (C) 1999, 2001-2002, 2006-2007, 2009-2024 Free Software
4 Foundation, Inc.
5 Copyright (C) 1992-1993 Jean-loup Gailly
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software Foundation,
19 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
22 * The unzip code was written and put in the public domain by Mark Adler.
23 * Portions of the lzw code are derived from the public domain 'compress'
24 * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies,
25 * Ken Turkowski, Dave Mack and Peter Jannesen.
27 * See the license_msg below and the file COPYING for the software license.
28 * See the file algorithm.doc for the compression algorithms and file formats.
31 static char const *const license_msg[] = {
32 "Copyright (C) 2024 Free Software Foundation, Inc.",
33 "Copyright (C) 1993 Jean-loup Gailly.",
34 "This is free software. You may redistribute copies of it under the terms of",
35 "the GNU General Public License <https://www.gnu.org/licenses/gpl.html>.",
36 "There is NO WARRANTY, to the extent permitted by law.",
37 0};
39 /* Compress files with zip algorithm and 'compress' interface.
40 * See help() function below for all options.
41 * Outputs:
42 * file.gz: compressed file with same mode, owner, and utimes
43 * or stdout with -c option or if stdin used as input.
44 * If the output file name had to be truncated, the original name is kept
45 * in the compressed file.
46 * On MSDOS, file.tmp -> file.tmz.
48 * Using gz on MSDOS would create too many file name conflicts. For
49 * example, foo.txt -> foo.tgz (.tgz must be reserved as shorthand for
50 * tar.gz). Similarly, foo.dir and foo.doc would both be mapped to foo.dgz.
51 * I also considered 12345678.txt -> 12345txt.gz but this truncates the name
52 * too heavily. There is no ideal solution given the MSDOS 8+3 limitation.
54 * For the meaning of all compilation flags, see comments in Makefile.in.
57 #include <config.h>
58 #include <ctype.h>
59 #include <sys/types.h>
60 #include <signal.h>
61 #include <stddef.h>
62 #include <sys/stat.h>
63 #include <getopt.h>
64 #include <errno.h>
66 #include "tailor.h"
67 #include "gzip.h"
68 #include "intprops.h"
69 #include "lzw.h"
70 #include "revision.h"
71 #include "timespec.h"
73 #include "dirname.h"
74 #include "fcntl--.h"
75 #include "filename.h"
76 #include "ignore-value.h"
77 #include "stat-time.h"
78 #include "version.h"
79 #include "xalloc.h"
80 #include "yesno.h"
82 /* configuration */
84 #include <limits.h>
85 #include <inttypes.h>
86 #include <unistd.h>
87 #include <stdlib.h>
89 #ifndef NO_DIR
90 # define NO_DIR 0
91 #endif
92 #if !NO_DIR
93 # include <dirent.h>
94 # include <savedir.h>
95 #endif
97 #ifndef NO_UTIME
98 # include <utimens.h>
99 #endif
101 #ifndef MAX_PATH_LEN
102 # define MAX_PATH_LEN 1024 /* max pathname length */
103 #endif
105 #ifndef SEEK_END
106 # define SEEK_END 2
107 #endif
109 #ifdef off_t
110 off_t lseek (int fd, off_t offset, int whence);
111 #endif
113 #ifndef HAVE_WORKING_O_NOFOLLOW
114 # define HAVE_WORKING_O_NOFOLLOW 0
115 #endif
117 /* Separator for file name parts (see shorten_name()) */
118 #ifdef NO_MULTIPLE_DOTS
119 # define PART_SEP "-"
120 #else
121 # define PART_SEP "."
122 #endif
124 /* global buffers */
126 /* With IBM_Z_DFLTCC, DEFLATE COMPRESSION works faster with
127 page-aligned input and output buffers, and requires page-aligned
128 windows; the alignment requirement is 4096. On other platforms
129 alignment doesn't hurt, and alignment up to 4096 is portable so
130 let's do that. */
131 #if defined HAVE_C_ALIGNASOF || defined alignas
132 # define BUFFER_ALIGNED alignas (4096)
133 #else
134 # define BUFFER_ALIGNED /**/
135 #endif
136 DECLARE(uch BUFFER_ALIGNED, inbuf, INBUFSIZ +INBUF_EXTRA);
137 DECLARE(uch BUFFER_ALIGNED, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
138 DECLARE(ush, d_buf, DIST_BUFSIZE);
139 DECLARE(uch BUFFER_ALIGNED, window, 2L*WSIZE);
140 #ifndef MAXSEG_64K
141 DECLARE(ush, tab_prefix, 1L<<BITS);
142 #else
143 DECLARE(ush, tab_prefix0, 1L<<(BITS-1));
144 DECLARE(ush, tab_prefix1, 1L<<(BITS-1));
145 #endif
147 /* local variables */
149 /* If true, pretend that standard input is a tty. This option
150 is deliberately not documented, and only for testing. */
151 static bool presume_input_tty;
153 /* If true, transfer output data to the output file's storage device
154 when supported. Otherwise, if the system crashes around the time
155 gzip is run, the user might lose both input and output data. See:
156 Pillai TS et al. All file systems are not created equal: on the
157 complexity of crafting crash-consistent applications. OSDI'14. 2014:433-48.
158 https://www.usenix.org/conference/osdi14/technical-sessions/presentation/pillai */
159 static bool synchronous;
161 static int ascii = 0; /* convert end-of-lines to local OS conventions */
162 int to_stdout = 0; /* output to stdout (-c) */
163 static int decompress = 0; /* decompress (-d) */
164 static int force = 0; /* don't ask questions, compress links (-f) */
165 static int keep = 0; /* keep (don't delete) input files */
166 static int no_name = -1; /* don't save or restore the original file name */
167 static int no_time = -1; /* don't save or restore the original file time */
168 static int recursive = 0; /* recurse through directories (-r) */
169 static int list = 0; /* list the file contents (-l) */
170 #ifndef DEBUG
171 static
172 #endif
173 int verbose = 0; /* be verbose (-v) */
174 int quiet = 0; /* be very quiet (-q) */
175 int test = 0; /* test .gz file integrity */
176 static int foreground = 0; /* set if program run in foreground */
177 char *program_name; /* program name */
178 int maxbits = BITS; /* max bits per code for LZW */
179 int method = DEFLATED;/* compression method */
180 int level = 6; /* compression level */
181 int exit_code = OK; /* program exit code */
182 int save_orig_name; /* set if original name must be saved */
183 static int last_member; /* set for .zip and .Z files */
184 static int part_nb; /* number of parts in .gz file */
185 off_t ifile_size; /* input file size, -1 for devices (debug only) */
186 static char *env; /* contents of GZIP env variable */
187 static char const *z_suffix; /* default suffix (can be set with --suffix) */
188 static size_t z_len; /* strlen(z_suffix) */
190 /* The original timestamp (modification time). If the original is
191 unknown, TIME_STAMP.tv_nsec is negative. If the original is
192 greater than struct timespec range, TIME_STAMP is the maximal
193 struct timespec value; this can happen on hosts with 32-bit signed
194 time_t because the gzip format's MTIME is 32-bit unsigned.
195 The original cannot be less than struct timespec range. */
196 struct timespec time_stamp;
198 /* The set of signals that are caught. */
199 static sigset_t caught_signals;
201 /* If nonnegative, close this file descriptor and unlink remove_ofname
202 on error. */
203 static int volatile remove_ofname_fd = -1;
204 static char volatile remove_ofname[MAX_PATH_LEN];
206 static bool stdin_was_read;
208 off_t bytes_in; /* number of input bytes */
209 off_t bytes_out; /* number of output bytes */
210 static off_t total_in; /* input bytes for all files */
211 static off_t total_out; /* output bytes for all files */
212 char ifname[MAX_PATH_LEN]; /* input file name */
213 char ofname[MAX_PATH_LEN]; /* output file name */
214 static char dfname[MAX_PATH_LEN]; /* name of dir containing output file */
215 static struct stat istat; /* status for input file */
216 int ifd; /* input file descriptor */
217 int ofd; /* output file descriptor */
218 static int dfd = -1; /* output directory file descriptor */
219 unsigned insize; /* valid bytes in inbuf */
220 unsigned inptr; /* index of next byte to be processed in inbuf */
221 unsigned outcnt; /* bytes in output buffer */
222 int rsync = 0; /* make rsyncable chunks */
224 static int handled_sig[] =
226 /* SIGINT must be first, as 'foreground' depends on it. */
227 SIGINT
229 #ifdef SIGHUP
230 , SIGHUP
231 #endif
232 #if SIGPIPE
233 , SIGPIPE
234 #endif
235 #ifdef SIGTERM
236 , SIGTERM
237 #endif
238 #ifdef SIGXCPU
239 , SIGXCPU
240 #endif
241 #ifdef SIGXFSZ
242 , SIGXFSZ
243 #endif
246 /* For long options that have no equivalent short option, use a
247 non-character as a pseudo short option, starting with CHAR_MAX + 1. */
248 enum
250 PRESUME_INPUT_TTY_OPTION = CHAR_MAX + 1,
251 RSYNCABLE_OPTION,
252 SYNCHRONOUS_OPTION,
254 /* A value greater than all valid long options, used as a flag to
255 distinguish options derived from the GZIP environment variable. */
256 ENV_OPTION
259 static char const shortopts[] = "ab:cdfhH?klLmMnNqrS:tvVZ123456789";
261 static const struct option longopts[] =
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 {"keep", 0, 0, 'k'}, /* keep (don't delete) input files */
274 {"list", 0, 0, 'l'}, /* list .gz file contents */
275 {"license", 0, 0, 'L'}, /* display software license */
276 {"no-name", 0, 0, 'n'}, /* don't save or restore original name & time */
277 {"name", 0, 0, 'N'}, /* save or restore original name & time */
278 {"-presume-input-tty", no_argument, NULL, PRESUME_INPUT_TTY_OPTION},
279 {"quiet", 0, 0, 'q'}, /* quiet mode */
280 {"silent", 0, 0, 'q'}, /* quiet mode */
281 {"synchronous",0, 0, SYNCHRONOUS_OPTION},
282 {"recursive", 0, 0, 'r'}, /* recurse through directories */
283 {"suffix", 1, 0, 'S'}, /* use given suffix instead of .gz */
284 {"test", 0, 0, 't'}, /* test compressed file integrity */
285 {"verbose", 0, 0, 'v'}, /* verbose mode */
286 {"version", 0, 0, 'V'}, /* display version number */
287 {"fast", 0, 0, '1'}, /* compress faster */
288 {"best", 0, 0, '9'}, /* compress better */
289 {"lzw", 0, 0, 'Z'}, /* make output compatible with old compress */
290 {"bits", 1, 0, 'b'}, /* max number of bits per code (implies -Z) */
291 {"rsyncable", 0, 0, RSYNCABLE_OPTION}, /* make rsync-friendly archive */
292 { 0, 0, 0, 0 }
295 /* local functions */
297 _Noreturn static void try_help (void);
298 static void help (void);
299 static void license (void);
300 static void version (void);
301 static int input_eof (void);
302 static void treat_stdin (void);
303 static void treat_file (char *iname);
304 static int create_outfile (void);
305 static char *get_suffix (char *name);
306 static int open_input_file (char *iname, struct stat *sbuf);
307 static void discard_input_bytes (size_t nbytes, unsigned int flags);
308 static int make_ofname (void);
309 static void shorten_name (char *name);
310 static int get_method (int in);
311 static void do_list (int method);
312 static int check_ofname (void);
313 static void copy_stat (struct stat *ifstat);
314 static void install_signal_handlers (void);
315 static void remove_output_file (bool);
316 static void abort_gzip_signal (int);
317 _Noreturn static void do_exit (int exitcode);
318 static void finish_out (void);
319 int main (int argc, char **argv);
320 static int (*work) (int infile, int outfile) = zip; /* function to call */
322 #if ! NO_DIR
323 static void treat_dir (int fd, char *dir);
324 #endif
326 #define strequ(s1, s2) (strcmp((s1),(s2)) == 0)
328 static void
329 try_help ()
331 fprintf (stderr, "Try `%s --help' for more information.\n",
332 program_name);
333 do_exit (ERROR);
336 /* ======================================================================== */
337 static void
338 help ()
340 static char const* const help_msg[] = {
341 "Compress or uncompress FILEs (by default, compress FILES in-place).",
343 "Mandatory arguments to long options are mandatory for short options too.",
345 #if O_BINARY
346 " -a, --ascii ascii text; convert end-of-line using local conventions",
347 #endif
348 " -c, --stdout write on standard output, keep original files unchanged",
349 " -d, --decompress decompress",
350 /* -e, --encrypt encrypt */
351 " -f, --force force overwrite of output file and compress links",
352 " -h, --help give this help",
353 /* -k, --pkzip force output in pkzip format */
354 " -k, --keep keep (don't delete) input files",
355 " -l, --list list compressed file contents",
356 " -L, --license display software license",
357 #ifdef UNDOCUMENTED
358 " -m do not save or restore the original modification time",
359 " -M, --time save or restore the original modification time",
360 #endif
361 " -n, --no-name do not save or restore the original name and timestamp",
362 " -N, --name save or restore the original name and timestamp",
363 " -q, --quiet suppress all warnings",
364 #if ! NO_DIR
365 " -r, --recursive operate recursively on directories",
366 #endif
367 " --rsyncable make rsync-friendly archive",
368 " -S, --suffix=SUF use suffix SUF on compressed files",
369 " --synchronous synchronous output (safer if system crashes, but slower)",
370 " -t, --test test compressed file integrity",
371 " -v, --verbose verbose mode",
372 " -V, --version display version number",
373 " -1, --fast compress faster",
374 " -9, --best compress better",
376 "With no FILE, or when FILE is -, read standard input.",
378 "Report bugs to <bug-gzip@gnu.org>.",
380 char const *const *p = help_msg;
382 printf ("Usage: %s [OPTION]... [FILE]...\n", program_name);
383 while (*p) printf ("%s\n", *p++);
386 /* ======================================================================== */
387 static void
388 license ()
390 char const *const *p = license_msg;
392 printf ("%s %s\n", program_name, Version);
393 while (*p) printf ("%s\n", *p++);
396 /* ======================================================================== */
397 static void
398 version ()
400 license ();
401 printf ("\n");
402 printf ("Written by Jean-loup Gailly.\n");
405 static void
406 progerror (char const *string)
408 fprintf (stderr, "%s: %s: %s\n", program_name, string, strerror (errno));
409 exit_code = ERROR;
412 /* ======================================================================== */
413 int main (int argc, char **argv)
415 int file_count; /* number of files to process */
416 size_t proglen; /* length of program_name */
417 char **argv_copy;
418 int env_argc;
419 char **env_argv;
421 EXPAND(argc, argv); /* wild card expansion if necessary */
423 program_name = gzip_base_name (argv[0]);
424 proglen = strlen (program_name);
426 /* Suppress .exe for MSDOS and OS/2: */
427 if (4 < proglen && strequ (program_name + proglen - 4, ".exe"))
428 program_name[proglen - 4] = '\0';
430 /* Add options in GZIP environment variable if there is one */
431 argv_copy = argv;
432 env = add_envopt (&env_argc, &argv_copy, OPTIONS_VAR);
433 env_argv = env ? argv_copy : NULL;
435 #ifndef GNU_STANDARD
436 # define GNU_STANDARD 1
437 #endif
438 #if !GNU_STANDARD
439 /* For compatibility with old compress, use program name as an option.
440 * Unless you compile with -DGNU_STANDARD=0, this program will behave as
441 * gzip even if it is invoked under the name gunzip or zcat.
443 * Systems which do not support links can still use -d or -dc.
444 * Ignore an .exe extension for MSDOS and OS/2.
446 if (strncmp (program_name, "un", 2) == 0 /* ungzip, uncompress */
447 || strncmp (program_name, "gun", 3) == 0) /* gunzip */
448 decompress = 1;
449 else if (strequ (program_name + 1, "cat") /* zcat, pcat, gcat */
450 || strequ (program_name, "gzcat")) /* gzcat */
451 decompress = to_stdout = 1;
452 #endif
454 z_suffix = Z_SUFFIX;
455 z_len = strlen(z_suffix);
457 while (true) {
458 int optc;
459 int longind = -1;
461 if (env_argv)
463 if (env_argv[optind] && strequ (env_argv[optind], "--"))
464 optc = ENV_OPTION + '-';
465 else
467 optc = getopt_long (env_argc, env_argv, shortopts, longopts,
468 &longind);
469 if (0 <= optc)
470 optc += ENV_OPTION;
471 else
473 if (optind != env_argc)
475 fprintf (stderr,
476 ("%s: %s: non-option in "OPTIONS_VAR
477 " environment variable\n"),
478 program_name, env_argv[optind]);
479 try_help ();
482 /* Wait until here before warning, so that GZIP='-q'
483 doesn't warn. */
484 if (env_argc != 1 && !quiet)
485 fprintf (stderr,
486 ("%s: warning: "OPTIONS_VAR" environment variable"
487 " is deprecated; use an alias or script\n"),
488 program_name);
490 /* Start processing ARGC and ARGV instead. */
491 free (env_argv);
492 env_argv = NULL;
493 optind = 1;
494 longind = -1;
499 if (!env_argv)
500 optc = getopt_long (argc, argv, shortopts, longopts, &longind);
501 if (optc < 0)
502 break;
504 switch (optc) {
505 case 'a':
506 ascii = 1; break;
507 case 'b':
508 maxbits = atoi(optarg);
509 for (; *optarg; optarg++)
510 if (! ('0' <= *optarg && *optarg <= '9'))
512 fprintf (stderr, "%s: -b operand is not an integer\n",
513 program_name);
514 try_help ();
516 break;
517 case 'c':
518 to_stdout = 1; break;
519 case 'd':
520 decompress = 1; break;
521 case 'f':
522 force++; break;
523 case 'h': case 'H':
524 help (); finish_out (); break;
525 case 'k':
526 keep = 1; break;
527 case 'l':
528 list = decompress = test = to_stdout = 1; break;
529 case 'L':
530 license (); finish_out (); 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 case 'n' + ENV_OPTION:
537 no_name = no_time = 1; break;
538 case 'N':
539 case 'N' + ENV_OPTION:
540 no_name = no_time = 0; break;
541 case PRESUME_INPUT_TTY_OPTION:
542 presume_input_tty = true; break;
543 case 'q':
544 case 'q' + ENV_OPTION:
545 quiet = 1; verbose = 0; break;
546 case 'r':
547 #if NO_DIR
548 fprintf (stderr, "%s: -r not supported on this system\n",
549 program_name);
550 try_help ();
551 #else
552 recursive = 1;
553 #endif
554 break;
556 case RSYNCABLE_OPTION:
557 case RSYNCABLE_OPTION + ENV_OPTION:
558 rsync = 1;
559 break;
560 case 'S':
561 #ifdef NO_MULTIPLE_DOTS
562 if (*optarg == '.') optarg++;
563 #endif
564 for (z_len = 0; optarg[z_len]; z_len++)
565 if (optarg[z_len] == '/')
567 fprintf (stderr, "%s: suffix contains '/'\n", program_name);
568 do_exit (ERROR);
570 z_suffix = optarg;
571 break;
572 case SYNCHRONOUS_OPTION:
573 synchronous = true;
574 break;
575 case 't':
576 test = decompress = to_stdout = 1;
577 break;
578 case 'v':
579 case 'v' + ENV_OPTION:
580 verbose++; quiet = 0; break;
581 case 'V':
582 version (); finish_out (); break;
583 case 'Z':
584 fprintf(stderr, "%s: -Z not supported in this version\n",
585 program_name);
586 try_help ();
587 break;
588 case '1' + ENV_OPTION: case '2' + ENV_OPTION: case '3' + ENV_OPTION:
589 case '4' + ENV_OPTION: case '5' + ENV_OPTION: case '6' + ENV_OPTION:
590 case '7' + ENV_OPTION: case '8' + ENV_OPTION: case '9' + ENV_OPTION:
591 optc -= ENV_OPTION;
592 FALLTHROUGH;
593 case '1': case '2': case '3': case '4':
594 case '5': case '6': case '7': case '8': case '9':
595 level = optc - '0';
596 break;
598 default:
599 if (ENV_OPTION <= optc && optc != ENV_OPTION + '?')
601 /* Output a diagnostic, since getopt_long didn't. */
602 fprintf (stderr, "%s: ", program_name);
603 if (longind < 0)
604 fprintf (stderr, "-%c: ", optc - ENV_OPTION);
605 else
606 fprintf (stderr, "--%s: ", longopts[longind].name);
607 fprintf (stderr, ("option not valid in "OPTIONS_VAR
608 " environment variable\n"));
610 try_help ();
612 } /* loop on all arguments */
614 /* By default, save name and timestamp on compression but do not
615 * restore them on decompression.
617 if (no_time < 0) no_time = decompress;
618 if (no_name < 0) no_name = decompress;
620 file_count = argc - optind;
622 #if O_BINARY
623 #else
624 if (ascii && !quiet) {
625 fprintf(stderr, "%s: option --ascii ignored on this system\n",
626 program_name);
628 #endif
629 if (z_len == 0 || z_len > MAX_SUFFIX) {
630 fprintf(stderr, "%s: invalid suffix '%s'\n", program_name, z_suffix);
631 do_exit(ERROR);
634 /* Allocate all global buffers (for DYN_ALLOC option) */
635 ALLOC(uch, inbuf, INBUFSIZ +INBUF_EXTRA);
636 ALLOC(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
637 ALLOC(ush, d_buf, DIST_BUFSIZE);
638 ALLOC(uch, window, 2L*WSIZE);
639 #ifndef MAXSEG_64K
640 ALLOC(ush, tab_prefix, 1L<<BITS);
641 #else
642 ALLOC(ush, tab_prefix0, 1L<<(BITS-1));
643 ALLOC(ush, tab_prefix1, 1L<<(BITS-1));
644 #endif
646 /* And get to work */
647 if (file_count != 0) {
648 if (to_stdout && !test && (!decompress || !ascii)) {
649 SET_BINARY_MODE (STDOUT_FILENO);
651 while (optind < argc) {
652 treat_file(argv[optind++]);
654 } else { /* Standard input */
655 treat_stdin();
657 if (stdin_was_read && close (STDIN_FILENO) != 0)
659 strcpy (ifname, "stdin");
660 read_error ();
662 if (list)
664 /* Output any totals, and check for output errors. */
665 if (!quiet && 1 < file_count)
666 do_list (-1);
667 if (fflush (stdout) != 0)
668 write_error ();
670 if (to_stdout
671 && ((synchronous
672 && fdatasync (STDOUT_FILENO) != 0 && errno != EINVAL)
673 || close (STDOUT_FILENO) != 0)
674 && errno != EBADF)
675 write_error ();
676 do_exit(exit_code);
679 /* Return nonzero when at end of file on input. */
680 static int
681 input_eof ()
683 if (!decompress || last_member)
684 return 1;
686 if (inptr == insize)
688 if (insize != INBUFSIZ || fill_inbuf (1) == EOF)
689 return 1;
691 /* Unget the char that fill_inbuf got. */
692 inptr = 0;
695 return 0;
698 static void
699 get_input_size_and_time (void)
701 ifile_size = -1;
702 time_stamp.tv_nsec = -1;
704 /* Record the input file's size and timestamp only if it is a
705 regular file. Doing this for the timestamp helps to keep gzip's
706 output more reproducible when it is used as part of a
707 pipeline. */
709 if (S_ISREG (istat.st_mode))
711 ifile_size = istat.st_size;
712 if (!no_time || list)
713 time_stamp = get_stat_mtime (&istat);
717 /* ========================================================================
718 * Compress or decompress stdin
720 static void
721 treat_stdin ()
723 if (!force && !list
724 && (presume_input_tty
725 || isatty (decompress ? STDIN_FILENO : STDOUT_FILENO))) {
726 /* Do not send compressed data to the terminal or read it from
727 * the terminal. We get here when user invoked the program
728 * without parameters, so be helpful. According to the GNU standards:
730 * If there is one behavior you think is most useful when the output
731 * is to a terminal, and another that you think is most useful when
732 * the output is a file or a pipe, then it is usually best to make
733 * the default behavior the one that is useful with output to a
734 * terminal, and have an option for the other behavior.
736 * Here we use the --force option to get the other behavior.
738 if (! quiet)
739 fprintf (stderr,
740 ("%s: compressed data not %s a terminal."
741 " Use -f to force %scompression.\n"
742 "For help, type: %s -h\n"),
743 program_name,
744 decompress ? "read from" : "written to",
745 decompress ? "de" : "",
746 program_name);
747 do_exit(ERROR);
750 if (decompress || !ascii) {
751 SET_BINARY_MODE (STDIN_FILENO);
753 if (!test && (!decompress || !ascii)) {
754 SET_BINARY_MODE (STDOUT_FILENO);
756 strcpy(ifname, "stdin");
757 strcpy(ofname, "stdout");
759 /* Get the file's timestamp and size. */
760 if (fstat (STDIN_FILENO, &istat) != 0)
762 progerror ("standard input");
763 do_exit (ERROR);
766 get_input_size_and_time ();
768 clear_bufs(); /* clear input and output buffers */
769 to_stdout = 1;
770 part_nb = 0;
771 ifd = STDIN_FILENO;
772 stdin_was_read = true;
774 if (decompress) {
775 method = get_method(ifd);
776 if (method < 0) {
777 do_exit(exit_code); /* error message already emitted */
781 /* Actually do the compression/decompression. Loop over zipped members.
783 for (;;) {
784 if (work (STDIN_FILENO, STDOUT_FILENO) != OK)
785 return;
787 if (input_eof ())
788 break;
790 method = get_method(ifd);
791 if (method < 0) return; /* error message already emitted */
794 if (list)
796 do_list (method);
797 return;
800 if (verbose) {
801 if (test) {
802 fprintf(stderr, " OK\n");
804 } else if (!decompress) {
805 display_ratio(bytes_in-(bytes_out-header_bytes), bytes_in, stderr);
806 fprintf(stderr, "\n");
807 #ifdef DISPLAY_STDIN_RATIO
808 } else {
809 display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out,stderr);
810 fprintf(stderr, "\n");
811 #endif
816 static char const dot = '.';
818 /* True if the cached directory for calls to openat etc. is DIR, with
819 length DIRLEN. DIR need not be null-terminated. DIRLEN must be
820 less than MAX_PATH_LEN. */
821 static bool
822 atdir_eq (char const *dir, ptrdiff_t dirlen)
824 if (dirlen == 0)
825 dir = &dot, dirlen = 1;
826 return memcmp (dfname, dir, dirlen) == 0 && !dfname[dirlen];
829 /* Set the directory used for calls to openat etc. to be the directory
830 DIR, with length DIRLEN. DIR need not be null-terminated.
831 DIRLEN must be less than MAX_PATH_LEN. Return a file descriptor for
832 the directory, or -1 if one could not be obtained. */
833 static int
834 atdir_set (char const *dir, ptrdiff_t dirlen)
836 /* Don't bother opening directories on older systems that
837 lack openat and unlinkat. It's not worth the porting hassle. */
838 #if HAVE_OPENAT && HAVE_UNLINKAT
839 enum { try_opening_directories = true };
840 #else
841 enum { try_opening_directories = false };
842 #endif
844 if (try_opening_directories && ! atdir_eq (dir, dirlen))
846 if (0 <= dfd)
847 close (dfd);
848 if (dirlen == 0)
849 dir = &dot, dirlen = 1;
850 memcpy (dfname, dir, dirlen);
851 dfname[dirlen] = '\0';
852 dfd = open (dfname, O_SEARCH | O_DIRECTORY);
855 return dfd;
858 /* ========================================================================
859 * Compress or decompress the given file
861 static void
862 treat_file (char *iname)
864 /* Accept "-" as synonym for stdin */
865 if (strequ(iname, "-")) {
866 int cflag = to_stdout;
867 treat_stdin();
868 to_stdout = cflag;
869 return;
872 /* Check if the input file is present, set ifname and istat: */
873 ifd = open_input_file (iname, &istat);
874 if (ifd < 0)
875 return;
877 /* If the input name is that of a directory, recurse or ignore: */
878 if (S_ISDIR(istat.st_mode)) {
879 #if ! NO_DIR
880 if (recursive) {
881 treat_dir (ifd, iname);
882 /* Warning: ifname is now garbage */
883 return;
885 #endif
886 close (ifd);
887 WARN ((stderr, "%s: %s is a directory -- ignored\n",
888 program_name, ifname));
889 return;
892 if (! to_stdout)
894 if (! S_ISREG (istat.st_mode))
896 WARN ((stderr,
897 "%s: %s is not a directory or a regular file - ignored\n",
898 program_name, ifname));
899 close (ifd);
900 return;
902 if (istat.st_mode & S_ISUID)
904 WARN ((stderr, "%s: %s is set-user-ID on execution - ignored\n",
905 program_name, ifname));
906 close (ifd);
907 return;
909 if (istat.st_mode & S_ISGID)
911 WARN ((stderr, "%s: %s is set-group-ID on execution - ignored\n",
912 program_name, ifname));
913 close (ifd);
914 return;
917 if (! force)
919 if (istat.st_mode & S_ISVTX)
921 WARN ((stderr,
922 "%s: %s has the sticky bit set - file ignored\n",
923 program_name, ifname));
924 close (ifd);
925 return;
927 if (2 <= istat.st_nlink)
929 WARN ((stderr, "%s: %s has %lu other link%s -- file ignored\n",
930 program_name, ifname,
931 (unsigned long int) istat.st_nlink - 1,
932 istat.st_nlink == 2 ? "" : "s"));
933 close (ifd);
934 return;
939 get_input_size_and_time ();
941 /* Generate output file name. For -r and (-t or -l), skip files
942 * without a valid gzip suffix (check done in make_ofname).
944 if (to_stdout && !test) {
945 strcpy(ofname, "stdout");
947 } else if (make_ofname() != OK) {
948 close (ifd);
949 return;
952 clear_bufs(); /* clear input and output buffers */
953 part_nb = 0;
955 if (decompress) {
956 method = get_method(ifd); /* updates ofname if original given */
957 if (method < 0) {
958 close(ifd);
959 return; /* error message already emitted */
963 /* If compressing to a file, check if ofname is not ambiguous
964 * because the operating system truncates names. Otherwise, generate
965 * a new ofname and save the original name in the compressed file.
967 if (to_stdout) {
968 ofd = STDOUT_FILENO;
969 /* Keep remove_ofname_fd negative. */
970 } else {
971 if (create_outfile() != OK) return;
973 if (!decompress && save_orig_name && !verbose && !quiet) {
974 fprintf(stderr, "%s: %s compressed to %s\n",
975 program_name, ifname, ofname);
978 /* Keep the name even if not truncated except with --no-name: */
979 if (!save_orig_name) save_orig_name = !no_name;
981 if (verbose && !list) {
982 fprintf(stderr, "%s:\t", ifname);
985 /* Actually do the compression/decompression. Loop over zipped members.
987 for (;;) {
988 if ((*work)(ifd, ofd) != OK) {
989 method = -1; /* force cleanup */
990 break;
993 if (input_eof ())
994 break;
996 method = get_method(ifd);
997 if (method < 0) break; /* error message already emitted */
1000 if (close (ifd) != 0)
1001 read_error ();
1003 if (list)
1005 do_list (method);
1006 return;
1009 if (!to_stdout)
1011 copy_stat (&istat);
1013 if ((synchronous
1014 && ((0 <= dfd && fdatasync (dfd) != 0 && errno != EINVAL)
1015 || (fsync (ofd) != 0 && errno != EINVAL)))
1016 || close (ofd) != 0)
1017 write_error ();
1019 if (!keep)
1021 sigset_t oldset;
1022 int unlink_errno;
1023 char *ifbase = last_component (ifname);
1024 int ufd = atdir_eq (ifname, ifbase - ifname) ? dfd : -1;
1025 int res;
1027 sigprocmask (SIG_BLOCK, &caught_signals, &oldset);
1028 remove_ofname_fd = -1;
1029 res = ufd < 0 ? xunlink (ifname) : unlinkat (ufd, ifbase, 0);
1030 unlink_errno = res == 0 ? 0 : errno;
1031 sigprocmask (SIG_SETMASK, &oldset, NULL);
1033 if (unlink_errno)
1034 WARN ((stderr, "%s: %s: %s\n", program_name, ifname,
1035 strerror (unlink_errno)));
1039 if (method == -1) {
1040 if (!to_stdout)
1041 remove_output_file (false);
1042 return;
1045 /* Display statistics */
1046 if(verbose) {
1047 if (test) {
1048 fprintf(stderr, " OK");
1049 } else if (decompress) {
1050 display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out,stderr);
1051 } else {
1052 display_ratio(bytes_in-(bytes_out-header_bytes), bytes_in, stderr);
1054 if (!test)
1055 fprintf(stderr, " -- %s %s", keep ? "created" : "replaced with",
1056 ofname);
1057 fprintf(stderr, "\n");
1061 static void
1062 volatile_strcpy (char volatile *dst, char const volatile *src)
1064 while ((*dst++ = *src++))
1065 continue;
1068 /* ========================================================================
1069 * Create the output file. Return OK or ERROR.
1070 * Try several times if necessary to avoid truncating the z_suffix. For
1071 * example, do not create a compressed file of name "1234567890123."
1072 * Sets save_orig_name to true if the file name has been truncated.
1073 * IN assertions: the input file has already been open (ifd is set) and
1074 * ofname has already been updated if there was an original name.
1075 * OUT assertions: ifd and ofd are closed in case of error.
1077 static int
1078 create_outfile ()
1080 static bool signal_handlers_installed;
1081 int name_shortened = 0;
1082 int flags = (O_WRONLY | O_CREAT | O_EXCL
1083 | (ascii && decompress ? 0 : O_BINARY));
1084 char const *base = ofname;
1085 int atfd = AT_FDCWD;
1087 if (!keep)
1089 char const *b = last_component (ofname);
1090 int f = atdir_set (ofname, b - ofname);
1091 if (0 <= f)
1093 base = b;
1094 atfd = f;
1098 if (!signal_handlers_installed)
1100 signal_handlers_installed = true;
1101 install_signal_handlers ();
1104 for (;;)
1106 int open_errno;
1107 sigset_t oldset;
1109 volatile_strcpy (remove_ofname, ofname);
1111 sigprocmask (SIG_BLOCK, &caught_signals, &oldset);
1112 remove_ofname_fd = ofd = openat (atfd, base, flags, S_IRUSR | S_IWUSR);
1113 open_errno = errno;
1114 sigprocmask (SIG_SETMASK, &oldset, NULL);
1116 if (0 <= ofd)
1117 break;
1119 switch (open_errno)
1121 #ifdef ENAMETOOLONG
1122 case ENAMETOOLONG:
1123 shorten_name (ofname);
1124 name_shortened = 1;
1125 break;
1126 #endif
1128 case EEXIST:
1129 if (check_ofname () != OK)
1131 close (ifd);
1132 return ERROR;
1134 break;
1136 default:
1137 write_error ();
1138 close (ifd);
1139 return ERROR;
1143 if (name_shortened && decompress)
1145 /* name might be too long if an original name was saved */
1146 WARN ((stderr, "%s: %s: warning, name truncated\n",
1147 program_name, ofname));
1150 return OK;
1153 /* ========================================================================
1154 * Return a pointer to the 'z' suffix of a file name, or NULL. For all
1155 * systems, ".gz", ".z", ".Z", ".taz", ".tgz", "-gz", "-z" and "_z" are
1156 * accepted suffixes, in addition to the value of the --suffix option.
1157 * ".tgz" is a useful convention for tar.z files on systems limited
1158 * to 3 characters extensions. On such systems, ".?z" and ".??z" are
1159 * also accepted suffixes. For Unix, we do not want to accept any
1160 * .??z suffix as indicating a compressed file; some people use .xyz
1161 * to denote volume data.
1163 static char *
1164 get_suffix (char *name)
1166 int nlen, slen;
1167 char suffix[MAX_SUFFIX+3]; /* last chars of name, forced to lower case */
1168 static char const *known_suffixes[] =
1169 {NULL, ".gz", ".z", ".taz", ".tgz", "-gz", "-z", "_z",
1170 #ifdef MAX_EXT_CHARS
1171 "z",
1172 #endif
1173 NULL, NULL};
1174 char const **suf;
1175 bool suffix_of_builtin = false;
1177 /* Normally put Z_SUFFIX at the start of KNOWN_SUFFIXES, but if it
1178 is a suffix of one of them, put it at the end. */
1179 for (suf = known_suffixes + 1; *suf; suf++)
1181 size_t suflen = strlen (*suf);
1182 if (z_len < suflen && strequ (z_suffix, *suf + suflen - z_len))
1184 suffix_of_builtin = true;
1185 break;
1189 char *z_lower = xstrdup(z_suffix);
1190 strlwr(z_lower);
1191 known_suffixes[suffix_of_builtin
1192 ? sizeof known_suffixes / sizeof *known_suffixes - 2
1193 : 0] = z_lower;
1194 suf = known_suffixes + suffix_of_builtin;
1196 nlen = strlen(name);
1197 if (nlen <= MAX_SUFFIX+2) {
1198 strcpy(suffix, name);
1199 } else {
1200 strcpy(suffix, name+nlen-MAX_SUFFIX-2);
1202 strlwr(suffix);
1203 slen = strlen(suffix);
1204 char *match = NULL;
1205 do {
1206 int s = strlen(*suf);
1207 if (slen > s && ! ISSLASH (suffix[slen - s - 1])
1208 && strequ(suffix + slen - s, *suf)) {
1209 match = name+nlen-s;
1210 break;
1212 } while (*++suf != NULL);
1213 free(z_lower);
1215 return match;
1219 /* Open file NAME with the given flags and store its status
1220 into *ST. Return a file descriptor to the newly opened file, or -1
1221 (setting errno) on failure. */
1222 static int
1223 open_and_stat (char *name, int flags, struct stat *st)
1225 int fd;
1226 int atfd = AT_FDCWD;
1227 char const *base = name;
1229 /* Refuse to follow symbolic links unless -c or -f. */
1230 if (!to_stdout && !force)
1232 if (HAVE_WORKING_O_NOFOLLOW)
1233 flags |= O_NOFOLLOW;
1234 else
1236 #ifdef S_ISLNK
1237 if (lstat (name, st) != 0)
1238 return -1;
1239 else if (S_ISLNK (st->st_mode))
1241 errno = ELOOP;
1242 return -1;
1244 #endif
1248 if (!keep)
1250 char const *b = last_component (name);
1251 int f = atdir_set (name, b - name);
1252 if (0 <= f)
1254 base = b;
1255 atfd = f;
1259 fd = openat (atfd, base, flags);
1260 if (0 <= fd && fstat (fd, st) != 0)
1262 int e = errno;
1263 close (fd);
1264 errno = e;
1265 return -1;
1267 return fd;
1271 /* ========================================================================
1272 * Set ifname to the input file name (with a suffix appended if necessary)
1273 * and istat to its stats. For decompression, if no file exists with the
1274 * original name, try adding successively z_suffix, .gz, .z, -z and .Z.
1275 * For MSDOS, we try only z_suffix and z.
1276 * Return an open file descriptor or -1.
1278 static int
1279 open_input_file (char *iname, struct stat *sbuf)
1281 int ilen; /* strlen(ifname) */
1282 int z_suffix_errno = 0;
1283 static char const *suffixes[] = {NULL, ".gz", ".z", "-z", ".Z", NULL};
1284 char const **suf = suffixes;
1285 char const *s;
1286 #ifdef NO_MULTIPLE_DOTS
1287 char *dot; /* pointer to ifname extension, or NULL */
1288 #endif
1289 int fd;
1290 int open_flags = (O_RDONLY | O_NONBLOCK | O_NOCTTY
1291 | (ascii && !decompress ? 0 : O_BINARY));
1293 *suf = z_suffix;
1295 if (sizeof ifname - 1 <= strlen (iname))
1296 goto name_too_long;
1298 strcpy(ifname, iname);
1300 /* If input file exists, return OK. */
1301 fd = open_and_stat (ifname, open_flags, sbuf);
1302 if (0 <= fd)
1303 return fd;
1305 if (!decompress || errno != ENOENT) {
1306 progerror(ifname);
1307 return -1;
1309 /* File.ext doesn't exist. Try adding a suffix. */
1310 s = get_suffix(ifname);
1311 if (s != NULL) {
1312 progerror(ifname); /* ifname already has z suffix and does not exist */
1313 return -1;
1315 #ifdef NO_MULTIPLE_DOTS
1316 dot = strrchr(ifname, '.');
1317 if (dot == NULL) {
1318 strcat(ifname, ".");
1319 dot = strrchr(ifname, '.');
1321 #endif
1322 ilen = strlen(ifname);
1323 if (strequ(z_suffix, ".gz")) suf++;
1325 /* Search for all suffixes */
1326 do {
1327 char const *s0 = s = *suf;
1328 strcpy (ifname, iname);
1329 #ifdef NO_MULTIPLE_DOTS
1330 if (*s == '.') s++;
1331 if (*dot == '\0') strcpy (dot, ".");
1332 #endif
1333 #ifdef MAX_EXT_CHARS
1334 if (MAX_EXT_CHARS < strlen (s) + strlen (dot + 1))
1335 dot[MAX_EXT_CHARS + 1 - strlen (s)] = '\0';
1336 #endif
1337 if (sizeof ifname <= ilen + strlen (s))
1338 goto name_too_long;
1339 strcat(ifname, s);
1340 fd = open_and_stat (ifname, open_flags, sbuf);
1341 if (0 <= fd)
1342 return fd;
1343 if (errno != ENOENT)
1345 progerror (ifname);
1346 return -1;
1348 if (strequ (s0, z_suffix))
1349 z_suffix_errno = errno;
1350 } while (*++suf != NULL);
1352 /* No suffix found, complain using z_suffix: */
1353 strcpy(ifname, iname);
1354 #ifdef NO_MULTIPLE_DOTS
1355 if (*dot == '\0') strcpy(dot, ".");
1356 #endif
1357 #ifdef MAX_EXT_CHARS
1358 if (MAX_EXT_CHARS < z_len + strlen (dot + 1))
1359 dot[MAX_EXT_CHARS + 1 - z_len] = '\0';
1360 #endif
1361 strcat(ifname, z_suffix);
1362 errno = z_suffix_errno;
1363 progerror(ifname);
1364 return -1;
1366 name_too_long:
1367 fprintf (stderr, "%s: %s: file name too long\n", program_name, iname);
1368 exit_code = ERROR;
1369 return -1;
1372 /* ========================================================================
1373 * Generate ofname given ifname. Return OK, or WARNING if file must be skipped.
1374 * Sets save_orig_name to true if the file name has been truncated.
1376 static int
1377 make_ofname ()
1379 char *suff; /* ofname z suffix */
1381 strcpy(ofname, ifname);
1382 /* strip a version number if any and get the gzip suffix if present: */
1383 suff = get_suffix(ofname);
1385 if (decompress) {
1386 if (suff == NULL) {
1387 /* With -t or -l, try all files (even without .gz suffix)
1388 * except with -r (behave as with just -dr).
1390 if (!recursive && test)
1391 return OK;
1393 /* Avoid annoying messages with -r */
1394 if (verbose || (!recursive && !quiet)) {
1395 WARN((stderr,"%s: %s: unknown suffix -- ignored\n",
1396 program_name, ifname));
1398 return WARNING;
1400 /* Make a special case for .tgz and .taz: */
1401 strlwr(suff);
1402 if (strequ(suff, ".tgz") || strequ(suff, ".taz")) {
1403 strcpy(suff, ".tar");
1404 } else {
1405 *suff = '\0'; /* strip the z suffix */
1407 /* ofname might be changed later if infile contains an original name */
1409 } else if (suff && ! force) {
1410 /* Avoid annoying messages with -r (see treat_dir()) */
1411 if (verbose || (!recursive && !quiet)) {
1412 /* Don't use WARN, as it affects exit status. */
1413 fprintf (stderr, "%s: %s already has %s suffix -- unchanged\n",
1414 program_name, ifname, suff);
1416 return WARNING;
1417 } else {
1418 save_orig_name = 0;
1420 #ifdef NO_MULTIPLE_DOTS
1421 suff = strrchr(ofname, '.');
1422 if (suff == NULL) {
1423 if (sizeof ofname <= strlen (ofname) + 1)
1424 goto name_too_long;
1425 strcat(ofname, ".");
1426 # ifdef MAX_EXT_CHARS
1427 if (strequ(z_suffix, "z")) {
1428 if (sizeof ofname <= strlen (ofname) + 2)
1429 goto name_too_long;
1430 strcat(ofname, "gz"); /* enough room */
1431 return OK;
1433 /* On the Atari and some versions of MSDOS,
1434 * ENAMETOOLONG does not work correctly. So we
1435 * must truncate here.
1437 } else if (strlen(suff)-1 + z_len > MAX_SUFFIX) {
1438 suff[MAX_SUFFIX+1-z_len] = '\0';
1439 save_orig_name = 1;
1440 # endif
1442 #endif /* NO_MULTIPLE_DOTS */
1443 if (sizeof ofname <= strlen (ofname) + z_len)
1444 goto name_too_long;
1445 strcat(ofname, z_suffix);
1447 } /* decompress ? */
1448 return OK;
1450 name_too_long:
1451 WARN ((stderr, "%s: %s: file name too long\n", program_name, ifname));
1452 return WARNING;
1455 /* Discard NBYTES input bytes from the input, or up through the next
1456 zero byte if NBYTES == (size_t) -1. If FLAGS say that the header
1457 CRC should be computed, update the CRC accordingly. */
1458 static void
1459 discard_input_bytes (size_t nbytes, unsigned int flags)
1461 while (nbytes != 0)
1463 uch c = get_byte ();
1464 if (flags & HEADER_CRC)
1465 updcrc (&c, 1);
1466 if (nbytes != (size_t) -1)
1467 nbytes--;
1468 else if (! c)
1469 break;
1473 /* ========================================================================
1474 * Check the magic number of the input file and update ofname if an
1475 * original name was given and to_stdout is not set.
1476 * Return the compression method, -1 for error, -2 for warning.
1477 * Set inptr to the offset of the next byte to be processed.
1478 * Updates time_stamp if there is one and neither -m nor -n is used.
1479 * This function may be called repeatedly for an input file consisting
1480 * of several contiguous gzip'ed members.
1481 * 'in' is the input file descriptor.
1482 * IN assertions: there is at least one remaining compressed member.
1483 * If the member is a zip file, it must be the only one.
1485 static int
1486 get_method (int in)
1488 uch flags; /* compression flags */
1489 uch magic[10]; /* magic header */
1490 int imagic0; /* first magic byte or EOF */
1491 int imagic1; /* like magic[1], but can represent EOF */
1492 ulg stamp; /* timestamp */
1494 /* If --force and --stdout, zcat == cat, so do not complain about
1495 * premature end of file: use try_byte instead of get_byte.
1497 if (force && to_stdout) {
1498 imagic0 = try_byte();
1499 magic[0] = imagic0;
1500 imagic1 = try_byte ();
1501 magic[1] = imagic1;
1502 /* If try_byte returned EOF, magic[1] == (char) EOF. */
1503 } else {
1504 magic[0] = get_byte ();
1505 imagic0 = 0;
1506 if (magic[0]) {
1507 magic[1] = get_byte ();
1508 imagic1 = 0; /* avoid lint warning */
1509 } else {
1510 imagic1 = try_byte ();
1511 magic[1] = imagic1;
1514 method = -1; /* unknown yet */
1515 part_nb++; /* number of parts in gzip file */
1516 header_bytes = 0;
1517 last_member = 0;
1518 /* assume multiple members in gzip file except for record oriented I/O */
1520 if (memcmp(magic, GZIP_MAGIC, 2) == 0
1521 || memcmp(magic, OLD_GZIP_MAGIC, 2) == 0) {
1523 method = (int)get_byte();
1524 if (method != DEFLATED) {
1525 fprintf(stderr,
1526 "%s: %s: unknown method %d -- not supported\n",
1527 program_name, ifname, method);
1528 exit_code = ERROR;
1529 return -1;
1531 work = unzip;
1532 flags = (uch)get_byte();
1534 if ((flags & ENCRYPTED) != 0) {
1535 fprintf(stderr,
1536 "%s: %s is encrypted -- not supported\n",
1537 program_name, ifname);
1538 exit_code = ERROR;
1539 return -1;
1541 if ((flags & RESERVED) != 0) {
1542 fprintf(stderr,
1543 "%s: %s has flags 0x%x -- not supported\n",
1544 program_name, ifname, flags);
1545 exit_code = ERROR;
1546 if (force <= 1) return -1;
1548 stamp = (ulg)get_byte();
1549 stamp |= ((ulg)get_byte()) << 8;
1550 stamp |= ((ulg)get_byte()) << 16;
1551 stamp |= ((ulg)get_byte()) << 24;
1552 if (stamp != 0 && !no_time)
1554 if (stamp <= TYPE_MAXIMUM (time_t))
1556 time_stamp.tv_sec = stamp;
1557 time_stamp.tv_nsec = 0;
1559 else
1561 WARN ((stderr,
1562 "%s: %s: MTIME %lu out of range for this platform\n",
1563 program_name, ifname, stamp));
1564 time_stamp.tv_sec = TYPE_MAXIMUM (time_t);
1565 time_stamp.tv_nsec = TIMESPEC_RESOLUTION - 1;
1569 magic[8] = get_byte (); /* Ignore extra flags. */
1570 magic[9] = get_byte (); /* Ignore OS type. */
1572 if (flags & HEADER_CRC)
1574 magic[2] = DEFLATED;
1575 magic[3] = flags;
1576 magic[4] = stamp & 0xff;
1577 magic[5] = (stamp >> 8) & 0xff;
1578 magic[6] = (stamp >> 16) & 0xff;
1579 magic[7] = stamp >> 24;
1580 updcrc (NULL, 0);
1581 updcrc (magic, 10);
1584 if ((flags & EXTRA_FIELD) != 0) {
1585 uch lenbuf[2];
1586 unsigned int len = lenbuf[0] = get_byte ();
1587 len |= (lenbuf[1] = get_byte ()) << 8;
1588 if (verbose) {
1589 fprintf(stderr,"%s: %s: extra field of %u bytes ignored\n",
1590 program_name, ifname, len);
1592 if (flags & HEADER_CRC)
1593 updcrc (lenbuf, 2);
1594 discard_input_bytes (len, flags);
1597 /* Get original file name if it was truncated */
1598 if ((flags & ORIG_NAME) != 0) {
1599 if (no_name || (to_stdout && !list) || part_nb > 1) {
1600 /* Discard the old name */
1601 discard_input_bytes (-1, flags);
1602 } else {
1603 /* Copy the base name. Keep a directory prefix intact. */
1604 char *p = gzip_base_name (ofname);
1605 char *base = p;
1606 for (;;) {
1607 *p = (char) get_byte ();
1608 if (*p++ == '\0') break;
1609 if (p >= ofname+sizeof(ofname)) {
1610 gzip_error ("corrupted input -- file name too large");
1613 if (flags & HEADER_CRC)
1614 updcrc ((uch *) base, p - base);
1615 p = gzip_base_name (base);
1616 memmove (base, p, strlen (p) + 1);
1617 /* If necessary, adapt the name to local OS conventions: */
1618 if (!list) {
1619 MAKE_LEGAL_NAME(base);
1620 if (base) list=0; /* avoid warning about unused variable */
1622 } /* no_name || to_stdout */
1623 } /* ORIG_NAME */
1625 /* Discard file comment if any */
1626 if ((flags & COMMENT) != 0) {
1627 discard_input_bytes (-1, flags);
1630 if (flags & HEADER_CRC)
1632 unsigned int crc16 = updcrc (magic, 0) & 0xffff;
1633 unsigned int header16 = get_byte ();
1634 header16 |= ((unsigned int) get_byte ()) << 8;
1635 if (header16 != crc16)
1637 fprintf (stderr,
1638 "%s: %s: header checksum 0x%04x != computed checksum 0x%04x\n",
1639 program_name, ifname, header16, crc16);
1640 exit_code = ERROR;
1641 if (force <= 1)
1642 return -1;
1646 if (part_nb == 1) {
1647 header_bytes = inptr + 2*4; /* include crc and size */
1650 } else if (memcmp(magic, PKZIP_MAGIC, 2) == 0 && inptr == 2
1651 && memcmp((char*)inbuf, PKZIP_MAGIC, 4) == 0) {
1652 /* To simplify the code, we support a zip file when alone only.
1653 * We are thus guaranteed that the entire local header fits in inbuf.
1655 inptr = 0;
1656 work = unzip;
1657 if (check_zipfile(in) != OK) return -1;
1658 /* check_zipfile may get ofname from the local header */
1659 last_member = 1;
1661 } else if (memcmp(magic, PACK_MAGIC, 2) == 0) {
1662 work = unpack;
1663 method = PACKED;
1665 } else if (memcmp(magic, LZW_MAGIC, 2) == 0) {
1666 work = unlzw;
1667 method = COMPRESSED;
1668 last_member = 1;
1670 } else if (memcmp(magic, LZH_MAGIC, 2) == 0) {
1671 work = unlzh;
1672 method = LZHED;
1673 last_member = 1;
1675 } else if (force && to_stdout && !list) { /* pass input unchanged */
1676 method = STORED;
1677 work = copy;
1678 if (imagic1 != EOF)
1679 inptr--;
1680 last_member = 1;
1681 if (imagic0 != EOF) {
1682 write_buf (STDOUT_FILENO, magic, 1);
1685 if (method >= 0) return method;
1687 if (part_nb == 1) {
1688 fprintf (stderr, "\n%s: %s: not in gzip format\n",
1689 program_name, ifname);
1690 exit_code = ERROR;
1691 return -1;
1692 } else {
1693 if (magic[0] == 0)
1695 int inbyte;
1696 for (inbyte = imagic1; inbyte == 0; inbyte = try_byte ())
1697 continue;
1698 if (inbyte == EOF)
1700 if (verbose)
1701 WARN ((stderr, "\n%s: %s: decompression OK, trailing zero bytes ignored\n",
1702 program_name, ifname));
1703 return -3;
1707 WARN((stderr, "\n%s: %s: decompression OK, trailing garbage ignored\n",
1708 program_name, ifname));
1709 return -2;
1713 /* ========================================================================
1714 * Display the characteristics of the compressed file.
1715 * If the given method is < 0, display the accumulated totals.
1716 * IN assertions: time_stamp, header_bytes and ifile_size are initialized.
1718 static void
1719 do_list (int method)
1721 ulg crc; /* original crc */
1722 static int first_time = 1;
1723 static char const *const methods[MAX_METHODS] = {
1724 "store", /* 0 */
1725 "compr", /* 1 */
1726 "pack ", /* 2 */
1727 "lzh ", /* 3 */
1728 "", "", "", "", /* 4 to 7 reserved */
1729 "defla"}; /* 8 */
1730 int positive_off_t_width = INT_STRLEN_BOUND (off_t) - 1;
1732 if (first_time && method >= 0) {
1733 first_time = 0;
1734 if (verbose) {
1735 printf("method crc date time ");
1737 if (!quiet) {
1738 printf("%*.*s %*.*s ratio uncompressed_name\n",
1739 positive_off_t_width, positive_off_t_width, "compressed",
1740 positive_off_t_width, positive_off_t_width, "uncompressed");
1742 } else if (method < 0) {
1743 if (total_in <= 0 || total_out <= 0) return;
1744 if (verbose) {
1745 printf(" ");
1747 if (verbose || !quiet)
1748 printf ("%*jd %*jd ", positive_off_t_width, (intmax_t) total_in,
1749 positive_off_t_width, (intmax_t) total_out);
1750 display_ratio(total_out-(total_in-header_bytes), total_out, stdout);
1751 /* header_bytes is not meaningful but used to ensure the same
1752 * ratio if there is a single file.
1754 printf(" (totals)\n");
1755 return;
1757 crc = (ulg)~0; /* unknown */
1759 if (method == DEFLATED && !last_member) {
1760 crc = unzip_crc;
1763 if (verbose)
1765 static char const month_abbr[][4]
1766 = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1767 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
1768 struct tm *tm = localtime (&time_stamp.tv_sec);
1769 printf ("%5s %08lx ", methods[method], crc);
1770 if (tm)
1771 printf ("%s%3d %02d:%02d ", month_abbr[tm->tm_mon],
1772 tm->tm_mday, tm->tm_hour, tm->tm_min);
1773 else
1774 printf ("??? ?? ??:?? ");
1776 printf ("%*jd %*jd ", positive_off_t_width, (intmax_t) bytes_in,
1777 positive_off_t_width, (intmax_t) bytes_out);
1778 if (bytes_in == -1L) {
1779 total_in = -1L;
1780 bytes_in = bytes_out = header_bytes = 0;
1781 } else if (total_in >= 0) {
1782 total_in += bytes_in;
1784 if (bytes_out == -1L) {
1785 total_out = -1L;
1786 bytes_in = bytes_out = header_bytes = 0;
1787 } else if (total_out >= 0) {
1788 total_out += bytes_out;
1790 display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out, stdout);
1791 printf(" %s\n", ofname);
1794 /* ========================================================================
1795 * Shorten the given name by one character, or replace a .tar extension
1796 * with .tgz. Truncate the last part of the name which is longer than
1797 * MIN_PART characters: 1234.678.012.gz -> 123.678.012.gz. If the name
1798 * has only parts shorter than MIN_PART truncate the longest part.
1799 * For decompression, just remove the last character of the name.
1801 * IN assertion: for compression, the suffix of the given name is z_suffix.
1803 static void
1804 shorten_name (char *name)
1806 int len; /* length of name without z_suffix */
1807 char *trunc = NULL; /* character to be truncated */
1808 int plen; /* current part length */
1809 int min_part = MIN_PART; /* current minimum part length */
1810 char *p;
1812 len = strlen(name);
1813 if (decompress) {
1814 if (len <= 1)
1815 gzip_error ("name too short");
1816 name[len-1] = '\0';
1817 return;
1819 p = get_suffix(name);
1820 if (! p)
1821 gzip_error ("can't recover suffix\n");
1822 *p = '\0';
1823 save_orig_name = 1;
1825 /* compress 1234567890.tar to 1234567890.tgz */
1826 if (len > 4 && strequ(p-4, ".tar")) {
1827 strcpy(p-4, ".tgz");
1828 return;
1830 /* Try keeping short extensions intact:
1831 * 1234.678.012.gz -> 123.678.012.gz
1833 do {
1834 p = last_component (name);
1835 while (*p) {
1836 plen = strcspn(p, PART_SEP);
1837 p += plen;
1838 if (plen > min_part) trunc = p-1;
1839 if (*p) p++;
1841 } while (trunc == NULL && --min_part != 0);
1843 if (trunc != NULL) {
1844 do {
1845 trunc[0] = trunc[1];
1846 } while (*trunc++);
1847 trunc--;
1848 } else {
1849 trunc = strrchr(name, PART_SEP[0]);
1850 if (!trunc)
1851 gzip_error ("internal error in shorten_name");
1852 if (trunc[1] == '\0') trunc--; /* force truncation */
1854 strcpy(trunc, z_suffix);
1857 /* ========================================================================
1858 * The compressed file already exists, so ask for confirmation.
1859 * Return ERROR if the file must be skipped.
1861 static int
1862 check_ofname ()
1864 /* Ask permission to overwrite the existing file */
1865 if (!force) {
1866 int ok = 0;
1867 fprintf (stderr, "%s: %s already exists;", program_name, ofname);
1868 if (foreground && (presume_input_tty || isatty (STDIN_FILENO))) {
1869 fprintf(stderr, " do you wish to overwrite (y or n)? ");
1870 fflush(stderr);
1871 ok = yesno();
1873 if (!ok) {
1874 fprintf(stderr, "\tnot overwritten\n");
1875 if (exit_code == OK) exit_code = WARNING;
1876 return ERROR;
1879 if (xunlink (ofname)) {
1880 progerror(ofname);
1881 return ERROR;
1883 return OK;
1886 /* Change the owner and group of a file. FD is a file descriptor for
1887 the file and NAME its name. Change it to user UID and to group GID.
1888 If UID or GID is -1, though, do not change the corresponding user
1889 or group. */
1890 #if ! (HAVE_FCHOWN || HAVE_CHOWN)
1891 /* The types uid_t and gid_t do not exist on mingw, so don't assume them. */
1892 # define do_chown(fd, name, uid, gid) ((void) 0)
1893 #else
1894 static void
1895 do_chown (int fd, char const *name, uid_t uid, gid_t gid)
1897 # if HAVE_FCHOWN
1898 ignore_value (fchown (fd, uid, gid));
1899 # else
1900 ignore_value (chown (name, uid, gid));
1901 # endif
1903 #endif
1905 /* ========================================================================
1906 * Copy modes, times, ownership from input file to output file.
1907 * IN assertion: to_stdout is false.
1909 static void
1910 copy_stat (struct stat *ifstat)
1912 mode_t mode = ifstat->st_mode & S_IRWXUGO;
1913 int r;
1915 #ifndef NO_UTIME
1916 bool restoring;
1917 struct timespec timespec[2];
1918 timespec[0] = get_stat_atime (ifstat);
1919 timespec[1] = get_stat_mtime (ifstat);
1920 restoring = (decompress && 0 <= time_stamp.tv_nsec
1921 && ! (timespec[1].tv_sec == time_stamp.tv_sec
1922 && timespec[1].tv_nsec == time_stamp.tv_nsec));
1923 if (restoring)
1924 timespec[1] = time_stamp;
1926 if (fdutimens (ofd, ofname, timespec) == 0)
1928 if (restoring && 1 < verbose) {
1929 fprintf(stderr, "%s: timestamp restored\n", ofname);
1932 else
1933 WARN ((stderr, "%s: %s: %s\n", program_name, ofname, strerror (errno)));
1934 #endif
1936 /* Change the group first, then the permissions, then the owner.
1937 That way, the permissions will be correct on systems that allow
1938 users to give away files, without introducing a security hole.
1939 Security depends on permissions not containing the setuid or
1940 setgid bits. */
1942 do_chown (ofd, ofname, -1, ifstat->st_gid);
1944 #if HAVE_FCHMOD
1945 r = fchmod (ofd, mode);
1946 #else
1947 r = chmod (ofname, mode);
1948 #endif
1949 if (r != 0)
1950 WARN ((stderr, "%s: %s: %s\n", program_name, ofname, strerror (errno)));
1952 do_chown (ofd, ofname, ifstat->st_uid, -1);
1955 #if ! NO_DIR
1957 /* ========================================================================
1958 * Recurse through the given directory.
1960 static void
1961 treat_dir (int fd, char *dir)
1963 DIR *dirp;
1964 char nbuf[MAX_PATH_LEN];
1965 char *entries;
1966 char const *entry;
1967 size_t entrylen;
1969 dirp = fdopendir (fd);
1971 if (dirp == NULL) {
1972 progerror(dir);
1973 close (fd);
1974 return ;
1977 entries = streamsavedir (dirp, SAVEDIR_SORT_NONE);
1978 if (! entries)
1979 progerror (dir);
1980 if (closedir (dirp) != 0)
1981 progerror (dir);
1982 if (! entries)
1983 return;
1985 for (entry = entries; *entry; entry += entrylen + 1) {
1986 size_t len = strlen (dir);
1987 entrylen = strlen (entry);
1988 if (strequ (entry, ".") || strequ (entry, ".."))
1989 continue;
1990 if (len + entrylen < MAX_PATH_LEN - 2) {
1991 strcpy(nbuf,dir);
1992 if (*last_component (nbuf) && !ISSLASH (nbuf[len - 1]))
1993 nbuf[len++] = '/';
1994 strcpy (nbuf + len, entry);
1995 treat_file(nbuf);
1996 } else {
1997 fprintf(stderr,"%s: %s/%s: pathname too long\n",
1998 program_name, dir, entry);
1999 exit_code = ERROR;
2002 free (entries);
2004 #endif /* ! NO_DIR */
2006 /* Make sure signals get handled properly. */
2008 static void
2009 install_signal_handlers ()
2011 int nsigs = sizeof handled_sig / sizeof handled_sig[0];
2012 int i;
2013 struct sigaction act;
2015 sigemptyset (&caught_signals);
2016 for (i = 0; i < nsigs; i++)
2018 sigaction (handled_sig[i], NULL, &act);
2019 if (act.sa_handler != SIG_IGN)
2020 sigaddset (&caught_signals, handled_sig[i]);
2023 act.sa_handler = abort_gzip_signal;
2024 act.sa_mask = caught_signals;
2025 act.sa_flags = 0;
2027 for (i = 0; i < nsigs; i++)
2028 if (sigismember (&caught_signals, handled_sig[i]))
2030 if (i == 0)
2031 foreground = 1;
2032 sigaction (handled_sig[i], &act, NULL);
2036 /* ========================================================================
2037 * Free all dynamically allocated variables and exit with the given code.
2039 static void
2040 do_exit (int exitcode)
2042 static int in_exit = 0;
2044 if (in_exit) exit(exitcode);
2045 in_exit = 1;
2046 free(env);
2047 env = NULL;
2048 FREE(inbuf);
2049 FREE(outbuf);
2050 FREE(d_buf);
2051 FREE(window);
2052 #ifndef MAXSEG_64K
2053 FREE(tab_prefix);
2054 #else
2055 FREE(tab_prefix0);
2056 FREE(tab_prefix1);
2057 #endif
2058 exit(exitcode);
2061 static void
2062 finish_out ()
2064 if (fclose (stdout) != 0)
2065 write_error ();
2066 do_exit (OK);
2069 /* ========================================================================
2070 * Close and unlink the output file.
2072 static void
2073 remove_output_file (bool signals_already_blocked)
2075 int fd;
2076 sigset_t oldset;
2078 if (!signals_already_blocked)
2079 sigprocmask (SIG_BLOCK, &caught_signals, &oldset);
2080 fd = remove_ofname_fd;
2081 if (0 <= fd)
2083 char fname[MAX_PATH_LEN];
2084 remove_ofname_fd = -1;
2085 close (fd);
2086 volatile_strcpy (fname, remove_ofname);
2087 xunlink (fname);
2089 if (!signals_already_blocked)
2090 sigprocmask (SIG_SETMASK, &oldset, NULL);
2093 /* ========================================================================
2094 * Error handler.
2096 void
2097 finish_up_gzip (int exitcode)
2099 if (0 <= remove_ofname_fd)
2100 remove_output_file (false);
2101 do_exit (exitcode);
2103 void
2104 abort_gzip ()
2106 finish_up_gzip (ERROR);
2108 /* ========================================================================
2109 * Signal handler.
2111 static void
2112 abort_gzip_signal (int sig)
2114 remove_output_file (true);
2115 signal (sig, SIG_DFL);
2116 raise (sig);