maint: update bootstrap and m4/.gitignore to latest Gnulib
[gzip.git] / gzip.c
blob7ff482667d8fd37c77e015c3ea67289e5e490fc2
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 <unistd.h>
86 #include <stdlib.h>
88 #ifndef NO_DIR
89 # define NO_DIR 0
90 #endif
91 #if !NO_DIR
92 # include <dirent.h>
93 # include <savedir.h>
94 #endif
96 #ifndef NO_UTIME
97 # include <utimens.h>
98 #endif
100 #ifndef MAX_PATH_LEN
101 # define MAX_PATH_LEN 1024 /* max pathname length */
102 #endif
104 #ifndef SEEK_END
105 # define SEEK_END 2
106 #endif
108 #ifndef CHAR_BIT
109 # define CHAR_BIT 8
110 #endif
112 #ifdef off_t
113 off_t lseek (int fd, off_t offset, int whence);
114 #endif
116 #ifndef HAVE_WORKING_O_NOFOLLOW
117 # define HAVE_WORKING_O_NOFOLLOW 0
118 #endif
120 /* Separator for file name parts (see shorten_name()) */
121 #ifdef NO_MULTIPLE_DOTS
122 # define PART_SEP "-"
123 #else
124 # define PART_SEP "."
125 #endif
127 /* global buffers */
129 /* With IBM_Z_DFLTCC, DEFLATE COMPRESSION works faster with
130 page-aligned input and output buffers, and requires page-aligned
131 windows; the alignment requirement is 4096. On other platforms
132 alignment doesn't hurt, and alignment up to 4096 is portable so
133 let's do that. */
134 #if defined HAVE_C_ALIGNASOF || defined alignas
135 # define BUFFER_ALIGNED alignas (4096)
136 #else
137 # define BUFFER_ALIGNED /**/
138 #endif
139 DECLARE(uch BUFFER_ALIGNED, inbuf, INBUFSIZ +INBUF_EXTRA);
140 DECLARE(uch BUFFER_ALIGNED, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
141 DECLARE(ush, d_buf, DIST_BUFSIZE);
142 DECLARE(uch BUFFER_ALIGNED, window, 2L*WSIZE);
143 #ifndef MAXSEG_64K
144 DECLARE(ush, tab_prefix, 1L<<BITS);
145 #else
146 DECLARE(ush, tab_prefix0, 1L<<(BITS-1));
147 DECLARE(ush, tab_prefix1, 1L<<(BITS-1));
148 #endif
150 /* local variables */
152 /* If true, pretend that standard input is a tty. This option
153 is deliberately not documented, and only for testing. */
154 static bool presume_input_tty;
156 /* If true, transfer output data to the output file's storage device
157 when supported. Otherwise, if the system crashes around the time
158 gzip is run, the user might lose both input and output data. See:
159 Pillai TS et al. All file systems are not created equal: on the
160 complexity of crafting crash-consistent applications. OSDI'14. 2014:433-48.
161 https://www.usenix.org/conference/osdi14/technical-sessions/presentation/pillai */
162 static bool synchronous;
164 static int ascii = 0; /* convert end-of-lines to local OS conventions */
165 int to_stdout = 0; /* output to stdout (-c) */
166 static int decompress = 0; /* decompress (-d) */
167 static int force = 0; /* don't ask questions, compress links (-f) */
168 static int keep = 0; /* keep (don't delete) input files */
169 static int no_name = -1; /* don't save or restore the original file name */
170 static int no_time = -1; /* don't save or restore the original file time */
171 static int recursive = 0; /* recurse through directories (-r) */
172 static int list = 0; /* list the file contents (-l) */
173 #ifndef DEBUG
174 static
175 #endif
176 int verbose = 0; /* be verbose (-v) */
177 int quiet = 0; /* be very quiet (-q) */
178 int test = 0; /* test .gz file integrity */
179 static int foreground = 0; /* set if program run in foreground */
180 char *program_name; /* program name */
181 int maxbits = BITS; /* max bits per code for LZW */
182 int method = DEFLATED;/* compression method */
183 int level = 6; /* compression level */
184 int exit_code = OK; /* program exit code */
185 int save_orig_name; /* set if original name must be saved */
186 static int last_member; /* set for .zip and .Z files */
187 static int part_nb; /* number of parts in .gz file */
188 off_t ifile_size; /* input file size, -1 for devices (debug only) */
189 static char *env; /* contents of GZIP env variable */
190 static char const *z_suffix; /* default suffix (can be set with --suffix) */
191 static size_t z_len; /* strlen(z_suffix) */
193 /* The original timestamp (modification time). If the original is
194 unknown, TIME_STAMP.tv_nsec is negative. If the original is
195 greater than struct timespec range, TIME_STAMP is the maximal
196 struct timespec value; this can happen on hosts with 32-bit signed
197 time_t because the gzip format's MTIME is 32-bit unsigned.
198 The original cannot be less than struct timespec range. */
199 struct timespec time_stamp;
201 /* The set of signals that are caught. */
202 static sigset_t caught_signals;
204 /* If nonnegative, close this file descriptor and unlink remove_ofname
205 on error. */
206 static int volatile remove_ofname_fd = -1;
207 static char volatile remove_ofname[MAX_PATH_LEN];
209 static bool stdin_was_read;
211 off_t bytes_in; /* number of input bytes */
212 off_t bytes_out; /* number of output bytes */
213 static off_t total_in; /* input bytes for all files */
214 static off_t total_out; /* output bytes for all files */
215 char ifname[MAX_PATH_LEN]; /* input file name */
216 char ofname[MAX_PATH_LEN]; /* output file name */
217 static char dfname[MAX_PATH_LEN]; /* name of dir containing output file */
218 static struct stat istat; /* status for input file */
219 int ifd; /* input file descriptor */
220 int ofd; /* output file descriptor */
221 static int dfd = -1; /* output directory file descriptor */
222 unsigned insize; /* valid bytes in inbuf */
223 unsigned inptr; /* index of next byte to be processed in inbuf */
224 unsigned outcnt; /* bytes in output buffer */
225 int rsync = 0; /* make rsyncable chunks */
227 static int handled_sig[] =
229 /* SIGINT must be first, as 'foreground' depends on it. */
230 SIGINT
232 #ifdef SIGHUP
233 , SIGHUP
234 #endif
235 #if SIGPIPE
236 , SIGPIPE
237 #endif
238 #ifdef SIGTERM
239 , SIGTERM
240 #endif
241 #ifdef SIGXCPU
242 , SIGXCPU
243 #endif
244 #ifdef SIGXFSZ
245 , SIGXFSZ
246 #endif
249 /* For long options that have no equivalent short option, use a
250 non-character as a pseudo short option, starting with CHAR_MAX + 1. */
251 enum
253 PRESUME_INPUT_TTY_OPTION = CHAR_MAX + 1,
254 RSYNCABLE_OPTION,
255 SYNCHRONOUS_OPTION,
257 /* A value greater than all valid long options, used as a flag to
258 distinguish options derived from the GZIP environment variable. */
259 ENV_OPTION
262 static char const shortopts[] = "ab:cdfhH?klLmMnNqrS:tvVZ123456789";
264 static const struct option longopts[] =
266 /* { name has_arg *flag val } */
267 {"ascii", 0, 0, 'a'}, /* ascii text mode */
268 {"to-stdout", 0, 0, 'c'}, /* write output on standard output */
269 {"stdout", 0, 0, 'c'}, /* write output on standard output */
270 {"decompress", 0, 0, 'd'}, /* decompress */
271 {"uncompress", 0, 0, 'd'}, /* decompress */
272 /* {"encrypt", 0, 0, 'e'}, encrypt */
273 {"force", 0, 0, 'f'}, /* force overwrite of output file */
274 {"help", 0, 0, 'h'}, /* give help */
275 /* {"pkzip", 0, 0, 'k'}, force output in pkzip format */
276 {"keep", 0, 0, 'k'}, /* keep (don't delete) input files */
277 {"list", 0, 0, 'l'}, /* list .gz file contents */
278 {"license", 0, 0, 'L'}, /* display software license */
279 {"no-name", 0, 0, 'n'}, /* don't save or restore original name & time */
280 {"name", 0, 0, 'N'}, /* save or restore original name & time */
281 {"-presume-input-tty", no_argument, NULL, PRESUME_INPUT_TTY_OPTION},
282 {"quiet", 0, 0, 'q'}, /* quiet mode */
283 {"silent", 0, 0, 'q'}, /* quiet mode */
284 {"synchronous",0, 0, SYNCHRONOUS_OPTION},
285 {"recursive", 0, 0, 'r'}, /* recurse through directories */
286 {"suffix", 1, 0, 'S'}, /* use given suffix instead of .gz */
287 {"test", 0, 0, 't'}, /* test compressed file integrity */
288 {"verbose", 0, 0, 'v'}, /* verbose mode */
289 {"version", 0, 0, 'V'}, /* display version number */
290 {"fast", 0, 0, '1'}, /* compress faster */
291 {"best", 0, 0, '9'}, /* compress better */
292 {"lzw", 0, 0, 'Z'}, /* make output compatible with old compress */
293 {"bits", 1, 0, 'b'}, /* max number of bits per code (implies -Z) */
294 {"rsyncable", 0, 0, RSYNCABLE_OPTION}, /* make rsync-friendly archive */
295 { 0, 0, 0, 0 }
298 /* local functions */
300 _Noreturn static void try_help (void);
301 static void help (void);
302 static void license (void);
303 static void version (void);
304 static int input_eof (void);
305 static void treat_stdin (void);
306 static void treat_file (char *iname);
307 static int create_outfile (void);
308 static char *get_suffix (char *name);
309 static int open_input_file (char *iname, struct stat *sbuf);
310 static void discard_input_bytes (size_t nbytes, unsigned int flags);
311 static int make_ofname (void);
312 static void shorten_name (char *name);
313 static int get_method (int in);
314 static void do_list (int method);
315 static int check_ofname (void);
316 static void copy_stat (struct stat *ifstat);
317 static void install_signal_handlers (void);
318 static void remove_output_file (bool);
319 static void abort_gzip_signal (int);
320 _Noreturn static void do_exit (int exitcode);
321 static void finish_out (void);
322 int main (int argc, char **argv);
323 static int (*work) (int infile, int outfile) = zip; /* function to call */
325 #if ! NO_DIR
326 static void treat_dir (int fd, char *dir);
327 #endif
329 #define strequ(s1, s2) (strcmp((s1),(s2)) == 0)
331 static void
332 try_help ()
334 fprintf (stderr, "Try `%s --help' for more information.\n",
335 program_name);
336 do_exit (ERROR);
339 /* ======================================================================== */
340 static void
341 help ()
343 static char const* const help_msg[] = {
344 "Compress or uncompress FILEs (by default, compress FILES in-place).",
346 "Mandatory arguments to long options are mandatory for short options too.",
348 #if O_BINARY
349 " -a, --ascii ascii text; convert end-of-line using local conventions",
350 #endif
351 " -c, --stdout write on standard output, keep original files unchanged",
352 " -d, --decompress decompress",
353 /* -e, --encrypt encrypt */
354 " -f, --force force overwrite of output file and compress links",
355 " -h, --help give this help",
356 /* -k, --pkzip force output in pkzip format */
357 " -k, --keep keep (don't delete) input files",
358 " -l, --list list compressed file contents",
359 " -L, --license display software license",
360 #ifdef UNDOCUMENTED
361 " -m do not save or restore the original modification time",
362 " -M, --time save or restore the original modification time",
363 #endif
364 " -n, --no-name do not save or restore the original name and timestamp",
365 " -N, --name save or restore the original name and timestamp",
366 " -q, --quiet suppress all warnings",
367 #if ! NO_DIR
368 " -r, --recursive operate recursively on directories",
369 #endif
370 " --rsyncable make rsync-friendly archive",
371 " -S, --suffix=SUF use suffix SUF on compressed files",
372 " --synchronous synchronous output (safer if system crashes, but slower)",
373 " -t, --test test compressed file integrity",
374 " -v, --verbose verbose mode",
375 " -V, --version display version number",
376 " -1, --fast compress faster",
377 " -9, --best compress better",
379 "With no FILE, or when FILE is -, read standard input.",
381 "Report bugs to <bug-gzip@gnu.org>.",
383 char const *const *p = help_msg;
385 printf ("Usage: %s [OPTION]... [FILE]...\n", program_name);
386 while (*p) printf ("%s\n", *p++);
389 /* ======================================================================== */
390 static void
391 license ()
393 char const *const *p = license_msg;
395 printf ("%s %s\n", program_name, Version);
396 while (*p) printf ("%s\n", *p++);
399 /* ======================================================================== */
400 static void
401 version ()
403 license ();
404 printf ("\n");
405 printf ("Written by Jean-loup Gailly.\n");
408 static void
409 progerror (char const *string)
411 fprintf (stderr, "%s: %s: %s\n", program_name, string, strerror (errno));
412 exit_code = ERROR;
415 /* ======================================================================== */
416 int main (int argc, char **argv)
418 int file_count; /* number of files to process */
419 size_t proglen; /* length of program_name */
420 char **argv_copy;
421 int env_argc;
422 char **env_argv;
424 EXPAND(argc, argv); /* wild card expansion if necessary */
426 program_name = gzip_base_name (argv[0]);
427 proglen = strlen (program_name);
429 /* Suppress .exe for MSDOS and OS/2: */
430 if (4 < proglen && strequ (program_name + proglen - 4, ".exe"))
431 program_name[proglen - 4] = '\0';
433 /* Add options in GZIP environment variable if there is one */
434 argv_copy = argv;
435 env = add_envopt (&env_argc, &argv_copy, OPTIONS_VAR);
436 env_argv = env ? argv_copy : NULL;
438 #ifndef GNU_STANDARD
439 # define GNU_STANDARD 1
440 #endif
441 #if !GNU_STANDARD
442 /* For compatibility with old compress, use program name as an option.
443 * Unless you compile with -DGNU_STANDARD=0, this program will behave as
444 * gzip even if it is invoked under the name gunzip or zcat.
446 * Systems which do not support links can still use -d or -dc.
447 * Ignore an .exe extension for MSDOS and OS/2.
449 if (strncmp (program_name, "un", 2) == 0 /* ungzip, uncompress */
450 || strncmp (program_name, "gun", 3) == 0) /* gunzip */
451 decompress = 1;
452 else if (strequ (program_name + 1, "cat") /* zcat, pcat, gcat */
453 || strequ (program_name, "gzcat")) /* gzcat */
454 decompress = to_stdout = 1;
455 #endif
457 z_suffix = Z_SUFFIX;
458 z_len = strlen(z_suffix);
460 while (true) {
461 int optc;
462 int longind = -1;
464 if (env_argv)
466 if (env_argv[optind] && strequ (env_argv[optind], "--"))
467 optc = ENV_OPTION + '-';
468 else
470 optc = getopt_long (env_argc, env_argv, shortopts, longopts,
471 &longind);
472 if (0 <= optc)
473 optc += ENV_OPTION;
474 else
476 if (optind != env_argc)
478 fprintf (stderr,
479 ("%s: %s: non-option in "OPTIONS_VAR
480 " environment variable\n"),
481 program_name, env_argv[optind]);
482 try_help ();
485 /* Wait until here before warning, so that GZIP='-q'
486 doesn't warn. */
487 if (env_argc != 1 && !quiet)
488 fprintf (stderr,
489 ("%s: warning: "OPTIONS_VAR" environment variable"
490 " is deprecated; use an alias or script\n"),
491 program_name);
493 /* Start processing ARGC and ARGV instead. */
494 free (env_argv);
495 env_argv = NULL;
496 optind = 1;
497 longind = -1;
502 if (!env_argv)
503 optc = getopt_long (argc, argv, shortopts, longopts, &longind);
504 if (optc < 0)
505 break;
507 switch (optc) {
508 case 'a':
509 ascii = 1; break;
510 case 'b':
511 maxbits = atoi(optarg);
512 for (; *optarg; optarg++)
513 if (! ('0' <= *optarg && *optarg <= '9'))
515 fprintf (stderr, "%s: -b operand is not an integer\n",
516 program_name);
517 try_help ();
519 break;
520 case 'c':
521 to_stdout = 1; break;
522 case 'd':
523 decompress = 1; break;
524 case 'f':
525 force++; break;
526 case 'h': case 'H':
527 help (); finish_out (); break;
528 case 'k':
529 keep = 1; break;
530 case 'l':
531 list = decompress = test = to_stdout = 1; break;
532 case 'L':
533 license (); finish_out (); break;
534 case 'm': /* undocumented, may change later */
535 no_time = 1; break;
536 case 'M': /* undocumented, may change later */
537 no_time = 0; break;
538 case 'n':
539 case 'n' + ENV_OPTION:
540 no_name = no_time = 1; break;
541 case 'N':
542 case 'N' + ENV_OPTION:
543 no_name = no_time = 0; break;
544 case PRESUME_INPUT_TTY_OPTION:
545 presume_input_tty = true; break;
546 case 'q':
547 case 'q' + ENV_OPTION:
548 quiet = 1; verbose = 0; break;
549 case 'r':
550 #if NO_DIR
551 fprintf (stderr, "%s: -r not supported on this system\n",
552 program_name);
553 try_help ();
554 #else
555 recursive = 1;
556 #endif
557 break;
559 case RSYNCABLE_OPTION:
560 case RSYNCABLE_OPTION + ENV_OPTION:
561 rsync = 1;
562 break;
563 case 'S':
564 #ifdef NO_MULTIPLE_DOTS
565 if (*optarg == '.') optarg++;
566 #endif
567 z_len = strlen(optarg);
568 z_suffix = optarg;
569 break;
570 case SYNCHRONOUS_OPTION:
571 synchronous = true;
572 break;
573 case 't':
574 test = decompress = to_stdout = 1;
575 break;
576 case 'v':
577 case 'v' + ENV_OPTION:
578 verbose++; quiet = 0; break;
579 case 'V':
580 version (); finish_out (); break;
581 case 'Z':
582 fprintf(stderr, "%s: -Z not supported in this version\n",
583 program_name);
584 try_help ();
585 break;
586 case '1' + ENV_OPTION: case '2' + ENV_OPTION: case '3' + ENV_OPTION:
587 case '4' + ENV_OPTION: case '5' + ENV_OPTION: case '6' + ENV_OPTION:
588 case '7' + ENV_OPTION: case '8' + ENV_OPTION: case '9' + ENV_OPTION:
589 optc -= ENV_OPTION;
590 FALLTHROUGH;
591 case '1': case '2': case '3': case '4':
592 case '5': case '6': case '7': case '8': case '9':
593 level = optc - '0';
594 break;
596 default:
597 if (ENV_OPTION <= optc && optc != ENV_OPTION + '?')
599 /* Output a diagnostic, since getopt_long didn't. */
600 fprintf (stderr, "%s: ", program_name);
601 if (longind < 0)
602 fprintf (stderr, "-%c: ", optc - ENV_OPTION);
603 else
604 fprintf (stderr, "--%s: ", longopts[longind].name);
605 fprintf (stderr, ("option not valid in "OPTIONS_VAR
606 " environment variable\n"));
608 try_help ();
610 } /* loop on all arguments */
612 /* By default, save name and timestamp on compression but do not
613 * restore them on decompression.
615 if (no_time < 0) no_time = decompress;
616 if (no_name < 0) no_name = decompress;
618 file_count = argc - optind;
620 #if O_BINARY
621 #else
622 if (ascii && !quiet) {
623 fprintf(stderr, "%s: option --ascii ignored on this system\n",
624 program_name);
626 #endif
627 if (z_len == 0 || z_len > MAX_SUFFIX) {
628 fprintf(stderr, "%s: invalid suffix '%s'\n", program_name, z_suffix);
629 do_exit(ERROR);
632 /* Allocate all global buffers (for DYN_ALLOC option) */
633 ALLOC(uch, inbuf, INBUFSIZ +INBUF_EXTRA);
634 ALLOC(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
635 ALLOC(ush, d_buf, DIST_BUFSIZE);
636 ALLOC(uch, window, 2L*WSIZE);
637 #ifndef MAXSEG_64K
638 ALLOC(ush, tab_prefix, 1L<<BITS);
639 #else
640 ALLOC(ush, tab_prefix0, 1L<<(BITS-1));
641 ALLOC(ush, tab_prefix1, 1L<<(BITS-1));
642 #endif
644 /* And get to work */
645 if (file_count != 0) {
646 if (to_stdout && !test && (!decompress || !ascii)) {
647 SET_BINARY_MODE (STDOUT_FILENO);
649 while (optind < argc) {
650 treat_file(argv[optind++]);
652 } else { /* Standard input */
653 treat_stdin();
655 if (stdin_was_read && close (STDIN_FILENO) != 0)
657 strcpy (ifname, "stdin");
658 read_error ();
660 if (list)
662 /* Output any totals, and check for output errors. */
663 if (!quiet && 1 < file_count)
664 do_list (-1);
665 if (fflush (stdout) != 0)
666 write_error ();
668 if (to_stdout
669 && ((synchronous
670 && fdatasync (STDOUT_FILENO) != 0 && errno != EINVAL)
671 || close (STDOUT_FILENO) != 0)
672 && errno != EBADF)
673 write_error ();
674 do_exit(exit_code);
677 /* Return nonzero when at end of file on input. */
678 static int
679 input_eof ()
681 if (!decompress || last_member)
682 return 1;
684 if (inptr == insize)
686 if (insize != INBUFSIZ || fill_inbuf (1) == EOF)
687 return 1;
689 /* Unget the char that fill_inbuf got. */
690 inptr = 0;
693 return 0;
696 static void
697 get_input_size_and_time (void)
699 ifile_size = -1;
700 time_stamp.tv_nsec = -1;
702 /* Record the input file's size and timestamp only if it is a
703 regular file. Doing this for the timestamp helps to keep gzip's
704 output more reproducible when it is used as part of a
705 pipeline. */
707 if (S_ISREG (istat.st_mode))
709 ifile_size = istat.st_size;
710 if (!no_time || list)
711 time_stamp = get_stat_mtime (&istat);
715 /* ========================================================================
716 * Compress or decompress stdin
718 static void
719 treat_stdin ()
721 if (!force && !list
722 && (presume_input_tty
723 || isatty (decompress ? STDIN_FILENO : STDOUT_FILENO))) {
724 /* Do not send compressed data to the terminal or read it from
725 * the terminal. We get here when user invoked the program
726 * without parameters, so be helpful. According to the GNU standards:
728 * If there is one behavior you think is most useful when the output
729 * is to a terminal, and another that you think is most useful when
730 * the output is a file or a pipe, then it is usually best to make
731 * the default behavior the one that is useful with output to a
732 * terminal, and have an option for the other behavior.
734 * Here we use the --force option to get the other behavior.
736 if (! quiet)
737 fprintf (stderr,
738 ("%s: compressed data not %s a terminal."
739 " Use -f to force %scompression.\n"
740 "For help, type: %s -h\n"),
741 program_name,
742 decompress ? "read from" : "written to",
743 decompress ? "de" : "",
744 program_name);
745 do_exit(ERROR);
748 if (decompress || !ascii) {
749 SET_BINARY_MODE (STDIN_FILENO);
751 if (!test && (!decompress || !ascii)) {
752 SET_BINARY_MODE (STDOUT_FILENO);
754 strcpy(ifname, "stdin");
755 strcpy(ofname, "stdout");
757 /* Get the file's timestamp and size. */
758 if (fstat (STDIN_FILENO, &istat) != 0)
760 progerror ("standard input");
761 do_exit (ERROR);
764 get_input_size_and_time ();
766 clear_bufs(); /* clear input and output buffers */
767 to_stdout = 1;
768 part_nb = 0;
769 ifd = STDIN_FILENO;
770 stdin_was_read = true;
772 if (decompress) {
773 method = get_method(ifd);
774 if (method < 0) {
775 do_exit(exit_code); /* error message already emitted */
779 /* Actually do the compression/decompression. Loop over zipped members.
781 for (;;) {
782 if (work (STDIN_FILENO, STDOUT_FILENO) != OK)
783 return;
785 if (input_eof ())
786 break;
788 method = get_method(ifd);
789 if (method < 0) return; /* error message already emitted */
792 if (list)
794 do_list (method);
795 return;
798 if (verbose) {
799 if (test) {
800 fprintf(stderr, " OK\n");
802 } else if (!decompress) {
803 display_ratio(bytes_in-(bytes_out-header_bytes), bytes_in, stderr);
804 fprintf(stderr, "\n");
805 #ifdef DISPLAY_STDIN_RATIO
806 } else {
807 display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out,stderr);
808 fprintf(stderr, "\n");
809 #endif
814 static char const dot = '.';
816 /* True if the cached directory for calls to openat etc. is DIR, with
817 length DIRLEN. DIR need not be null-terminated. DIRLEN must be
818 less than MAX_PATH_LEN. */
819 static bool
820 atdir_eq (char const *dir, ptrdiff_t dirlen)
822 if (dirlen == 0)
823 dir = &dot, dirlen = 1;
824 return memcmp (dfname, dir, dirlen) == 0 && !dfname[dirlen];
827 /* Set the directory used for calls to openat etc. to be the directory
828 DIR, with length DIRLEN. DIR need not be null-terminated.
829 DIRLEN must be less than MAX_PATH_LEN. Return a file descriptor for
830 the directory, or -1 if one could not be obtained. */
831 static int
832 atdir_set (char const *dir, ptrdiff_t dirlen)
834 /* Don't bother opening directories on older systems that
835 lack openat and unlinkat. It's not worth the porting hassle. */
836 #if HAVE_OPENAT && HAVE_UNLINKAT
837 enum { try_opening_directories = true };
838 #else
839 enum { try_opening_directories = false };
840 #endif
842 if (try_opening_directories && ! atdir_eq (dir, dirlen))
844 if (0 <= dfd)
845 close (dfd);
846 if (dirlen == 0)
847 dir = &dot, dirlen = 1;
848 memcpy (dfname, dir, dirlen);
849 dfname[dirlen] = '\0';
850 dfd = open (dfname, O_SEARCH | O_DIRECTORY);
853 return dfd;
856 /* ========================================================================
857 * Compress or decompress the given file
859 static void
860 treat_file (char *iname)
862 /* Accept "-" as synonym for stdin */
863 if (strequ(iname, "-")) {
864 int cflag = to_stdout;
865 treat_stdin();
866 to_stdout = cflag;
867 return;
870 /* Check if the input file is present, set ifname and istat: */
871 ifd = open_input_file (iname, &istat);
872 if (ifd < 0)
873 return;
875 /* If the input name is that of a directory, recurse or ignore: */
876 if (S_ISDIR(istat.st_mode)) {
877 #if ! NO_DIR
878 if (recursive) {
879 treat_dir (ifd, iname);
880 /* Warning: ifname is now garbage */
881 return;
883 #endif
884 close (ifd);
885 WARN ((stderr, "%s: %s is a directory -- ignored\n",
886 program_name, ifname));
887 return;
890 if (! to_stdout)
892 if (! S_ISREG (istat.st_mode))
894 WARN ((stderr,
895 "%s: %s is not a directory or a regular file - ignored\n",
896 program_name, ifname));
897 close (ifd);
898 return;
900 if (istat.st_mode & S_ISUID)
902 WARN ((stderr, "%s: %s is set-user-ID on execution - ignored\n",
903 program_name, ifname));
904 close (ifd);
905 return;
907 if (istat.st_mode & S_ISGID)
909 WARN ((stderr, "%s: %s is set-group-ID on execution - ignored\n",
910 program_name, ifname));
911 close (ifd);
912 return;
915 if (! force)
917 if (istat.st_mode & S_ISVTX)
919 WARN ((stderr,
920 "%s: %s has the sticky bit set - file ignored\n",
921 program_name, ifname));
922 close (ifd);
923 return;
925 if (2 <= istat.st_nlink)
927 WARN ((stderr, "%s: %s has %lu other link%s -- file ignored\n",
928 program_name, ifname,
929 (unsigned long int) istat.st_nlink - 1,
930 istat.st_nlink == 2 ? "" : "s"));
931 close (ifd);
932 return;
937 get_input_size_and_time ();
939 /* Generate output file name. For -r and (-t or -l), skip files
940 * without a valid gzip suffix (check done in make_ofname).
942 if (to_stdout && !test) {
943 strcpy(ofname, "stdout");
945 } else if (make_ofname() != OK) {
946 close (ifd);
947 return;
950 clear_bufs(); /* clear input and output buffers */
951 part_nb = 0;
953 if (decompress) {
954 method = get_method(ifd); /* updates ofname if original given */
955 if (method < 0) {
956 close(ifd);
957 return; /* error message already emitted */
961 /* If compressing to a file, check if ofname is not ambiguous
962 * because the operating system truncates names. Otherwise, generate
963 * a new ofname and save the original name in the compressed file.
965 if (to_stdout) {
966 ofd = STDOUT_FILENO;
967 /* Keep remove_ofname_fd negative. */
968 } else {
969 if (create_outfile() != OK) return;
971 if (!decompress && save_orig_name && !verbose && !quiet) {
972 fprintf(stderr, "%s: %s compressed to %s\n",
973 program_name, ifname, ofname);
976 /* Keep the name even if not truncated except with --no-name: */
977 if (!save_orig_name) save_orig_name = !no_name;
979 if (verbose && !list) {
980 fprintf(stderr, "%s:\t", ifname);
983 /* Actually do the compression/decompression. Loop over zipped members.
985 for (;;) {
986 if ((*work)(ifd, ofd) != OK) {
987 method = -1; /* force cleanup */
988 break;
991 if (input_eof ())
992 break;
994 method = get_method(ifd);
995 if (method < 0) break; /* error message already emitted */
998 if (close (ifd) != 0)
999 read_error ();
1001 if (list)
1003 do_list (method);
1004 return;
1007 if (!to_stdout)
1009 copy_stat (&istat);
1011 if ((synchronous
1012 && ((0 <= dfd && fdatasync (dfd) != 0 && errno != EINVAL)
1013 || (fsync (ofd) != 0 && errno != EINVAL)))
1014 || close (ofd) != 0)
1015 write_error ();
1017 if (!keep)
1019 sigset_t oldset;
1020 int unlink_errno;
1021 char *ifbase = last_component (ifname);
1022 int ufd = atdir_eq (ifname, ifbase - ifname) ? dfd : -1;
1023 int res;
1025 sigprocmask (SIG_BLOCK, &caught_signals, &oldset);
1026 remove_ofname_fd = -1;
1027 res = ufd < 0 ? xunlink (ifname) : unlinkat (ufd, ifbase, 0);
1028 unlink_errno = res == 0 ? 0 : errno;
1029 sigprocmask (SIG_SETMASK, &oldset, NULL);
1031 if (unlink_errno)
1032 WARN ((stderr, "%s: %s: %s\n", program_name, ifname,
1033 strerror (unlink_errno)));
1037 if (method == -1) {
1038 if (!to_stdout)
1039 remove_output_file (false);
1040 return;
1043 /* Display statistics */
1044 if(verbose) {
1045 if (test) {
1046 fprintf(stderr, " OK");
1047 } else if (decompress) {
1048 display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out,stderr);
1049 } else {
1050 display_ratio(bytes_in-(bytes_out-header_bytes), bytes_in, stderr);
1052 if (!test)
1053 fprintf(stderr, " -- %s %s", keep ? "created" : "replaced with",
1054 ofname);
1055 fprintf(stderr, "\n");
1059 static void
1060 volatile_strcpy (char volatile *dst, char const volatile *src)
1062 while ((*dst++ = *src++))
1063 continue;
1066 /* ========================================================================
1067 * Create the output file. Return OK or ERROR.
1068 * Try several times if necessary to avoid truncating the z_suffix. For
1069 * example, do not create a compressed file of name "1234567890123."
1070 * Sets save_orig_name to true if the file name has been truncated.
1071 * IN assertions: the input file has already been open (ifd is set) and
1072 * ofname has already been updated if there was an original name.
1073 * OUT assertions: ifd and ofd are closed in case of error.
1075 static int
1076 create_outfile ()
1078 static bool signal_handlers_installed;
1079 int name_shortened = 0;
1080 int flags = (O_WRONLY | O_CREAT | O_EXCL
1081 | (ascii && decompress ? 0 : O_BINARY));
1082 char const *base = ofname;
1083 int atfd = AT_FDCWD;
1085 if (!keep)
1087 char const *b = last_component (ofname);
1088 int f = atdir_set (ofname, b - ofname);
1089 if (0 <= f)
1091 base = b;
1092 atfd = f;
1096 if (!signal_handlers_installed)
1098 signal_handlers_installed = true;
1099 install_signal_handlers ();
1102 for (;;)
1104 int open_errno;
1105 sigset_t oldset;
1107 volatile_strcpy (remove_ofname, ofname);
1109 sigprocmask (SIG_BLOCK, &caught_signals, &oldset);
1110 remove_ofname_fd = ofd = openat (atfd, base, flags, S_IRUSR | S_IWUSR);
1111 open_errno = errno;
1112 sigprocmask (SIG_SETMASK, &oldset, NULL);
1114 if (0 <= ofd)
1115 break;
1117 switch (open_errno)
1119 #ifdef ENAMETOOLONG
1120 case ENAMETOOLONG:
1121 shorten_name (ofname);
1122 name_shortened = 1;
1123 break;
1124 #endif
1126 case EEXIST:
1127 if (check_ofname () != OK)
1129 close (ifd);
1130 return ERROR;
1132 break;
1134 default:
1135 write_error ();
1136 close (ifd);
1137 return ERROR;
1141 if (name_shortened && decompress)
1143 /* name might be too long if an original name was saved */
1144 WARN ((stderr, "%s: %s: warning, name truncated\n",
1145 program_name, ofname));
1148 return OK;
1151 /* ========================================================================
1152 * Return a pointer to the 'z' suffix of a file name, or NULL. For all
1153 * systems, ".gz", ".z", ".Z", ".taz", ".tgz", "-gz", "-z" and "_z" are
1154 * accepted suffixes, in addition to the value of the --suffix option.
1155 * ".tgz" is a useful convention for tar.z files on systems limited
1156 * to 3 characters extensions. On such systems, ".?z" and ".??z" are
1157 * also accepted suffixes. For Unix, we do not want to accept any
1158 * .??z suffix as indicating a compressed file; some people use .xyz
1159 * to denote volume data.
1161 static char *
1162 get_suffix (char *name)
1164 int nlen, slen;
1165 char suffix[MAX_SUFFIX+3]; /* last chars of name, forced to lower case */
1166 static char const *known_suffixes[] =
1167 {NULL, ".gz", ".z", ".taz", ".tgz", "-gz", "-z", "_z",
1168 #ifdef MAX_EXT_CHARS
1169 "z",
1170 #endif
1171 NULL, NULL};
1172 char const **suf;
1173 bool suffix_of_builtin = false;
1175 /* Normally put Z_SUFFIX at the start of KNOWN_SUFFIXES, but if it
1176 is a suffix of one of them, put it at the end. */
1177 for (suf = known_suffixes + 1; *suf; suf++)
1179 size_t suflen = strlen (*suf);
1180 if (z_len < suflen && strequ (z_suffix, *suf + suflen - z_len))
1182 suffix_of_builtin = true;
1183 break;
1187 char *z_lower = xstrdup(z_suffix);
1188 strlwr(z_lower);
1189 known_suffixes[suffix_of_builtin
1190 ? sizeof known_suffixes / sizeof *known_suffixes - 2
1191 : 0] = z_lower;
1192 suf = known_suffixes + suffix_of_builtin;
1194 nlen = strlen(name);
1195 if (nlen <= MAX_SUFFIX+2) {
1196 strcpy(suffix, name);
1197 } else {
1198 strcpy(suffix, name+nlen-MAX_SUFFIX-2);
1200 strlwr(suffix);
1201 slen = strlen(suffix);
1202 char *match = NULL;
1203 do {
1204 int s = strlen(*suf);
1205 if (slen > s && ! ISSLASH (suffix[slen - s - 1])
1206 && strequ(suffix + slen - s, *suf)) {
1207 match = name+nlen-s;
1208 break;
1210 } while (*++suf != NULL);
1211 free(z_lower);
1213 return match;
1217 /* Open file NAME with the given flags and store its status
1218 into *ST. Return a file descriptor to the newly opened file, or -1
1219 (setting errno) on failure. */
1220 static int
1221 open_and_stat (char *name, int flags, struct stat *st)
1223 int fd;
1224 int atfd = AT_FDCWD;
1225 char const *base = name;
1227 /* Refuse to follow symbolic links unless -c or -f. */
1228 if (!to_stdout && !force)
1230 if (HAVE_WORKING_O_NOFOLLOW)
1231 flags |= O_NOFOLLOW;
1232 else
1234 #ifdef S_ISLNK
1235 if (lstat (name, st) != 0)
1236 return -1;
1237 else if (S_ISLNK (st->st_mode))
1239 errno = ELOOP;
1240 return -1;
1242 #endif
1246 if (!keep)
1248 char const *b = last_component (name);
1249 int f = atdir_set (name, b - name);
1250 if (0 <= f)
1252 base = b;
1253 atfd = f;
1257 fd = openat (atfd, base, flags);
1258 if (0 <= fd && fstat (fd, st) != 0)
1260 int e = errno;
1261 close (fd);
1262 errno = e;
1263 return -1;
1265 return fd;
1269 /* ========================================================================
1270 * Set ifname to the input file name (with a suffix appended if necessary)
1271 * and istat to its stats. For decompression, if no file exists with the
1272 * original name, try adding successively z_suffix, .gz, .z, -z and .Z.
1273 * For MSDOS, we try only z_suffix and z.
1274 * Return an open file descriptor or -1.
1276 static int
1277 open_input_file (char *iname, struct stat *sbuf)
1279 int ilen; /* strlen(ifname) */
1280 int z_suffix_errno = 0;
1281 static char const *suffixes[] = {NULL, ".gz", ".z", "-z", ".Z", NULL};
1282 char const **suf = suffixes;
1283 char const *s;
1284 #ifdef NO_MULTIPLE_DOTS
1285 char *dot; /* pointer to ifname extension, or NULL */
1286 #endif
1287 int fd;
1288 int open_flags = (O_RDONLY | O_NONBLOCK | O_NOCTTY
1289 | (ascii && !decompress ? 0 : O_BINARY));
1291 *suf = z_suffix;
1293 if (sizeof ifname - 1 <= strlen (iname))
1294 goto name_too_long;
1296 strcpy(ifname, iname);
1298 /* If input file exists, return OK. */
1299 fd = open_and_stat (ifname, open_flags, sbuf);
1300 if (0 <= fd)
1301 return fd;
1303 if (!decompress || errno != ENOENT) {
1304 progerror(ifname);
1305 return -1;
1307 /* File.ext doesn't exist. Try adding a suffix. */
1308 s = get_suffix(ifname);
1309 if (s != NULL) {
1310 progerror(ifname); /* ifname already has z suffix and does not exist */
1311 return -1;
1313 #ifdef NO_MULTIPLE_DOTS
1314 dot = strrchr(ifname, '.');
1315 if (dot == NULL) {
1316 strcat(ifname, ".");
1317 dot = strrchr(ifname, '.');
1319 #endif
1320 ilen = strlen(ifname);
1321 if (strequ(z_suffix, ".gz")) suf++;
1323 /* Search for all suffixes */
1324 do {
1325 char const *s0 = s = *suf;
1326 strcpy (ifname, iname);
1327 #ifdef NO_MULTIPLE_DOTS
1328 if (*s == '.') s++;
1329 if (*dot == '\0') strcpy (dot, ".");
1330 #endif
1331 #ifdef MAX_EXT_CHARS
1332 if (MAX_EXT_CHARS < strlen (s) + strlen (dot + 1))
1333 dot[MAX_EXT_CHARS + 1 - strlen (s)] = '\0';
1334 #endif
1335 if (sizeof ifname <= ilen + strlen (s))
1336 goto name_too_long;
1337 strcat(ifname, s);
1338 fd = open_and_stat (ifname, open_flags, sbuf);
1339 if (0 <= fd)
1340 return fd;
1341 if (errno != ENOENT)
1343 progerror (ifname);
1344 return -1;
1346 if (strequ (s0, z_suffix))
1347 z_suffix_errno = errno;
1348 } while (*++suf != NULL);
1350 /* No suffix found, complain using z_suffix: */
1351 strcpy(ifname, iname);
1352 #ifdef NO_MULTIPLE_DOTS
1353 if (*dot == '\0') strcpy(dot, ".");
1354 #endif
1355 #ifdef MAX_EXT_CHARS
1356 if (MAX_EXT_CHARS < z_len + strlen (dot + 1))
1357 dot[MAX_EXT_CHARS + 1 - z_len] = '\0';
1358 #endif
1359 strcat(ifname, z_suffix);
1360 errno = z_suffix_errno;
1361 progerror(ifname);
1362 return -1;
1364 name_too_long:
1365 fprintf (stderr, "%s: %s: file name too long\n", program_name, iname);
1366 exit_code = ERROR;
1367 return -1;
1370 /* ========================================================================
1371 * Generate ofname given ifname. Return OK, or WARNING if file must be skipped.
1372 * Sets save_orig_name to true if the file name has been truncated.
1374 static int
1375 make_ofname ()
1377 char *suff; /* ofname z suffix */
1379 strcpy(ofname, ifname);
1380 /* strip a version number if any and get the gzip suffix if present: */
1381 suff = get_suffix(ofname);
1383 if (decompress) {
1384 if (suff == NULL) {
1385 /* With -t or -l, try all files (even without .gz suffix)
1386 * except with -r (behave as with just -dr).
1388 if (!recursive && test)
1389 return OK;
1391 /* Avoid annoying messages with -r */
1392 if (verbose || (!recursive && !quiet)) {
1393 WARN((stderr,"%s: %s: unknown suffix -- ignored\n",
1394 program_name, ifname));
1396 return WARNING;
1398 /* Make a special case for .tgz and .taz: */
1399 strlwr(suff);
1400 if (strequ(suff, ".tgz") || strequ(suff, ".taz")) {
1401 strcpy(suff, ".tar");
1402 } else {
1403 *suff = '\0'; /* strip the z suffix */
1405 /* ofname might be changed later if infile contains an original name */
1407 } else if (suff && ! force) {
1408 /* Avoid annoying messages with -r (see treat_dir()) */
1409 if (verbose || (!recursive && !quiet)) {
1410 /* Don't use WARN, as it affects exit status. */
1411 fprintf (stderr, "%s: %s already has %s suffix -- unchanged\n",
1412 program_name, ifname, suff);
1414 return WARNING;
1415 } else {
1416 save_orig_name = 0;
1418 #ifdef NO_MULTIPLE_DOTS
1419 suff = strrchr(ofname, '.');
1420 if (suff == NULL) {
1421 if (sizeof ofname <= strlen (ofname) + 1)
1422 goto name_too_long;
1423 strcat(ofname, ".");
1424 # ifdef MAX_EXT_CHARS
1425 if (strequ(z_suffix, "z")) {
1426 if (sizeof ofname <= strlen (ofname) + 2)
1427 goto name_too_long;
1428 strcat(ofname, "gz"); /* enough room */
1429 return OK;
1431 /* On the Atari and some versions of MSDOS,
1432 * ENAMETOOLONG does not work correctly. So we
1433 * must truncate here.
1435 } else if (strlen(suff)-1 + z_len > MAX_SUFFIX) {
1436 suff[MAX_SUFFIX+1-z_len] = '\0';
1437 save_orig_name = 1;
1438 # endif
1440 #endif /* NO_MULTIPLE_DOTS */
1441 if (sizeof ofname <= strlen (ofname) + z_len)
1442 goto name_too_long;
1443 strcat(ofname, z_suffix);
1445 } /* decompress ? */
1446 return OK;
1448 name_too_long:
1449 WARN ((stderr, "%s: %s: file name too long\n", program_name, ifname));
1450 return WARNING;
1453 /* Discard NBYTES input bytes from the input, or up through the next
1454 zero byte if NBYTES == (size_t) -1. If FLAGS say that the header
1455 CRC should be computed, update the CRC accordingly. */
1456 static void
1457 discard_input_bytes (size_t nbytes, unsigned int flags)
1459 while (nbytes != 0)
1461 uch c = get_byte ();
1462 if (flags & HEADER_CRC)
1463 updcrc (&c, 1);
1464 if (nbytes != (size_t) -1)
1465 nbytes--;
1466 else if (! c)
1467 break;
1471 /* ========================================================================
1472 * Check the magic number of the input file and update ofname if an
1473 * original name was given and to_stdout is not set.
1474 * Return the compression method, -1 for error, -2 for warning.
1475 * Set inptr to the offset of the next byte to be processed.
1476 * Updates time_stamp if there is one and neither -m nor -n is used.
1477 * This function may be called repeatedly for an input file consisting
1478 * of several contiguous gzip'ed members.
1479 * 'in' is the input file descriptor.
1480 * IN assertions: there is at least one remaining compressed member.
1481 * If the member is a zip file, it must be the only one.
1483 static int
1484 get_method (int in)
1486 uch flags; /* compression flags */
1487 uch magic[10]; /* magic header */
1488 int imagic0; /* first magic byte or EOF */
1489 int imagic1; /* like magic[1], but can represent EOF */
1490 ulg stamp; /* timestamp */
1492 /* If --force and --stdout, zcat == cat, so do not complain about
1493 * premature end of file: use try_byte instead of get_byte.
1495 if (force && to_stdout) {
1496 imagic0 = try_byte();
1497 magic[0] = imagic0;
1498 imagic1 = try_byte ();
1499 magic[1] = imagic1;
1500 /* If try_byte returned EOF, magic[1] == (char) EOF. */
1501 } else {
1502 magic[0] = get_byte ();
1503 imagic0 = 0;
1504 if (magic[0]) {
1505 magic[1] = get_byte ();
1506 imagic1 = 0; /* avoid lint warning */
1507 } else {
1508 imagic1 = try_byte ();
1509 magic[1] = imagic1;
1512 method = -1; /* unknown yet */
1513 part_nb++; /* number of parts in gzip file */
1514 header_bytes = 0;
1515 last_member = 0;
1516 /* assume multiple members in gzip file except for record oriented I/O */
1518 if (memcmp(magic, GZIP_MAGIC, 2) == 0
1519 || memcmp(magic, OLD_GZIP_MAGIC, 2) == 0) {
1521 method = (int)get_byte();
1522 if (method != DEFLATED) {
1523 fprintf(stderr,
1524 "%s: %s: unknown method %d -- not supported\n",
1525 program_name, ifname, method);
1526 exit_code = ERROR;
1527 return -1;
1529 work = unzip;
1530 flags = (uch)get_byte();
1532 if ((flags & ENCRYPTED) != 0) {
1533 fprintf(stderr,
1534 "%s: %s is encrypted -- not supported\n",
1535 program_name, ifname);
1536 exit_code = ERROR;
1537 return -1;
1539 if ((flags & RESERVED) != 0) {
1540 fprintf(stderr,
1541 "%s: %s has flags 0x%x -- not supported\n",
1542 program_name, ifname, flags);
1543 exit_code = ERROR;
1544 if (force <= 1) return -1;
1546 stamp = (ulg)get_byte();
1547 stamp |= ((ulg)get_byte()) << 8;
1548 stamp |= ((ulg)get_byte()) << 16;
1549 stamp |= ((ulg)get_byte()) << 24;
1550 if (stamp != 0 && !no_time)
1552 if (stamp <= TYPE_MAXIMUM (time_t))
1554 time_stamp.tv_sec = stamp;
1555 time_stamp.tv_nsec = 0;
1557 else
1559 WARN ((stderr,
1560 "%s: %s: MTIME %lu out of range for this platform\n",
1561 program_name, ifname, stamp));
1562 time_stamp.tv_sec = TYPE_MAXIMUM (time_t);
1563 time_stamp.tv_nsec = TIMESPEC_RESOLUTION - 1;
1567 magic[8] = get_byte (); /* Ignore extra flags. */
1568 magic[9] = get_byte (); /* Ignore OS type. */
1570 if (flags & HEADER_CRC)
1572 magic[2] = DEFLATED;
1573 magic[3] = flags;
1574 magic[4] = stamp & 0xff;
1575 magic[5] = (stamp >> 8) & 0xff;
1576 magic[6] = (stamp >> 16) & 0xff;
1577 magic[7] = stamp >> 24;
1578 updcrc (NULL, 0);
1579 updcrc (magic, 10);
1582 if ((flags & EXTRA_FIELD) != 0) {
1583 uch lenbuf[2];
1584 unsigned int len = lenbuf[0] = get_byte ();
1585 len |= (lenbuf[1] = get_byte ()) << 8;
1586 if (verbose) {
1587 fprintf(stderr,"%s: %s: extra field of %u bytes ignored\n",
1588 program_name, ifname, len);
1590 if (flags & HEADER_CRC)
1591 updcrc (lenbuf, 2);
1592 discard_input_bytes (len, flags);
1595 /* Get original file name if it was truncated */
1596 if ((flags & ORIG_NAME) != 0) {
1597 if (no_name || (to_stdout && !list) || part_nb > 1) {
1598 /* Discard the old name */
1599 discard_input_bytes (-1, flags);
1600 } else {
1601 /* Copy the base name. Keep a directory prefix intact. */
1602 char *p = gzip_base_name (ofname);
1603 char *base = p;
1604 for (;;) {
1605 *p = (char) get_byte ();
1606 if (*p++ == '\0') break;
1607 if (p >= ofname+sizeof(ofname)) {
1608 gzip_error ("corrupted input -- file name too large");
1611 if (flags & HEADER_CRC)
1612 updcrc ((uch *) base, p - base);
1613 p = gzip_base_name (base);
1614 memmove (base, p, strlen (p) + 1);
1615 /* If necessary, adapt the name to local OS conventions: */
1616 if (!list) {
1617 MAKE_LEGAL_NAME(base);
1618 if (base) list=0; /* avoid warning about unused variable */
1620 } /* no_name || to_stdout */
1621 } /* ORIG_NAME */
1623 /* Discard file comment if any */
1624 if ((flags & COMMENT) != 0) {
1625 discard_input_bytes (-1, flags);
1628 if (flags & HEADER_CRC)
1630 unsigned int crc16 = updcrc (magic, 0) & 0xffff;
1631 unsigned int header16 = get_byte ();
1632 header16 |= ((unsigned int) get_byte ()) << 8;
1633 if (header16 != crc16)
1635 fprintf (stderr,
1636 "%s: %s: header checksum 0x%04x != computed checksum 0x%04x\n",
1637 program_name, ifname, header16, crc16);
1638 exit_code = ERROR;
1639 if (force <= 1)
1640 return -1;
1644 if (part_nb == 1) {
1645 header_bytes = inptr + 2*4; /* include crc and size */
1648 } else if (memcmp(magic, PKZIP_MAGIC, 2) == 0 && inptr == 2
1649 && memcmp((char*)inbuf, PKZIP_MAGIC, 4) == 0) {
1650 /* To simplify the code, we support a zip file when alone only.
1651 * We are thus guaranteed that the entire local header fits in inbuf.
1653 inptr = 0;
1654 work = unzip;
1655 if (check_zipfile(in) != OK) return -1;
1656 /* check_zipfile may get ofname from the local header */
1657 last_member = 1;
1659 } else if (memcmp(magic, PACK_MAGIC, 2) == 0) {
1660 work = unpack;
1661 method = PACKED;
1663 } else if (memcmp(magic, LZW_MAGIC, 2) == 0) {
1664 work = unlzw;
1665 method = COMPRESSED;
1666 last_member = 1;
1668 } else if (memcmp(magic, LZH_MAGIC, 2) == 0) {
1669 work = unlzh;
1670 method = LZHED;
1671 last_member = 1;
1673 } else if (force && to_stdout && !list) { /* pass input unchanged */
1674 method = STORED;
1675 work = copy;
1676 if (imagic1 != EOF)
1677 inptr--;
1678 last_member = 1;
1679 if (imagic0 != EOF) {
1680 write_buf (STDOUT_FILENO, magic, 1);
1683 if (method >= 0) return method;
1685 if (part_nb == 1) {
1686 fprintf (stderr, "\n%s: %s: not in gzip format\n",
1687 program_name, ifname);
1688 exit_code = ERROR;
1689 return -1;
1690 } else {
1691 if (magic[0] == 0)
1693 int inbyte;
1694 for (inbyte = imagic1; inbyte == 0; inbyte = try_byte ())
1695 continue;
1696 if (inbyte == EOF)
1698 if (verbose)
1699 WARN ((stderr, "\n%s: %s: decompression OK, trailing zero bytes ignored\n",
1700 program_name, ifname));
1701 return -3;
1705 WARN((stderr, "\n%s: %s: decompression OK, trailing garbage ignored\n",
1706 program_name, ifname));
1707 return -2;
1711 /* ========================================================================
1712 * Display the characteristics of the compressed file.
1713 * If the given method is < 0, display the accumulated totals.
1714 * IN assertions: time_stamp, header_bytes and ifile_size are initialized.
1716 static void
1717 do_list (int method)
1719 ulg crc; /* original crc */
1720 static int first_time = 1;
1721 static char const *const methods[MAX_METHODS] = {
1722 "store", /* 0 */
1723 "compr", /* 1 */
1724 "pack ", /* 2 */
1725 "lzh ", /* 3 */
1726 "", "", "", "", /* 4 to 7 reserved */
1727 "defla"}; /* 8 */
1728 int positive_off_t_width = INT_STRLEN_BOUND (off_t) - 1;
1730 if (first_time && method >= 0) {
1731 first_time = 0;
1732 if (verbose) {
1733 printf("method crc date time ");
1735 if (!quiet) {
1736 printf("%*.*s %*.*s ratio uncompressed_name\n",
1737 positive_off_t_width, positive_off_t_width, "compressed",
1738 positive_off_t_width, positive_off_t_width, "uncompressed");
1740 } else if (method < 0) {
1741 if (total_in <= 0 || total_out <= 0) return;
1742 if (verbose) {
1743 printf(" ");
1745 if (verbose || !quiet) {
1746 fprint_off(stdout, total_in, positive_off_t_width);
1747 printf(" ");
1748 fprint_off(stdout, total_out, positive_off_t_width);
1749 printf(" ");
1751 display_ratio(total_out-(total_in-header_bytes), total_out, stdout);
1752 /* header_bytes is not meaningful but used to ensure the same
1753 * ratio if there is a single file.
1755 printf(" (totals)\n");
1756 return;
1758 crc = (ulg)~0; /* unknown */
1760 if (method == DEFLATED && !last_member) {
1761 crc = unzip_crc;
1764 if (verbose)
1766 static char const month_abbr[][4]
1767 = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1768 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
1769 struct tm *tm = localtime (&time_stamp.tv_sec);
1770 printf ("%5s %08lx ", methods[method], crc);
1771 if (tm)
1772 printf ("%s%3d %02d:%02d ", month_abbr[tm->tm_mon],
1773 tm->tm_mday, tm->tm_hour, tm->tm_min);
1774 else
1775 printf ("??? ?? ??:?? ");
1777 fprint_off(stdout, bytes_in, positive_off_t_width);
1778 printf(" ");
1779 fprint_off(stdout, bytes_out, positive_off_t_width);
1780 printf(" ");
1781 if (bytes_in == -1L) {
1782 total_in = -1L;
1783 bytes_in = bytes_out = header_bytes = 0;
1784 } else if (total_in >= 0) {
1785 total_in += bytes_in;
1787 if (bytes_out == -1L) {
1788 total_out = -1L;
1789 bytes_in = bytes_out = header_bytes = 0;
1790 } else if (total_out >= 0) {
1791 total_out += bytes_out;
1793 display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out, stdout);
1794 printf(" %s\n", ofname);
1797 /* ========================================================================
1798 * Shorten the given name by one character, or replace a .tar extension
1799 * with .tgz. Truncate the last part of the name which is longer than
1800 * MIN_PART characters: 1234.678.012.gz -> 123.678.012.gz. If the name
1801 * has only parts shorter than MIN_PART truncate the longest part.
1802 * For decompression, just remove the last character of the name.
1804 * IN assertion: for compression, the suffix of the given name is z_suffix.
1806 static void
1807 shorten_name (char *name)
1809 int len; /* length of name without z_suffix */
1810 char *trunc = NULL; /* character to be truncated */
1811 int plen; /* current part length */
1812 int min_part = MIN_PART; /* current minimum part length */
1813 char *p;
1815 len = strlen(name);
1816 if (decompress) {
1817 if (len <= 1)
1818 gzip_error ("name too short");
1819 name[len-1] = '\0';
1820 return;
1822 p = get_suffix(name);
1823 if (! p)
1824 gzip_error ("can't recover suffix\n");
1825 *p = '\0';
1826 save_orig_name = 1;
1828 /* compress 1234567890.tar to 1234567890.tgz */
1829 if (len > 4 && strequ(p-4, ".tar")) {
1830 strcpy(p-4, ".tgz");
1831 return;
1833 /* Try keeping short extensions intact:
1834 * 1234.678.012.gz -> 123.678.012.gz
1836 do {
1837 p = last_component (name);
1838 while (*p) {
1839 plen = strcspn(p, PART_SEP);
1840 p += plen;
1841 if (plen > min_part) trunc = p-1;
1842 if (*p) p++;
1844 } while (trunc == NULL && --min_part != 0);
1846 if (trunc != NULL) {
1847 do {
1848 trunc[0] = trunc[1];
1849 } while (*trunc++);
1850 trunc--;
1851 } else {
1852 trunc = strrchr(name, PART_SEP[0]);
1853 if (!trunc)
1854 gzip_error ("internal error in shorten_name");
1855 if (trunc[1] == '\0') trunc--; /* force truncation */
1857 strcpy(trunc, z_suffix);
1860 /* ========================================================================
1861 * The compressed file already exists, so ask for confirmation.
1862 * Return ERROR if the file must be skipped.
1864 static int
1865 check_ofname ()
1867 /* Ask permission to overwrite the existing file */
1868 if (!force) {
1869 int ok = 0;
1870 fprintf (stderr, "%s: %s already exists;", program_name, ofname);
1871 if (foreground && (presume_input_tty || isatty (STDIN_FILENO))) {
1872 fprintf(stderr, " do you wish to overwrite (y or n)? ");
1873 fflush(stderr);
1874 ok = yesno();
1876 if (!ok) {
1877 fprintf(stderr, "\tnot overwritten\n");
1878 if (exit_code == OK) exit_code = WARNING;
1879 return ERROR;
1882 if (xunlink (ofname)) {
1883 progerror(ofname);
1884 return ERROR;
1886 return OK;
1889 /* Change the owner and group of a file. FD is a file descriptor for
1890 the file and NAME its name. Change it to user UID and to group GID.
1891 If UID or GID is -1, though, do not change the corresponding user
1892 or group. */
1893 #if ! (HAVE_FCHOWN || HAVE_CHOWN)
1894 /* The types uid_t and gid_t do not exist on mingw, so don't assume them. */
1895 # define do_chown(fd, name, uid, gid) ((void) 0)
1896 #else
1897 static void
1898 do_chown (int fd, char const *name, uid_t uid, gid_t gid)
1900 # if HAVE_FCHOWN
1901 ignore_value (fchown (fd, uid, gid));
1902 # else
1903 ignore_value (chown (name, uid, gid));
1904 # endif
1906 #endif
1908 /* ========================================================================
1909 * Copy modes, times, ownership from input file to output file.
1910 * IN assertion: to_stdout is false.
1912 static void
1913 copy_stat (struct stat *ifstat)
1915 mode_t mode = ifstat->st_mode & S_IRWXUGO;
1916 int r;
1918 #ifndef NO_UTIME
1919 bool restoring;
1920 struct timespec timespec[2];
1921 timespec[0] = get_stat_atime (ifstat);
1922 timespec[1] = get_stat_mtime (ifstat);
1923 restoring = (decompress && 0 <= time_stamp.tv_nsec
1924 && ! (timespec[1].tv_sec == time_stamp.tv_sec
1925 && timespec[1].tv_nsec == time_stamp.tv_nsec));
1926 if (restoring)
1927 timespec[1] = time_stamp;
1929 if (fdutimens (ofd, ofname, timespec) == 0)
1931 if (restoring && 1 < verbose) {
1932 fprintf(stderr, "%s: timestamp restored\n", ofname);
1935 else
1936 WARN ((stderr, "%s: %s: %s\n", program_name, ofname, strerror (errno)));
1937 #endif
1939 /* Change the group first, then the permissions, then the owner.
1940 That way, the permissions will be correct on systems that allow
1941 users to give away files, without introducing a security hole.
1942 Security depends on permissions not containing the setuid or
1943 setgid bits. */
1945 do_chown (ofd, ofname, -1, ifstat->st_gid);
1947 #if HAVE_FCHMOD
1948 r = fchmod (ofd, mode);
1949 #else
1950 r = chmod (ofname, mode);
1951 #endif
1952 if (r != 0)
1953 WARN ((stderr, "%s: %s: %s\n", program_name, ofname, strerror (errno)));
1955 do_chown (ofd, ofname, ifstat->st_uid, -1);
1958 #if ! NO_DIR
1960 /* ========================================================================
1961 * Recurse through the given directory.
1963 static void
1964 treat_dir (int fd, char *dir)
1966 DIR *dirp;
1967 char nbuf[MAX_PATH_LEN];
1968 char *entries;
1969 char const *entry;
1970 size_t entrylen;
1972 dirp = fdopendir (fd);
1974 if (dirp == NULL) {
1975 progerror(dir);
1976 close (fd);
1977 return ;
1980 entries = streamsavedir (dirp, SAVEDIR_SORT_NONE);
1981 if (! entries)
1982 progerror (dir);
1983 if (closedir (dirp) != 0)
1984 progerror (dir);
1985 if (! entries)
1986 return;
1988 for (entry = entries; *entry; entry += entrylen + 1) {
1989 size_t len = strlen (dir);
1990 entrylen = strlen (entry);
1991 if (strequ (entry, ".") || strequ (entry, ".."))
1992 continue;
1993 if (len + entrylen < MAX_PATH_LEN - 2) {
1994 strcpy(nbuf,dir);
1995 if (*last_component (nbuf) && !ISSLASH (nbuf[len - 1]))
1996 nbuf[len++] = '/';
1997 strcpy (nbuf + len, entry);
1998 treat_file(nbuf);
1999 } else {
2000 fprintf(stderr,"%s: %s/%s: pathname too long\n",
2001 program_name, dir, entry);
2002 exit_code = ERROR;
2005 free (entries);
2007 #endif /* ! NO_DIR */
2009 /* Make sure signals get handled properly. */
2011 static void
2012 install_signal_handlers ()
2014 int nsigs = sizeof handled_sig / sizeof handled_sig[0];
2015 int i;
2016 struct sigaction act;
2018 sigemptyset (&caught_signals);
2019 for (i = 0; i < nsigs; i++)
2021 sigaction (handled_sig[i], NULL, &act);
2022 if (act.sa_handler != SIG_IGN)
2023 sigaddset (&caught_signals, handled_sig[i]);
2026 act.sa_handler = abort_gzip_signal;
2027 act.sa_mask = caught_signals;
2028 act.sa_flags = 0;
2030 for (i = 0; i < nsigs; i++)
2031 if (sigismember (&caught_signals, handled_sig[i]))
2033 if (i == 0)
2034 foreground = 1;
2035 sigaction (handled_sig[i], &act, NULL);
2039 /* ========================================================================
2040 * Free all dynamically allocated variables and exit with the given code.
2042 static void
2043 do_exit (int exitcode)
2045 static int in_exit = 0;
2047 if (in_exit) exit(exitcode);
2048 in_exit = 1;
2049 free(env);
2050 env = NULL;
2051 FREE(inbuf);
2052 FREE(outbuf);
2053 FREE(d_buf);
2054 FREE(window);
2055 #ifndef MAXSEG_64K
2056 FREE(tab_prefix);
2057 #else
2058 FREE(tab_prefix0);
2059 FREE(tab_prefix1);
2060 #endif
2061 exit(exitcode);
2064 static void
2065 finish_out ()
2067 if (fclose (stdout) != 0)
2068 write_error ();
2069 do_exit (OK);
2072 /* ========================================================================
2073 * Close and unlink the output file.
2075 static void
2076 remove_output_file (bool signals_already_blocked)
2078 int fd;
2079 sigset_t oldset;
2081 if (!signals_already_blocked)
2082 sigprocmask (SIG_BLOCK, &caught_signals, &oldset);
2083 fd = remove_ofname_fd;
2084 if (0 <= fd)
2086 char fname[MAX_PATH_LEN];
2087 remove_ofname_fd = -1;
2088 close (fd);
2089 volatile_strcpy (fname, remove_ofname);
2090 xunlink (fname);
2092 if (!signals_already_blocked)
2093 sigprocmask (SIG_SETMASK, &oldset, NULL);
2096 /* ========================================================================
2097 * Error handler.
2099 void
2100 finish_up_gzip (int exitcode)
2102 if (0 <= remove_ofname_fd)
2103 remove_output_file (false);
2104 do_exit (exitcode);
2106 void
2107 abort_gzip ()
2109 finish_up_gzip (ERROR);
2111 /* ========================================================================
2112 * Signal handler.
2114 static void
2115 abort_gzip_signal (int sig)
2117 remove_output_file (true);
2118 signal (sig, SIG_DFL);
2119 raise (sig);