tests: reference: don't rely on od's -w option
[gzip.git] / gzip.c
blob7a0625e656301fd63089493e1b85b17475981d3f
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, see <https://www.gnu.org/licenses/>. */
21 * The unzip code was written and put in the public domain by Mark Adler.
22 * Portions of the lzw code are derived from the public domain 'compress'
23 * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies,
24 * Ken Turkowski, Dave Mack and Peter Jannesen.
26 * See the license_msg below and the file COPYING for the software license.
27 * See the file algorithm.doc for the compression algorithms and file formats.
30 static char const *const license_msg[] = {
31 "Copyright (C) 2024 Free Software Foundation, Inc.",
32 "Copyright (C) 1993 Jean-loup Gailly.",
33 "This is free software. You may redistribute copies of it under the terms of",
34 "the GNU General Public License <https://www.gnu.org/licenses/gpl.html>.",
35 "There is NO WARRANTY, to the extent permitted by law.",
36 0};
38 /* Compress files with zip algorithm and 'compress' interface.
39 * See help() function below for all options.
40 * Outputs:
41 * file.gz: compressed file with same mode, owner, and utimes
42 * or stdout with -c option or if stdin used as input.
43 * If the output file name had to be truncated, the original name is kept
44 * in the compressed file.
45 * On MSDOS, file.tmp -> file.tmz.
47 * Using gz on MSDOS would create too many file name conflicts. For
48 * example, foo.txt -> foo.tgz (.tgz must be reserved as shorthand for
49 * tar.gz). Similarly, foo.dir and foo.doc would both be mapped to foo.dgz.
50 * I also considered 12345678.txt -> 12345txt.gz but this truncates the name
51 * too heavily. There is no ideal solution given the MSDOS 8+3 limitation.
53 * For the meaning of all compilation flags, see comments in Makefile.in.
56 #include <config.h>
57 #include <ctype.h>
58 #include <sys/types.h>
59 #include <signal.h>
60 #include <stddef.h>
61 #include <sys/stat.h>
62 #include <getopt.h>
63 #include <errno.h>
65 #include "tailor.h"
66 #include "gzip.h"
67 #include "intprops.h"
68 #include "lzw.h"
69 #include "revision.h"
70 #include "timespec.h"
72 #include "dirname.h"
73 #include "fcntl--.h"
74 #include "filename.h"
75 #include "ignore-value.h"
76 #include "stat-time.h"
77 #include "version.h"
78 #include "xalloc.h"
79 #include "yesno.h"
81 /* configuration */
83 #include <limits.h>
84 #include <inttypes.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 #ifdef off_t
109 off_t lseek (int fd, off_t offset, int whence);
110 #endif
112 #ifndef HAVE_WORKING_O_NOFOLLOW
113 # define HAVE_WORKING_O_NOFOLLOW 0
114 #endif
116 /* Separator for file name parts (see shorten_name()) */
117 #ifdef NO_MULTIPLE_DOTS
118 # define PART_SEP "-"
119 #else
120 # define PART_SEP "."
121 #endif
123 /* global buffers */
125 /* With IBM_Z_DFLTCC, DEFLATE COMPRESSION works faster with
126 page-aligned input and output buffers, and requires page-aligned
127 windows; the alignment requirement is 4096. On other platforms
128 alignment doesn't hurt, and alignment up to 4096 is portable so
129 let's do that. */
130 #if defined HAVE_C_ALIGNASOF || defined alignas
131 # define BUFFER_ALIGNED alignas (4096)
132 #else
133 # define BUFFER_ALIGNED /**/
134 #endif
135 DECLARE(uch BUFFER_ALIGNED, inbuf, INBUFSIZ +INBUF_EXTRA);
136 DECLARE(uch BUFFER_ALIGNED, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
137 DECLARE(ush, d_buf, DIST_BUFSIZE);
138 DECLARE(uch BUFFER_ALIGNED, window, 2L*WSIZE);
139 #ifndef MAXSEG_64K
140 DECLARE(ush, tab_prefix, 1L<<BITS);
141 #else
142 DECLARE(ush, tab_prefix0, 1L<<(BITS-1));
143 DECLARE(ush, tab_prefix1, 1L<<(BITS-1));
144 #endif
146 /* local variables */
148 /* If true, pretend that standard input is a tty. This option
149 is deliberately not documented, and only for testing. */
150 static bool presume_input_tty;
152 /* If true, transfer output data to the output file's storage device
153 when supported. Otherwise, if the system crashes around the time
154 gzip is run, the user might lose both input and output data. See:
155 Pillai TS et al. All file systems are not created equal: on the
156 complexity of crafting crash-consistent applications. OSDI'14. 2014:433-48.
157 https://www.usenix.org/conference/osdi14/technical-sessions/presentation/pillai */
158 static bool synchronous;
160 static int ascii = 0; /* convert end-of-lines to local OS conventions */
161 int to_stdout = 0; /* output to stdout (-c) */
162 static int decompress = 0; /* decompress (-d) */
163 static int force = 0; /* don't ask questions, compress links (-f) */
164 static int keep = 0; /* keep (don't delete) input files */
165 static int no_name = -1; /* don't save or restore the original file name */
166 static int no_time = -1; /* don't save or restore the original file time */
167 static int recursive = 0; /* recurse through directories (-r) */
168 static int list = 0; /* list the file contents (-l) */
169 #ifndef DEBUG
170 static
171 #endif
172 int verbose = 0; /* be verbose (-v) */
173 int quiet = 0; /* be very quiet (-q) */
174 int test = 0; /* test .gz file integrity */
175 static int foreground = 0; /* set if program run in foreground */
176 char *program_name; /* program name */
177 int maxbits = BITS; /* max bits per code for LZW */
178 int method = DEFLATED;/* compression method */
179 int level = 6; /* compression level */
180 int exit_code = OK; /* program exit code */
181 int save_orig_name; /* set if original name must be saved */
182 static int last_member; /* set for .zip and .Z files */
183 static int part_nb; /* number of parts in .gz file */
184 off_t ifile_size; /* input file size, -1 for devices (debug only) */
185 static char *env; /* contents of GZIP env variable */
186 static char const *z_suffix; /* default suffix (can be set with --suffix) */
187 static size_t z_len; /* strlen(z_suffix) */
189 /* The original timestamp (modification time). If the original is
190 unknown, TIME_STAMP.tv_nsec is negative. If the original is
191 greater than struct timespec range, TIME_STAMP is the maximal
192 struct timespec value; this can happen on hosts with 32-bit signed
193 time_t because the gzip format's MTIME is 32-bit unsigned.
194 The original cannot be less than struct timespec range. */
195 struct timespec time_stamp;
197 /* The set of signals that are caught. */
198 static sigset_t caught_signals;
200 /* If nonnegative, close this file descriptor and unlink remove_ofname
201 on error. */
202 static int volatile remove_ofname_fd = -1;
203 static char volatile remove_ofname[MAX_PATH_LEN];
205 static bool stdin_was_read;
207 off_t bytes_in; /* number of input bytes */
208 off_t bytes_out; /* number of output bytes */
209 static off_t total_in; /* input bytes for all files */
210 static off_t total_out; /* output bytes for all files */
211 char ifname[MAX_PATH_LEN]; /* input file name */
212 char ofname[MAX_PATH_LEN]; /* output file name */
213 static char dfname[MAX_PATH_LEN]; /* name of dir containing output file */
214 static struct stat istat; /* status for input file */
215 int ifd; /* input file descriptor */
216 int ofd; /* output file descriptor */
217 static int dfd = -1; /* output directory file descriptor */
218 unsigned insize; /* valid bytes in inbuf */
219 unsigned inptr; /* index of next byte to be processed in inbuf */
220 unsigned outcnt; /* bytes in output buffer */
221 int rsync = 0; /* make rsyncable chunks */
223 static int handled_sig[] =
225 /* SIGINT must be first, as 'foreground' depends on it. */
226 SIGINT
228 #ifdef SIGHUP
229 , SIGHUP
230 #endif
231 #if SIGPIPE
232 , SIGPIPE
233 #endif
234 #ifdef SIGTERM
235 , SIGTERM
236 #endif
237 #ifdef SIGXCPU
238 , SIGXCPU
239 #endif
240 #ifdef SIGXFSZ
241 , SIGXFSZ
242 #endif
245 /* For long options that have no equivalent short option, use a
246 non-character as a pseudo short option, starting with CHAR_MAX + 1. */
247 enum
249 PRESUME_INPUT_TTY_OPTION = CHAR_MAX + 1,
250 RSYNCABLE_OPTION,
251 SYNCHRONOUS_OPTION,
253 /* A value greater than all valid long options, used as a flag to
254 distinguish options derived from the GZIP environment variable. */
255 ENV_OPTION
258 static char const shortopts[] = "ab:cdfhH?klLmMnNqrS:tvVZ123456789";
260 static const struct option longopts[] =
262 /* { name has_arg *flag val } */
263 {"ascii", 0, 0, 'a'}, /* ascii text mode */
264 {"to-stdout", 0, 0, 'c'}, /* write output on standard output */
265 {"stdout", 0, 0, 'c'}, /* write output on standard output */
266 {"decompress", 0, 0, 'd'}, /* decompress */
267 {"uncompress", 0, 0, 'd'}, /* decompress */
268 /* {"encrypt", 0, 0, 'e'}, encrypt */
269 {"force", 0, 0, 'f'}, /* force overwrite of output file */
270 {"help", 0, 0, 'h'}, /* give help */
271 /* {"pkzip", 0, 0, 'k'}, force output in pkzip format */
272 {"keep", 0, 0, 'k'}, /* keep (don't delete) input files */
273 {"list", 0, 0, 'l'}, /* list .gz file contents */
274 {"license", 0, 0, 'L'}, /* display software license */
275 {"no-name", 0, 0, 'n'}, /* don't save or restore original name & time */
276 {"name", 0, 0, 'N'}, /* save or restore original name & time */
277 {"-presume-input-tty", no_argument, NULL, PRESUME_INPUT_TTY_OPTION},
278 {"quiet", 0, 0, 'q'}, /* quiet mode */
279 {"silent", 0, 0, 'q'}, /* quiet mode */
280 {"synchronous",0, 0, SYNCHRONOUS_OPTION},
281 {"recursive", 0, 0, 'r'}, /* recurse through directories */
282 {"suffix", 1, 0, 'S'}, /* use given suffix instead of .gz */
283 {"test", 0, 0, 't'}, /* test compressed file integrity */
284 {"verbose", 0, 0, 'v'}, /* verbose mode */
285 {"version", 0, 0, 'V'}, /* display version number */
286 {"fast", 0, 0, '1'}, /* compress faster */
287 {"best", 0, 0, '9'}, /* compress better */
288 {"lzw", 0, 0, 'Z'}, /* make output compatible with old compress */
289 {"bits", 1, 0, 'b'}, /* max number of bits per code (implies -Z) */
290 {"rsyncable", 0, 0, RSYNCABLE_OPTION}, /* make rsync-friendly archive */
291 { 0, 0, 0, 0 }
294 /* local functions */
296 _Noreturn static void try_help (void);
297 static void help (void);
298 static void license (void);
299 static void version (void);
300 static int input_eof (void);
301 static void treat_stdin (void);
302 static void treat_file (char *iname);
303 static int create_outfile (void);
304 static char *get_suffix (char *name);
305 static int open_input_file (char *iname, struct stat *sbuf);
306 static void discard_input_bytes (size_t nbytes, unsigned int flags);
307 static int make_ofname (void);
308 static void shorten_name (char *name);
309 static int get_method (int in);
310 static void do_list (int method);
311 static int check_ofname (void);
312 static void copy_stat (struct stat *ifstat);
313 static void install_signal_handlers (void);
314 static void remove_output_file (bool);
315 static void abort_gzip_signal (int);
316 _Noreturn static void do_exit (int exitcode);
317 static void finish_out (void);
318 int main (int argc, char **argv);
319 static int (*work) (int infile, int outfile) = zip; /* function to call */
321 #if ! NO_DIR
322 static void treat_dir (int fd, char *dir);
323 #endif
325 #define strequ(s1, s2) (strcmp((s1),(s2)) == 0)
327 static void
328 try_help ()
330 fprintf (stderr, "Try `%s --help' for more information.\n",
331 program_name);
332 do_exit (ERROR);
335 /* ======================================================================== */
336 static void
337 help ()
339 static char const* const help_msg[] = {
340 "Compress or uncompress FILEs (by default, compress FILES in-place).",
342 "Mandatory arguments to long options are mandatory for short options too.",
344 #if O_BINARY
345 " -a, --ascii ascii text; convert end-of-line using local conventions",
346 #endif
347 " -c, --stdout write on standard output, keep original files unchanged",
348 " -d, --decompress decompress",
349 /* -e, --encrypt encrypt */
350 " -f, --force force overwrite of output file and compress links",
351 " -h, --help give this help",
352 /* -k, --pkzip force output in pkzip format */
353 " -k, --keep keep (don't delete) input files",
354 " -l, --list list compressed file contents",
355 " -L, --license display software license",
356 #ifdef UNDOCUMENTED
357 " -m do not save or restore the original modification time",
358 " -M, --time save or restore the original modification time",
359 #endif
360 " -n, --no-name do not save or restore the original name and timestamp",
361 " -N, --name save or restore the original name and timestamp",
362 " -q, --quiet suppress all warnings",
363 #if ! NO_DIR
364 " -r, --recursive operate recursively on directories",
365 #endif
366 " --rsyncable make rsync-friendly archive",
367 " -S, --suffix=SUF use suffix SUF on compressed files",
368 " --synchronous synchronous output (safer if system crashes, but slower)",
369 " -t, --test test compressed file integrity",
370 " -v, --verbose verbose mode",
371 " -V, --version display version number",
372 " -1, --fast compress faster",
373 " -9, --best compress better",
375 "With no FILE, or when FILE is -, read standard input.",
377 "Report bugs to <bug-gzip@gnu.org>.",
379 char const *const *p = help_msg;
381 printf ("Usage: %s [OPTION]... [FILE]...\n", program_name);
382 while (*p) printf ("%s\n", *p++);
385 /* ======================================================================== */
386 static void
387 license ()
389 char const *const *p = license_msg;
391 printf ("%s %s\n", program_name, Version);
392 while (*p) printf ("%s\n", *p++);
395 /* ======================================================================== */
396 static void
397 version ()
399 license ();
400 printf ("\n");
401 printf ("Written by Jean-loup Gailly.\n");
404 static void
405 progerror (char const *string)
407 fprintf (stderr, "%s: %s: %s\n", program_name, string, strerror (errno));
408 exit_code = ERROR;
411 /* ======================================================================== */
412 int main (int argc, char **argv)
414 int file_count; /* number of files to process */
415 size_t proglen; /* length of program_name */
416 char **argv_copy;
417 int env_argc;
418 char **env_argv;
420 EXPAND(argc, argv); /* wild card expansion if necessary */
422 program_name = gzip_base_name (argv[0]);
423 proglen = strlen (program_name);
425 /* Suppress .exe for MSDOS and OS/2: */
426 if (4 < proglen && strequ (program_name + proglen - 4, ".exe"))
427 program_name[proglen - 4] = '\0';
429 /* Add options in GZIP environment variable if there is one */
430 argv_copy = argv;
431 env = add_envopt (&env_argc, &argv_copy, OPTIONS_VAR);
432 env_argv = env ? argv_copy : NULL;
434 #ifndef GNU_STANDARD
435 # define GNU_STANDARD 1
436 #endif
437 #if !GNU_STANDARD
438 /* For compatibility with old compress, use program name as an option.
439 * Unless you compile with -DGNU_STANDARD=0, this program will behave as
440 * gzip even if it is invoked under the name gunzip or zcat.
442 * Systems which do not support links can still use -d or -dc.
443 * Ignore an .exe extension for MSDOS and OS/2.
445 if (strncmp (program_name, "un", 2) == 0 /* ungzip, uncompress */
446 || strncmp (program_name, "gun", 3) == 0) /* gunzip */
447 decompress = 1;
448 else if (strequ (program_name + 1, "cat") /* zcat, pcat, gcat */
449 || strequ (program_name, "gzcat")) /* gzcat */
450 decompress = to_stdout = 1;
451 #endif
453 z_suffix = Z_SUFFIX;
454 z_len = strlen(z_suffix);
456 while (true) {
457 int optc;
458 int longind = -1;
460 if (env_argv)
462 if (env_argv[optind] && strequ (env_argv[optind], "--"))
463 optc = ENV_OPTION + '-';
464 else
466 optc = getopt_long (env_argc, env_argv, shortopts, longopts,
467 &longind);
468 if (0 <= optc)
469 optc += ENV_OPTION;
470 else
472 if (optind != env_argc)
474 fprintf (stderr,
475 ("%s: %s: non-option in "OPTIONS_VAR
476 " environment variable\n"),
477 program_name, env_argv[optind]);
478 try_help ();
481 /* Wait until here before warning, so that GZIP='-q'
482 doesn't warn. */
483 if (env_argc != 1 && !quiet)
484 fprintf (stderr,
485 ("%s: warning: "OPTIONS_VAR" environment variable"
486 " is deprecated; use an alias or script\n"),
487 program_name);
489 /* Start processing ARGC and ARGV instead. */
490 free (env_argv);
491 env_argv = NULL;
492 optind = 1;
493 longind = -1;
498 if (!env_argv)
499 optc = getopt_long (argc, argv, shortopts, longopts, &longind);
500 if (optc < 0)
501 break;
503 switch (optc) {
504 case 'a':
505 ascii = 1; break;
506 case 'b':
507 maxbits = atoi(optarg);
508 for (; *optarg; optarg++)
509 if (! ('0' <= *optarg && *optarg <= '9'))
511 fprintf (stderr, "%s: -b operand is not an integer\n",
512 program_name);
513 try_help ();
515 break;
516 case 'c':
517 to_stdout = 1; break;
518 case 'd':
519 decompress = 1; break;
520 case 'f':
521 force++; break;
522 case 'h': case 'H':
523 help (); finish_out (); break;
524 case 'k':
525 keep = 1; break;
526 case 'l':
527 list = decompress = test = to_stdout = 1; break;
528 case 'L':
529 license (); finish_out (); break;
530 case 'm': /* undocumented, may change later */
531 no_time = 1; break;
532 case 'M': /* undocumented, may change later */
533 no_time = 0; break;
534 case 'n':
535 case 'n' + ENV_OPTION:
536 no_name = no_time = 1; break;
537 case 'N':
538 case 'N' + ENV_OPTION:
539 no_name = no_time = 0; break;
540 case PRESUME_INPUT_TTY_OPTION:
541 presume_input_tty = true; break;
542 case 'q':
543 case 'q' + ENV_OPTION:
544 quiet = 1; verbose = 0; break;
545 case 'r':
546 #if NO_DIR
547 fprintf (stderr, "%s: -r not supported on this system\n",
548 program_name);
549 try_help ();
550 #else
551 recursive = 1;
552 #endif
553 break;
555 case RSYNCABLE_OPTION:
556 case RSYNCABLE_OPTION + ENV_OPTION:
557 rsync = 1;
558 break;
559 case 'S':
560 #ifdef NO_MULTIPLE_DOTS
561 if (*optarg == '.') optarg++;
562 #endif
563 for (z_len = 0; optarg[z_len]; z_len++)
564 if (optarg[z_len] == '/')
566 fprintf (stderr, "%s: suffix contains '/'\n", program_name);
567 do_exit (ERROR);
569 z_suffix = optarg;
570 break;
571 case SYNCHRONOUS_OPTION:
572 synchronous = true;
573 break;
574 case 't':
575 test = decompress = to_stdout = 1;
576 break;
577 case 'v':
578 case 'v' + ENV_OPTION:
579 verbose++; quiet = 0; break;
580 case 'V':
581 version (); finish_out (); break;
582 case 'Z':
583 fprintf(stderr, "%s: -Z not supported in this version\n",
584 program_name);
585 try_help ();
586 break;
587 case '1' + ENV_OPTION: case '2' + ENV_OPTION: case '3' + ENV_OPTION:
588 case '4' + ENV_OPTION: case '5' + ENV_OPTION: case '6' + ENV_OPTION:
589 case '7' + ENV_OPTION: case '8' + ENV_OPTION: case '9' + ENV_OPTION:
590 optc -= ENV_OPTION;
591 FALLTHROUGH;
592 case '1': case '2': case '3': case '4':
593 case '5': case '6': case '7': case '8': case '9':
594 level = optc - '0';
595 break;
597 default:
598 if (ENV_OPTION <= optc && optc != ENV_OPTION + '?')
600 /* Output a diagnostic, since getopt_long didn't. */
601 fprintf (stderr, "%s: ", program_name);
602 if (longind < 0)
603 fprintf (stderr, "-%c: ", optc - ENV_OPTION);
604 else
605 fprintf (stderr, "--%s: ", longopts[longind].name);
606 fprintf (stderr, ("option not valid in "OPTIONS_VAR
607 " environment variable\n"));
609 try_help ();
611 } /* loop on all arguments */
613 /* By default, save name and timestamp on compression but do not
614 * restore them on decompression.
616 if (no_time < 0) no_time = decompress;
617 if (no_name < 0) no_name = decompress;
619 file_count = argc - optind;
621 #if O_BINARY
622 #else
623 if (ascii && !quiet) {
624 fprintf(stderr, "%s: option --ascii ignored on this system\n",
625 program_name);
627 #endif
628 if (z_len == 0 || z_len > MAX_SUFFIX) {
629 fprintf(stderr, "%s: invalid suffix '%s'\n", program_name, z_suffix);
630 do_exit(ERROR);
633 /* Allocate all global buffers (for DYN_ALLOC option) */
634 ALLOC(uch, inbuf, INBUFSIZ +INBUF_EXTRA);
635 ALLOC(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
636 ALLOC(ush, d_buf, DIST_BUFSIZE);
637 ALLOC(uch, window, 2L*WSIZE);
638 #ifndef MAXSEG_64K
639 ALLOC(ush, tab_prefix, 1L<<BITS);
640 #else
641 ALLOC(ush, tab_prefix0, 1L<<(BITS-1));
642 ALLOC(ush, tab_prefix1, 1L<<(BITS-1));
643 #endif
645 /* And get to work */
646 if (file_count != 0) {
647 if (to_stdout && !test && (!decompress || !ascii)) {
648 SET_BINARY_MODE (STDOUT_FILENO);
650 while (optind < argc) {
651 treat_file(argv[optind++]);
653 } else { /* Standard input */
654 treat_stdin();
656 if (stdin_was_read && close (STDIN_FILENO) != 0)
658 strcpy (ifname, "stdin");
659 read_error ();
661 if (list)
663 /* Output any totals, and check for output errors. */
664 if (!quiet && 1 < file_count)
665 do_list (-1);
666 if (fflush (stdout) != 0)
667 write_error ();
669 if (to_stdout
670 && ((synchronous
671 && fdatasync (STDOUT_FILENO) != 0 && errno != EINVAL)
672 || close (STDOUT_FILENO) != 0)
673 && errno != EBADF)
674 write_error ();
675 do_exit(exit_code);
678 /* Return nonzero when at end of file on input. */
679 static int
680 input_eof ()
682 if (!decompress || last_member)
683 return 1;
685 if (inptr == insize)
687 if (insize != INBUFSIZ || fill_inbuf (1) == EOF)
688 return 1;
690 /* Unget the char that fill_inbuf got. */
691 inptr = 0;
694 return 0;
697 static void
698 get_input_size_and_time (void)
700 ifile_size = -1;
701 time_stamp.tv_nsec = -1;
703 /* Record the input file's size and timestamp only if it is a
704 regular file. Doing this for the timestamp helps to keep gzip's
705 output more reproducible when it is used as part of a
706 pipeline. */
708 if (S_ISREG (istat.st_mode))
710 ifile_size = istat.st_size;
711 if (!no_time || list)
712 time_stamp = get_stat_mtime (&istat);
716 /* ========================================================================
717 * Compress or decompress stdin
719 static void
720 treat_stdin ()
722 if (!force && !list
723 && (presume_input_tty
724 || isatty (decompress ? STDIN_FILENO : STDOUT_FILENO))) {
725 /* Do not send compressed data to the terminal or read it from
726 * the terminal. We get here when user invoked the program
727 * without parameters, so be helpful. According to the GNU standards:
729 * If there is one behavior you think is most useful when the output
730 * is to a terminal, and another that you think is most useful when
731 * the output is a file or a pipe, then it is usually best to make
732 * the default behavior the one that is useful with output to a
733 * terminal, and have an option for the other behavior.
735 * Here we use the --force option to get the other behavior.
737 if (! quiet)
738 fprintf (stderr,
739 ("%s: compressed data not %s a terminal."
740 " Use -f to force %scompression.\n"
741 "For help, type: %s -h\n"),
742 program_name,
743 decompress ? "read from" : "written to",
744 decompress ? "de" : "",
745 program_name);
746 do_exit(ERROR);
749 if (decompress || !ascii) {
750 SET_BINARY_MODE (STDIN_FILENO);
752 if (!test && (!decompress || !ascii)) {
753 SET_BINARY_MODE (STDOUT_FILENO);
755 strcpy(ifname, "stdin");
756 strcpy(ofname, "stdout");
758 /* Get the file's timestamp and size. */
759 if (fstat (STDIN_FILENO, &istat) != 0)
761 progerror ("standard input");
762 do_exit (ERROR);
765 get_input_size_and_time ();
767 clear_bufs(); /* clear input and output buffers */
768 to_stdout = 1;
769 part_nb = 0;
770 ifd = STDIN_FILENO;
771 stdin_was_read = true;
773 if (decompress) {
774 method = get_method(ifd);
775 if (method < 0) {
776 do_exit(exit_code); /* error message already emitted */
780 /* Actually do the compression/decompression. Loop over zipped members.
782 for (;;) {
783 if (work (STDIN_FILENO, STDOUT_FILENO) != OK)
784 return;
786 if (input_eof ())
787 break;
789 method = get_method(ifd);
790 if (method < 0) return; /* error message already emitted */
793 if (list)
795 do_list (method);
796 return;
799 if (verbose) {
800 if (test) {
801 fprintf(stderr, " OK\n");
803 } else if (!decompress) {
804 display_ratio(bytes_in-(bytes_out-header_bytes), bytes_in, stderr);
805 fprintf(stderr, "\n");
806 #ifdef DISPLAY_STDIN_RATIO
807 } else {
808 display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out,stderr);
809 fprintf(stderr, "\n");
810 #endif
815 static char const dot = '.';
817 /* True if the cached directory for calls to openat etc. is DIR, with
818 length DIRLEN. DIR need not be null-terminated. DIRLEN must be
819 less than MAX_PATH_LEN. */
820 static bool
821 atdir_eq (char const *dir, ptrdiff_t dirlen)
823 if (dirlen == 0)
824 dir = &dot, dirlen = 1;
825 return memcmp (dfname, dir, dirlen) == 0 && !dfname[dirlen];
828 /* Set the directory used for calls to openat etc. to be the directory
829 DIR, with length DIRLEN. DIR need not be null-terminated.
830 DIRLEN must be less than MAX_PATH_LEN. Return a file descriptor for
831 the directory, or -1 if one could not be obtained. */
832 static int
833 atdir_set (char const *dir, ptrdiff_t dirlen)
835 /* Don't bother opening directories on older systems that
836 lack openat and unlinkat. It's not worth the porting hassle. */
837 #if HAVE_OPENAT && HAVE_UNLINKAT
838 enum { try_opening_directories = true };
839 #else
840 enum { try_opening_directories = false };
841 #endif
843 if (try_opening_directories && ! atdir_eq (dir, dirlen))
845 if (0 <= dfd)
846 close (dfd);
847 if (dirlen == 0)
848 dir = &dot, dirlen = 1;
849 memcpy (dfname, dir, dirlen);
850 dfname[dirlen] = '\0';
851 dfd = open (dfname, O_SEARCH | O_DIRECTORY);
854 return dfd;
857 /* ========================================================================
858 * Compress or decompress the given file
860 static void
861 treat_file (char *iname)
863 /* Accept "-" as synonym for stdin */
864 if (strequ(iname, "-")) {
865 int cflag = to_stdout;
866 treat_stdin();
867 to_stdout = cflag;
868 return;
871 /* Check if the input file is present, set ifname and istat: */
872 ifd = open_input_file (iname, &istat);
873 if (ifd < 0)
874 return;
876 /* If the input name is that of a directory, recurse or ignore: */
877 if (S_ISDIR(istat.st_mode)) {
878 #if ! NO_DIR
879 if (recursive) {
880 treat_dir (ifd, iname);
881 /* Warning: ifname is now garbage */
882 return;
884 #endif
885 close (ifd);
886 WARN ((stderr, "%s: %s is a directory -- ignored\n",
887 program_name, ifname));
888 return;
891 if (! to_stdout)
893 if (! S_ISREG (istat.st_mode))
895 WARN ((stderr,
896 "%s: %s is not a directory or a regular file - ignored\n",
897 program_name, ifname));
898 close (ifd);
899 return;
901 if (istat.st_mode & S_ISUID)
903 WARN ((stderr, "%s: %s is set-user-ID on execution - ignored\n",
904 program_name, ifname));
905 close (ifd);
906 return;
908 if (istat.st_mode & S_ISGID)
910 WARN ((stderr, "%s: %s is set-group-ID on execution - ignored\n",
911 program_name, ifname));
912 close (ifd);
913 return;
916 if (! force)
918 if (istat.st_mode & S_ISVTX)
920 WARN ((stderr,
921 "%s: %s has the sticky bit set - file ignored\n",
922 program_name, ifname));
923 close (ifd);
924 return;
926 if (2 <= istat.st_nlink)
928 WARN ((stderr, "%s: %s has %lu other link%s -- file ignored\n",
929 program_name, ifname,
930 (unsigned long int) istat.st_nlink - 1,
931 istat.st_nlink == 2 ? "" : "s"));
932 close (ifd);
933 return;
938 get_input_size_and_time ();
940 /* Generate output file name. For -r and (-t or -l), skip files
941 * without a valid gzip suffix (check done in make_ofname).
943 if (to_stdout && !test) {
944 strcpy(ofname, "stdout");
946 } else if (make_ofname() != OK) {
947 close (ifd);
948 return;
951 clear_bufs(); /* clear input and output buffers */
952 part_nb = 0;
954 if (decompress) {
955 method = get_method(ifd); /* updates ofname if original given */
956 if (method < 0) {
957 close(ifd);
958 return; /* error message already emitted */
962 /* If compressing to a file, check if ofname is not ambiguous
963 * because the operating system truncates names. Otherwise, generate
964 * a new ofname and save the original name in the compressed file.
966 if (to_stdout) {
967 ofd = STDOUT_FILENO;
968 /* Keep remove_ofname_fd negative. */
969 } else {
970 if (create_outfile() != OK) return;
972 if (!decompress && save_orig_name && !verbose && !quiet) {
973 fprintf(stderr, "%s: %s compressed to %s\n",
974 program_name, ifname, ofname);
977 /* Keep the name even if not truncated except with --no-name: */
978 if (!save_orig_name) save_orig_name = !no_name;
980 if (verbose && !list) {
981 fprintf(stderr, "%s:\t", ifname);
984 /* Actually do the compression/decompression. Loop over zipped members.
986 for (;;) {
987 if ((*work)(ifd, ofd) != OK) {
988 method = -1; /* force cleanup */
989 break;
992 if (input_eof ())
993 break;
995 method = get_method(ifd);
996 if (method < 0) break; /* error message already emitted */
999 if (close (ifd) != 0)
1000 read_error ();
1002 if (list)
1004 do_list (method);
1005 return;
1008 if (!to_stdout)
1010 copy_stat (&istat);
1012 if ((synchronous
1013 && ((0 <= dfd && fdatasync (dfd) != 0 && errno != EINVAL)
1014 || (fsync (ofd) != 0 && errno != EINVAL)))
1015 || close (ofd) != 0)
1016 write_error ();
1018 if (!keep)
1020 sigset_t oldset;
1021 int unlink_errno;
1022 char *ifbase = last_component (ifname);
1023 int ufd = atdir_eq (ifname, ifbase - ifname) ? dfd : -1;
1024 int res;
1026 sigprocmask (SIG_BLOCK, &caught_signals, &oldset);
1027 remove_ofname_fd = -1;
1028 res = ufd < 0 ? xunlink (ifname) : unlinkat (ufd, ifbase, 0);
1029 unlink_errno = res == 0 ? 0 : errno;
1030 sigprocmask (SIG_SETMASK, &oldset, NULL);
1032 if (unlink_errno)
1033 WARN ((stderr, "%s: %s: %s\n", program_name, ifname,
1034 strerror (unlink_errno)));
1038 if (method == -1) {
1039 if (!to_stdout)
1040 remove_output_file (false);
1041 return;
1044 /* Display statistics */
1045 if(verbose) {
1046 if (test) {
1047 fprintf(stderr, " OK");
1048 } else if (decompress) {
1049 display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out,stderr);
1050 } else {
1051 display_ratio(bytes_in-(bytes_out-header_bytes), bytes_in, stderr);
1053 if (!test)
1054 fprintf(stderr, " -- %s %s", keep ? "created" : "replaced with",
1055 ofname);
1056 fprintf(stderr, "\n");
1060 static void
1061 volatile_strcpy (char volatile *dst, char const volatile *src)
1063 while ((*dst++ = *src++))
1064 continue;
1067 /* ========================================================================
1068 * Create the output file. Return OK or ERROR.
1069 * Try several times if necessary to avoid truncating the z_suffix. For
1070 * example, do not create a compressed file of name "1234567890123."
1071 * Sets save_orig_name to true if the file name has been truncated.
1072 * IN assertions: the input file has already been open (ifd is set) and
1073 * ofname has already been updated if there was an original name.
1074 * OUT assertions: ifd and ofd are closed in case of error.
1076 static int
1077 create_outfile ()
1079 static bool signal_handlers_installed;
1080 int name_shortened = 0;
1081 int flags = (O_WRONLY | O_CREAT | O_EXCL
1082 | (ascii && decompress ? 0 : O_BINARY));
1083 char const *base = ofname;
1084 int atfd = AT_FDCWD;
1086 if (!keep)
1088 char const *b = last_component (ofname);
1089 int f = atdir_set (ofname, b - ofname);
1090 if (0 <= f)
1092 base = b;
1093 atfd = f;
1097 if (!signal_handlers_installed)
1099 signal_handlers_installed = true;
1100 install_signal_handlers ();
1103 for (;;)
1105 int open_errno;
1106 sigset_t oldset;
1108 volatile_strcpy (remove_ofname, ofname);
1110 sigprocmask (SIG_BLOCK, &caught_signals, &oldset);
1111 remove_ofname_fd = ofd = openat (atfd, base, flags, S_IRUSR | S_IWUSR);
1112 open_errno = errno;
1113 sigprocmask (SIG_SETMASK, &oldset, NULL);
1115 if (0 <= ofd)
1116 break;
1118 switch (open_errno)
1120 #ifdef ENAMETOOLONG
1121 case ENAMETOOLONG:
1122 shorten_name (ofname);
1123 name_shortened = 1;
1124 break;
1125 #endif
1127 case EEXIST:
1128 if (check_ofname () != OK)
1130 close (ifd);
1131 return ERROR;
1133 break;
1135 default:
1136 write_error ();
1137 close (ifd);
1138 return ERROR;
1142 if (name_shortened && decompress)
1144 /* name might be too long if an original name was saved */
1145 WARN ((stderr, "%s: %s: warning, name truncated\n",
1146 program_name, ofname));
1149 return OK;
1152 /* ========================================================================
1153 * Return a pointer to the 'z' suffix of a file name, or NULL. For all
1154 * systems, ".gz", ".z", ".Z", ".taz", ".tgz", "-gz", "-z" and "_z" are
1155 * accepted suffixes, in addition to the value of the --suffix option.
1156 * ".tgz" is a useful convention for tar.z files on systems limited
1157 * to 3 characters extensions. On such systems, ".?z" and ".??z" are
1158 * also accepted suffixes. For Unix, we do not want to accept any
1159 * .??z suffix as indicating a compressed file; some people use .xyz
1160 * to denote volume data.
1162 static char *
1163 get_suffix (char *name)
1165 int nlen, slen;
1166 char suffix[MAX_SUFFIX+3]; /* last chars of name, forced to lower case */
1167 static char const *known_suffixes[] =
1168 {NULL, ".gz", ".z", ".taz", ".tgz", "-gz", "-z", "_z",
1169 #ifdef MAX_EXT_CHARS
1170 "z",
1171 #endif
1172 NULL, NULL};
1173 char const **suf;
1174 bool suffix_of_builtin = false;
1176 /* Normally put Z_SUFFIX at the start of KNOWN_SUFFIXES, but if it
1177 is a suffix of one of them, put it at the end. */
1178 for (suf = known_suffixes + 1; *suf; suf++)
1180 size_t suflen = strlen (*suf);
1181 if (z_len < suflen && strequ (z_suffix, *suf + suflen - z_len))
1183 suffix_of_builtin = true;
1184 break;
1188 char *z_lower = xstrdup(z_suffix);
1189 strlwr(z_lower);
1190 known_suffixes[suffix_of_builtin
1191 ? sizeof known_suffixes / sizeof *known_suffixes - 2
1192 : 0] = z_lower;
1193 suf = known_suffixes + suffix_of_builtin;
1195 nlen = strlen(name);
1196 if (nlen <= MAX_SUFFIX+2) {
1197 strcpy(suffix, name);
1198 } else {
1199 strcpy(suffix, name+nlen-MAX_SUFFIX-2);
1201 strlwr(suffix);
1202 slen = strlen(suffix);
1203 char *match = NULL;
1204 do {
1205 int s = strlen(*suf);
1206 if (slen > s && ! ISSLASH (suffix[slen - s - 1])
1207 && strequ(suffix + slen - s, *suf)) {
1208 match = name+nlen-s;
1209 break;
1211 } while (*++suf != NULL);
1212 free(z_lower);
1214 return match;
1218 /* Open file NAME with the given flags and store its status
1219 into *ST. Return a file descriptor to the newly opened file, or -1
1220 (setting errno) on failure. */
1221 static int
1222 open_and_stat (char *name, int flags, struct stat *st)
1224 int fd;
1225 int atfd = AT_FDCWD;
1226 char const *base = name;
1228 /* Refuse to follow symbolic links unless -c or -f. */
1229 if (!to_stdout && !force)
1231 if (HAVE_WORKING_O_NOFOLLOW)
1232 flags |= O_NOFOLLOW;
1233 else
1235 #ifdef S_ISLNK
1236 if (lstat (name, st) != 0)
1237 return -1;
1238 else if (S_ISLNK (st->st_mode))
1240 errno = ELOOP;
1241 return -1;
1243 #endif
1247 if (!keep)
1249 char const *b = last_component (name);
1250 int f = atdir_set (name, b - name);
1251 if (0 <= f)
1253 base = b;
1254 atfd = f;
1258 fd = openat (atfd, base, flags);
1259 if (0 <= fd && fstat (fd, st) != 0)
1261 int e = errno;
1262 close (fd);
1263 errno = e;
1264 return -1;
1266 return fd;
1270 /* ========================================================================
1271 * Set ifname to the input file name (with a suffix appended if necessary)
1272 * and istat to its stats. For decompression, if no file exists with the
1273 * original name, try adding successively z_suffix, .gz, .z, -z and .Z.
1274 * For MSDOS, we try only z_suffix and z.
1275 * Return an open file descriptor or -1.
1277 static int
1278 open_input_file (char *iname, struct stat *sbuf)
1280 int ilen; /* strlen(ifname) */
1281 int z_suffix_errno = 0;
1282 static char const *suffixes[] = {NULL, ".gz", ".z", "-z", ".Z", NULL};
1283 char const **suf = suffixes;
1284 char const *s;
1285 #ifdef NO_MULTIPLE_DOTS
1286 char *dot; /* pointer to ifname extension, or NULL */
1287 #endif
1288 int fd;
1289 int open_flags = (O_RDONLY | O_NONBLOCK | O_NOCTTY
1290 | (ascii && !decompress ? 0 : O_BINARY));
1292 *suf = z_suffix;
1294 if (sizeof ifname - 1 <= strlen (iname))
1295 goto name_too_long;
1297 strcpy(ifname, iname);
1299 /* If input file exists, return OK. */
1300 fd = open_and_stat (ifname, open_flags, sbuf);
1301 if (0 <= fd)
1302 return fd;
1304 if (!decompress || errno != ENOENT) {
1305 progerror(ifname);
1306 return -1;
1308 /* File.ext doesn't exist. Try adding a suffix. */
1309 s = get_suffix(ifname);
1310 if (s != NULL) {
1311 progerror(ifname); /* ifname already has z suffix and does not exist */
1312 return -1;
1314 #ifdef NO_MULTIPLE_DOTS
1315 dot = strrchr(ifname, '.');
1316 if (dot == NULL) {
1317 strcat(ifname, ".");
1318 dot = strrchr(ifname, '.');
1320 #endif
1321 ilen = strlen(ifname);
1322 if (strequ(z_suffix, ".gz")) suf++;
1324 /* Search for all suffixes */
1325 do {
1326 char const *s0 = s = *suf;
1327 strcpy (ifname, iname);
1328 #ifdef NO_MULTIPLE_DOTS
1329 if (*s == '.') s++;
1330 if (*dot == '\0') strcpy (dot, ".");
1331 #endif
1332 #ifdef MAX_EXT_CHARS
1333 if (MAX_EXT_CHARS < strlen (s) + strlen (dot + 1))
1334 dot[MAX_EXT_CHARS + 1 - strlen (s)] = '\0';
1335 #endif
1336 if (sizeof ifname <= ilen + strlen (s))
1337 goto name_too_long;
1338 strcat(ifname, s);
1339 fd = open_and_stat (ifname, open_flags, sbuf);
1340 if (0 <= fd)
1341 return fd;
1342 if (errno != ENOENT)
1344 progerror (ifname);
1345 return -1;
1347 if (strequ (s0, z_suffix))
1348 z_suffix_errno = errno;
1349 } while (*++suf != NULL);
1351 /* No suffix found, complain using z_suffix: */
1352 strcpy(ifname, iname);
1353 #ifdef NO_MULTIPLE_DOTS
1354 if (*dot == '\0') strcpy(dot, ".");
1355 #endif
1356 #ifdef MAX_EXT_CHARS
1357 if (MAX_EXT_CHARS < z_len + strlen (dot + 1))
1358 dot[MAX_EXT_CHARS + 1 - z_len] = '\0';
1359 #endif
1360 strcat(ifname, z_suffix);
1361 errno = z_suffix_errno;
1362 progerror(ifname);
1363 return -1;
1365 name_too_long:
1366 fprintf (stderr, "%s: %s: file name too long\n", program_name, iname);
1367 exit_code = ERROR;
1368 return -1;
1371 /* ========================================================================
1372 * Generate ofname given ifname. Return OK, or WARNING if file must be skipped.
1373 * Sets save_orig_name to true if the file name has been truncated.
1375 static int
1376 make_ofname ()
1378 char *suff; /* ofname z suffix */
1380 strcpy(ofname, ifname);
1381 /* strip a version number if any and get the gzip suffix if present: */
1382 suff = get_suffix(ofname);
1384 if (decompress) {
1385 if (suff == NULL) {
1386 /* With -t or -l, try all files (even without .gz suffix)
1387 * except with -r (behave as with just -dr).
1389 if (!recursive && test)
1390 return OK;
1392 /* Avoid annoying messages with -r */
1393 if (verbose || (!recursive && !quiet)) {
1394 WARN((stderr,"%s: %s: unknown suffix -- ignored\n",
1395 program_name, ifname));
1397 return WARNING;
1399 /* Make a special case for .tgz and .taz: */
1400 strlwr(suff);
1401 if (strequ(suff, ".tgz") || strequ(suff, ".taz")) {
1402 strcpy(suff, ".tar");
1403 } else {
1404 *suff = '\0'; /* strip the z suffix */
1406 /* ofname might be changed later if infile contains an original name */
1408 } else if (suff && ! force) {
1409 /* Avoid annoying messages with -r (see treat_dir()) */
1410 if (verbose || (!recursive && !quiet)) {
1411 /* Don't use WARN, as it affects exit status. */
1412 fprintf (stderr, "%s: %s already has %s suffix -- unchanged\n",
1413 program_name, ifname, suff);
1415 return WARNING;
1416 } else {
1417 save_orig_name = 0;
1419 #ifdef NO_MULTIPLE_DOTS
1420 suff = strrchr(ofname, '.');
1421 if (suff == NULL) {
1422 if (sizeof ofname <= strlen (ofname) + 1)
1423 goto name_too_long;
1424 strcat(ofname, ".");
1425 # ifdef MAX_EXT_CHARS
1426 if (strequ(z_suffix, "z")) {
1427 if (sizeof ofname <= strlen (ofname) + 2)
1428 goto name_too_long;
1429 strcat(ofname, "gz"); /* enough room */
1430 return OK;
1432 /* On the Atari and some versions of MSDOS,
1433 * ENAMETOOLONG does not work correctly. So we
1434 * must truncate here.
1436 } else if (strlen(suff)-1 + z_len > MAX_SUFFIX) {
1437 suff[MAX_SUFFIX+1-z_len] = '\0';
1438 save_orig_name = 1;
1439 # endif
1441 #endif /* NO_MULTIPLE_DOTS */
1442 if (sizeof ofname <= strlen (ofname) + z_len)
1443 goto name_too_long;
1444 strcat(ofname, z_suffix);
1446 } /* decompress ? */
1447 return OK;
1449 name_too_long:
1450 WARN ((stderr, "%s: %s: file name too long\n", program_name, ifname));
1451 return WARNING;
1454 /* Discard NBYTES input bytes from the input, or up through the next
1455 zero byte if NBYTES == (size_t) -1. If FLAGS say that the header
1456 CRC should be computed, update the CRC accordingly. */
1457 static void
1458 discard_input_bytes (size_t nbytes, unsigned int flags)
1460 while (nbytes != 0)
1462 uch c = get_byte ();
1463 if (flags & HEADER_CRC)
1464 updcrc (&c, 1);
1465 if (nbytes != (size_t) -1)
1466 nbytes--;
1467 else if (! c)
1468 break;
1472 /* ========================================================================
1473 * Check the magic number of the input file and update ofname if an
1474 * original name was given and to_stdout is not set.
1475 * Return the compression method, -1 for error, -2 for warning.
1476 * Set inptr to the offset of the next byte to be processed.
1477 * Updates time_stamp if there is one and neither -m nor -n is used.
1478 * This function may be called repeatedly for an input file consisting
1479 * of several contiguous gzip'ed members.
1480 * 'in' is the input file descriptor.
1481 * IN assertions: there is at least one remaining compressed member.
1482 * If the member is a zip file, it must be the only one.
1484 static int
1485 get_method (int in)
1487 uch flags; /* compression flags */
1488 uch magic[10]; /* magic header */
1489 int imagic0; /* first magic byte or EOF */
1490 int imagic1; /* like magic[1], but can represent EOF */
1491 ulg stamp; /* timestamp */
1493 /* If --force and --stdout, zcat == cat, so do not complain about
1494 * premature end of file: use try_byte instead of get_byte.
1496 if (force && to_stdout) {
1497 imagic0 = try_byte();
1498 magic[0] = imagic0;
1499 imagic1 = try_byte ();
1500 magic[1] = imagic1;
1501 /* If try_byte returned EOF, magic[1] == (char) EOF. */
1502 } else {
1503 magic[0] = get_byte ();
1504 imagic0 = 0;
1505 if (magic[0]) {
1506 magic[1] = get_byte ();
1507 imagic1 = 0; /* avoid lint warning */
1508 } else {
1509 imagic1 = try_byte ();
1510 magic[1] = imagic1;
1513 method = -1; /* unknown yet */
1514 part_nb++; /* number of parts in gzip file */
1515 header_bytes = 0;
1516 last_member = 0;
1517 /* assume multiple members in gzip file except for record oriented I/O */
1519 if (memcmp(magic, GZIP_MAGIC, 2) == 0
1520 || memcmp(magic, OLD_GZIP_MAGIC, 2) == 0) {
1522 method = (int)get_byte();
1523 if (method != DEFLATED) {
1524 fprintf(stderr,
1525 "%s: %s: unknown method %d -- not supported\n",
1526 program_name, ifname, method);
1527 exit_code = ERROR;
1528 return -1;
1530 work = unzip;
1531 flags = (uch)get_byte();
1533 if ((flags & ENCRYPTED) != 0) {
1534 fprintf(stderr,
1535 "%s: %s is encrypted -- not supported\n",
1536 program_name, ifname);
1537 exit_code = ERROR;
1538 return -1;
1540 if ((flags & RESERVED) != 0) {
1541 fprintf(stderr,
1542 "%s: %s has flags 0x%x -- not supported\n",
1543 program_name, ifname, flags);
1544 exit_code = ERROR;
1545 if (force <= 1) return -1;
1547 stamp = (ulg)get_byte();
1548 stamp |= ((ulg)get_byte()) << 8;
1549 stamp |= ((ulg)get_byte()) << 16;
1550 stamp |= ((ulg)get_byte()) << 24;
1551 if (stamp != 0 && !no_time)
1553 if (stamp <= TYPE_MAXIMUM (time_t))
1555 time_stamp.tv_sec = stamp;
1556 time_stamp.tv_nsec = 0;
1558 else
1560 WARN ((stderr,
1561 "%s: %s: MTIME %lu out of range for this platform\n",
1562 program_name, ifname, stamp));
1563 time_stamp.tv_sec = TYPE_MAXIMUM (time_t);
1564 time_stamp.tv_nsec = TIMESPEC_RESOLUTION - 1;
1568 magic[8] = get_byte (); /* Ignore extra flags. */
1569 magic[9] = get_byte (); /* Ignore OS type. */
1571 if (flags & HEADER_CRC)
1573 magic[2] = DEFLATED;
1574 magic[3] = flags;
1575 magic[4] = stamp & 0xff;
1576 magic[5] = (stamp >> 8) & 0xff;
1577 magic[6] = (stamp >> 16) & 0xff;
1578 magic[7] = stamp >> 24;
1579 updcrc (NULL, 0);
1580 updcrc (magic, 10);
1583 if ((flags & EXTRA_FIELD) != 0) {
1584 uch lenbuf[2];
1585 unsigned int len = lenbuf[0] = get_byte ();
1586 len |= (lenbuf[1] = get_byte ()) << 8;
1587 if (verbose) {
1588 fprintf(stderr,"%s: %s: extra field of %u bytes ignored\n",
1589 program_name, ifname, len);
1591 if (flags & HEADER_CRC)
1592 updcrc (lenbuf, 2);
1593 discard_input_bytes (len, flags);
1596 /* Get original file name if it was truncated */
1597 if ((flags & ORIG_NAME) != 0) {
1598 if (no_name || (to_stdout && !list) || part_nb > 1) {
1599 /* Discard the old name */
1600 discard_input_bytes (-1, flags);
1601 } else {
1602 /* Copy the base name. Keep a directory prefix intact. */
1603 char *p = gzip_base_name (ofname);
1604 char *base = p;
1605 for (;;) {
1606 *p = (char) get_byte ();
1607 if (*p++ == '\0') break;
1608 if (p >= ofname+sizeof(ofname)) {
1609 gzip_error ("corrupted input -- file name too large");
1612 if (flags & HEADER_CRC)
1613 updcrc ((uch *) base, p - base);
1614 p = gzip_base_name (base);
1615 memmove (base, p, strlen (p) + 1);
1616 /* If necessary, adapt the name to local OS conventions: */
1617 if (!list) {
1618 MAKE_LEGAL_NAME(base);
1619 if (base) list=0; /* avoid warning about unused variable */
1621 } /* no_name || to_stdout */
1622 } /* ORIG_NAME */
1624 /* Discard file comment if any */
1625 if ((flags & COMMENT) != 0) {
1626 discard_input_bytes (-1, flags);
1629 if (flags & HEADER_CRC)
1631 unsigned int crc16 = updcrc (magic, 0) & 0xffff;
1632 unsigned int header16 = get_byte ();
1633 header16 |= ((unsigned int) get_byte ()) << 8;
1634 if (header16 != crc16)
1636 fprintf (stderr,
1637 "%s: %s: header checksum 0x%04x != computed checksum 0x%04x\n",
1638 program_name, ifname, header16, crc16);
1639 exit_code = ERROR;
1640 if (force <= 1)
1641 return -1;
1645 if (part_nb == 1) {
1646 header_bytes = inptr + 2*4; /* include crc and size */
1649 } else if (memcmp(magic, PKZIP_MAGIC, 2) == 0 && inptr == 2
1650 && memcmp((char*)inbuf, PKZIP_MAGIC, 4) == 0) {
1651 /* To simplify the code, we support a zip file when alone only.
1652 * We are thus guaranteed that the entire local header fits in inbuf.
1654 inptr = 0;
1655 work = unzip;
1656 if (check_zipfile(in) != OK) return -1;
1657 /* check_zipfile may get ofname from the local header */
1658 last_member = 1;
1660 } else if (memcmp(magic, PACK_MAGIC, 2) == 0) {
1661 work = unpack;
1662 method = PACKED;
1664 } else if (memcmp(magic, LZW_MAGIC, 2) == 0) {
1665 work = unlzw;
1666 method = COMPRESSED;
1667 last_member = 1;
1669 } else if (memcmp(magic, LZH_MAGIC, 2) == 0) {
1670 work = unlzh;
1671 method = LZHED;
1672 last_member = 1;
1674 } else if (force && to_stdout && !list) { /* pass input unchanged */
1675 method = STORED;
1676 work = copy;
1677 if (imagic1 != EOF)
1678 inptr--;
1679 last_member = 1;
1680 if (imagic0 != EOF) {
1681 write_buf (STDOUT_FILENO, magic, 1);
1684 if (method >= 0) return method;
1686 if (part_nb == 1) {
1687 fprintf (stderr, "\n%s: %s: not in gzip format\n",
1688 program_name, ifname);
1689 exit_code = ERROR;
1690 return -1;
1691 } else {
1692 if (magic[0] == 0)
1694 int inbyte;
1695 for (inbyte = imagic1; inbyte == 0; inbyte = try_byte ())
1696 continue;
1697 if (inbyte == EOF)
1699 if (verbose)
1700 WARN ((stderr, "\n%s: %s: decompression OK, trailing zero bytes ignored\n",
1701 program_name, ifname));
1702 return -3;
1706 WARN((stderr, "\n%s: %s: decompression OK, trailing garbage ignored\n",
1707 program_name, ifname));
1708 return -2;
1712 /* ========================================================================
1713 * Display the characteristics of the compressed file.
1714 * If the given method is < 0, display the accumulated totals.
1715 * IN assertions: time_stamp, header_bytes and ifile_size are initialized.
1717 static void
1718 do_list (int method)
1720 ulg crc; /* original crc */
1721 static int first_time = 1;
1722 static char const *const methods[MAX_METHODS] = {
1723 "store", /* 0 */
1724 "compr", /* 1 */
1725 "pack ", /* 2 */
1726 "lzh ", /* 3 */
1727 "", "", "", "", /* 4 to 7 reserved */
1728 "defla"}; /* 8 */
1729 int positive_off_t_width = INT_STRLEN_BOUND (off_t) - 1;
1731 if (first_time && method >= 0) {
1732 first_time = 0;
1733 if (verbose) {
1734 printf("method crc date time ");
1736 if (!quiet) {
1737 printf("%*.*s %*.*s ratio uncompressed_name\n",
1738 positive_off_t_width, positive_off_t_width, "compressed",
1739 positive_off_t_width, positive_off_t_width, "uncompressed");
1741 } else if (method < 0) {
1742 if (total_in <= 0 || total_out <= 0) return;
1743 if (verbose) {
1744 printf(" ");
1746 if (verbose || !quiet)
1747 printf ("%*jd %*jd ", positive_off_t_width, (intmax_t) total_in,
1748 positive_off_t_width, (intmax_t) total_out);
1749 display_ratio(total_out-(total_in-header_bytes), total_out, stdout);
1750 /* header_bytes is not meaningful but used to ensure the same
1751 * ratio if there is a single file.
1753 printf(" (totals)\n");
1754 return;
1756 crc = (ulg)~0; /* unknown */
1758 if (method == DEFLATED && !last_member) {
1759 crc = unzip_crc;
1762 if (verbose)
1764 static char const month_abbr[][4]
1765 = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1766 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
1767 struct tm *tm = localtime (&time_stamp.tv_sec);
1768 printf ("%5s %08lx ", methods[method], crc);
1769 if (tm)
1770 printf ("%s%3d %02d:%02d ", month_abbr[tm->tm_mon],
1771 tm->tm_mday, tm->tm_hour, tm->tm_min);
1772 else
1773 printf ("??? ?? ??:?? ");
1775 printf ("%*jd %*jd ", positive_off_t_width, (intmax_t) bytes_in,
1776 positive_off_t_width, (intmax_t) bytes_out);
1777 if (bytes_in == -1L) {
1778 total_in = -1L;
1779 bytes_in = bytes_out = header_bytes = 0;
1780 } else if (total_in >= 0) {
1781 total_in += bytes_in;
1783 if (bytes_out == -1L) {
1784 total_out = -1L;
1785 bytes_in = bytes_out = header_bytes = 0;
1786 } else if (total_out >= 0) {
1787 total_out += bytes_out;
1789 display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out, stdout);
1790 printf(" %s\n", ofname);
1793 /* ========================================================================
1794 * Shorten the given name by one character, or replace a .tar extension
1795 * with .tgz. Truncate the last part of the name which is longer than
1796 * MIN_PART characters: 1234.678.012.gz -> 123.678.012.gz. If the name
1797 * has only parts shorter than MIN_PART truncate the longest part.
1798 * For decompression, just remove the last character of the name.
1800 * IN assertion: for compression, the suffix of the given name is z_suffix.
1802 static void
1803 shorten_name (char *name)
1805 int len; /* length of name without z_suffix */
1806 char *trunc = NULL; /* character to be truncated */
1807 int plen; /* current part length */
1808 int min_part = MIN_PART; /* current minimum part length */
1809 char *p;
1811 len = strlen(name);
1812 if (decompress) {
1813 if (len <= 1)
1814 gzip_error ("name too short");
1815 name[len-1] = '\0';
1816 return;
1818 p = get_suffix(name);
1819 if (! p)
1820 gzip_error ("can't recover suffix\n");
1821 *p = '\0';
1822 save_orig_name = 1;
1824 /* compress 1234567890.tar to 1234567890.tgz */
1825 if (len > 4 && strequ(p-4, ".tar")) {
1826 strcpy(p-4, ".tgz");
1827 return;
1829 /* Try keeping short extensions intact:
1830 * 1234.678.012.gz -> 123.678.012.gz
1832 do {
1833 p = last_component (name);
1834 while (*p) {
1835 plen = strcspn(p, PART_SEP);
1836 p += plen;
1837 if (plen > min_part) trunc = p-1;
1838 if (*p) p++;
1840 } while (trunc == NULL && --min_part != 0);
1842 if (trunc != NULL) {
1843 do {
1844 trunc[0] = trunc[1];
1845 } while (*trunc++);
1846 trunc--;
1847 } else {
1848 trunc = strrchr(name, PART_SEP[0]);
1849 if (!trunc)
1850 gzip_error ("internal error in shorten_name");
1851 if (trunc[1] == '\0') trunc--; /* force truncation */
1853 strcpy(trunc, z_suffix);
1856 /* ========================================================================
1857 * The compressed file already exists, so ask for confirmation.
1858 * Return ERROR if the file must be skipped.
1860 static int
1861 check_ofname ()
1863 /* Ask permission to overwrite the existing file */
1864 if (!force) {
1865 int ok = 0;
1866 fprintf (stderr, "%s: %s already exists;", program_name, ofname);
1867 if (foreground && (presume_input_tty || isatty (STDIN_FILENO))) {
1868 fprintf(stderr, " do you wish to overwrite (y or n)? ");
1869 fflush(stderr);
1870 ok = yesno();
1872 if (!ok) {
1873 fprintf(stderr, "\tnot overwritten\n");
1874 if (exit_code == OK) exit_code = WARNING;
1875 return ERROR;
1878 if (xunlink (ofname)) {
1879 progerror(ofname);
1880 return ERROR;
1882 return OK;
1885 /* Change the owner and group of a file. FD is a file descriptor for
1886 the file and NAME its name. Change it to user UID and to group GID.
1887 If UID or GID is -1, though, do not change the corresponding user
1888 or group. */
1889 #if ! (HAVE_FCHOWN || HAVE_CHOWN)
1890 /* The types uid_t and gid_t do not exist on mingw, so don't assume them. */
1891 # define do_chown(fd, name, uid, gid) ((void) 0)
1892 #else
1893 static void
1894 do_chown (int fd, char const *name, uid_t uid, gid_t gid)
1896 # if HAVE_FCHOWN
1897 ignore_value (fchown (fd, uid, gid));
1898 # else
1899 ignore_value (chown (name, uid, gid));
1900 # endif
1902 #endif
1904 /* ========================================================================
1905 * Copy modes, times, ownership from input file to output file.
1906 * IN assertion: to_stdout is false.
1908 static void
1909 copy_stat (struct stat *ifstat)
1911 mode_t mode = ifstat->st_mode & S_IRWXUGO;
1912 int r;
1914 #ifndef NO_UTIME
1915 bool restoring;
1916 struct timespec timespec[2];
1917 timespec[0] = get_stat_atime (ifstat);
1918 timespec[1] = get_stat_mtime (ifstat);
1919 restoring = (decompress && 0 <= time_stamp.tv_nsec
1920 && ! (timespec[1].tv_sec == time_stamp.tv_sec
1921 && timespec[1].tv_nsec == time_stamp.tv_nsec));
1922 if (restoring)
1923 timespec[1] = time_stamp;
1925 if (fdutimens (ofd, ofname, timespec) == 0)
1927 if (restoring && 1 < verbose) {
1928 fprintf(stderr, "%s: timestamp restored\n", ofname);
1931 else
1932 WARN ((stderr, "%s: %s: %s\n", program_name, ofname, strerror (errno)));
1933 #endif
1935 /* Change the group first, then the permissions, then the owner.
1936 That way, the permissions will be correct on systems that allow
1937 users to give away files, without introducing a security hole.
1938 Security depends on permissions not containing the setuid or
1939 setgid bits. */
1941 do_chown (ofd, ofname, -1, ifstat->st_gid);
1943 #if HAVE_FCHMOD
1944 r = fchmod (ofd, mode);
1945 #else
1946 r = chmod (ofname, mode);
1947 #endif
1948 if (r != 0)
1949 WARN ((stderr, "%s: %s: %s\n", program_name, ofname, strerror (errno)));
1951 do_chown (ofd, ofname, ifstat->st_uid, -1);
1954 #if ! NO_DIR
1956 /* ========================================================================
1957 * Recurse through the given directory.
1959 static void
1960 treat_dir (int fd, char *dir)
1962 DIR *dirp;
1963 char nbuf[MAX_PATH_LEN];
1964 char *entries;
1965 char const *entry;
1966 size_t entrylen;
1968 dirp = fdopendir (fd);
1970 if (dirp == NULL) {
1971 progerror(dir);
1972 close (fd);
1973 return ;
1976 entries = streamsavedir (dirp, SAVEDIR_SORT_NONE);
1977 if (! entries)
1978 progerror (dir);
1979 if (closedir (dirp) != 0)
1980 progerror (dir);
1981 if (! entries)
1982 return;
1984 for (entry = entries; *entry; entry += entrylen + 1) {
1985 size_t len = strlen (dir);
1986 entrylen = strlen (entry);
1987 if (strequ (entry, ".") || strequ (entry, ".."))
1988 continue;
1989 if (len + entrylen < MAX_PATH_LEN - 2) {
1990 strcpy(nbuf,dir);
1991 if (*last_component (nbuf) && !ISSLASH (nbuf[len - 1]))
1992 nbuf[len++] = '/';
1993 strcpy (nbuf + len, entry);
1994 treat_file(nbuf);
1995 } else {
1996 fprintf(stderr,"%s: %s/%s: pathname too long\n",
1997 program_name, dir, entry);
1998 exit_code = ERROR;
2001 free (entries);
2003 #endif /* ! NO_DIR */
2005 /* Make sure signals get handled properly. */
2007 static void
2008 install_signal_handlers ()
2010 int nsigs = sizeof handled_sig / sizeof handled_sig[0];
2011 int i;
2012 struct sigaction act;
2014 sigemptyset (&caught_signals);
2015 for (i = 0; i < nsigs; i++)
2017 sigaction (handled_sig[i], NULL, &act);
2018 if (act.sa_handler != SIG_IGN)
2019 sigaddset (&caught_signals, handled_sig[i]);
2022 act.sa_handler = abort_gzip_signal;
2023 act.sa_mask = caught_signals;
2024 act.sa_flags = 0;
2026 for (i = 0; i < nsigs; i++)
2027 if (sigismember (&caught_signals, handled_sig[i]))
2029 if (i == 0)
2030 foreground = 1;
2031 sigaction (handled_sig[i], &act, NULL);
2035 /* ========================================================================
2036 * Free all dynamically allocated variables and exit with the given code.
2038 static void
2039 do_exit (int exitcode)
2041 static int in_exit = 0;
2043 if (in_exit) exit(exitcode);
2044 in_exit = 1;
2045 free(env);
2046 env = NULL;
2047 FREE(inbuf);
2048 FREE(outbuf);
2049 FREE(d_buf);
2050 FREE(window);
2051 #ifndef MAXSEG_64K
2052 FREE(tab_prefix);
2053 #else
2054 FREE(tab_prefix0);
2055 FREE(tab_prefix1);
2056 #endif
2057 exit(exitcode);
2060 static void
2061 finish_out ()
2063 if (fclose (stdout) != 0)
2064 write_error ();
2065 do_exit (OK);
2068 /* ========================================================================
2069 * Close and unlink the output file.
2071 static void
2072 remove_output_file (bool signals_already_blocked)
2074 int fd;
2075 sigset_t oldset;
2077 if (!signals_already_blocked)
2078 sigprocmask (SIG_BLOCK, &caught_signals, &oldset);
2079 fd = remove_ofname_fd;
2080 if (0 <= fd)
2082 char fname[MAX_PATH_LEN];
2083 remove_ofname_fd = -1;
2084 close (fd);
2085 volatile_strcpy (fname, remove_ofname);
2086 xunlink (fname);
2088 if (!signals_already_blocked)
2089 sigprocmask (SIG_SETMASK, &oldset, NULL);
2092 /* ========================================================================
2093 * Error handler.
2095 void
2096 finish_up_gzip (int exitcode)
2098 if (0 <= remove_ofname_fd)
2099 remove_output_file (false);
2100 do_exit (exitcode);
2102 void
2103 abort_gzip ()
2105 finish_up_gzip (ERROR);
2107 /* ========================================================================
2108 * Signal handler.
2110 static void
2111 abort_gzip_signal (int sig)
2113 remove_output_file (true);
2114 signal (sig, SIG_DFL);
2115 raise (sig);