1 /* gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
3 Copyright (C) 1999, 2001-2002, 2006-2007, 2009-2021 Free Software
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)
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) 2018 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.",
39 /* Compress files with zip algorithm and 'compress' interface.
40 * See help() function below for all options.
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.
59 #include <sys/types.h>
78 #include "ignore-value.h"
79 #include "stat-time.h"
100 # include <utimens.h>
104 # define MAX_PATH_LEN 1024 /* max pathname length */
116 off_t
lseek (int fd
, off_t offset
, int whence
);
119 #ifndef HAVE_WORKING_O_NOFOLLOW
120 # define HAVE_WORKING_O_NOFOLLOW 0
123 /* Separator for file name parts (see shorten_name()) */
124 #ifdef NO_MULTIPLE_DOTS
125 # define PART_SEP "-"
127 # define PART_SEP "."
132 /* With IBM_Z_DFLTCC, DEFLATE COMPRESSION works faster with
133 page-aligned input and output buffers, and requires page-aligned
134 windows; the alignment requirement is 4096. On other platforms
135 alignment doesn't hurt, and alignment up to 4096 is portable so
137 #ifdef __alignas_is_defined
138 # define BUFFER_ALIGNED alignas (4096)
140 # define BUFFER_ALIGNED /**/
142 DECLARE(uch BUFFER_ALIGNED
, inbuf
, INBUFSIZ
+INBUF_EXTRA
);
143 DECLARE(uch BUFFER_ALIGNED
, outbuf
, OUTBUFSIZ
+OUTBUF_EXTRA
);
144 DECLARE(ush
, d_buf
, DIST_BUFSIZE
);
145 DECLARE(uch BUFFER_ALIGNED
, window
, 2L*WSIZE
);
147 DECLARE(ush
, tab_prefix
, 1L<<BITS
);
149 DECLARE(ush
, tab_prefix0
, 1L<<(BITS
-1));
150 DECLARE(ush
, tab_prefix1
, 1L<<(BITS
-1));
153 /* local variables */
155 /* If true, pretend that standard input is a tty. This option
156 is deliberately not documented, and only for testing. */
157 static bool presume_input_tty
;
159 /* If true, transfer output data to the output file's storage device
160 when supported. Otherwise, if the system crashes around the time
161 gzip is run, the user might lose both input and output data. See:
162 Pillai TS et al. All file systems are not created equal: on the
163 complexity of crafting crash-consistent applications. OSDI'14. 2014:433-48.
164 https://www.usenix.org/conference/osdi14/technical-sessions/presentation/pillai */
165 static bool synchronous
;
167 static int ascii
= 0; /* convert end-of-lines to local OS conventions */
168 int to_stdout
= 0; /* output to stdout (-c) */
169 static int decompress
= 0; /* decompress (-d) */
170 static int force
= 0; /* don't ask questions, compress links (-f) */
171 static int keep
= 0; /* keep (don't delete) input files */
172 static int no_name
= -1; /* don't save or restore the original file name */
173 static int no_time
= -1; /* don't save or restore the original file time */
174 static int recursive
= 0; /* recurse through directories (-r) */
175 static int list
= 0; /* list the file contents (-l) */
176 int verbose
= 0; /* be verbose (-v) */
177 int quiet
= 0; /* be very quiet (-q) */
178 static int do_lzw
= 0; /* generate output compatible with old compress (-Z) */
179 int test
= 0; /* test .gz file integrity */
180 static int foreground
= 0; /* set if program run in foreground */
181 char *program_name
; /* program name */
182 int maxbits
= BITS
; /* max bits per code for LZW */
183 int method
= DEFLATED
;/* compression method */
184 int level
= 6; /* compression level */
185 int exit_code
= OK
; /* program exit code */
186 int save_orig_name
; /* set if original name must be saved */
187 static int last_member
; /* set for .zip and .Z files */
188 static int part_nb
; /* number of parts in .gz file */
189 off_t ifile_size
; /* input file size, -1 for devices (debug only) */
190 static char *env
; /* contents of GZIP env variable */
191 static char const *z_suffix
; /* default suffix (can be set with --suffix) */
192 static size_t z_len
; /* strlen(z_suffix) */
194 /* The original timestamp (modification time). If the original is
195 unknown, TIME_STAMP.tv_nsec is negative. If the original is
196 greater than struct timespec range, TIME_STAMP is the maximal
197 struct timespec value; this can happen on hosts with 32-bit signed
198 time_t because the gzip format's MTIME is 32-bit unsigned.
199 The original cannot be less than struct timespec range. */
200 struct timespec time_stamp
;
202 /* The set of signals that are caught. */
203 static sigset_t caught_signals
;
205 /* If nonzero then exit with status WARNING, rather than with the usual
206 signal status, on receipt of a signal with this value. This
207 suppresses a "Broken Pipe" message with some shells. */
208 static int volatile exiting_signal
;
210 /* If nonnegative, close this file descriptor and unlink remove_ofname
212 static int volatile remove_ofname_fd
= -1;
213 static char volatile remove_ofname
[MAX_PATH_LEN
];
215 static bool stdin_was_read
;
217 off_t bytes_in
; /* number of input bytes */
218 off_t bytes_out
; /* number of output bytes */
219 static off_t total_in
; /* input bytes for all files */
220 static off_t total_out
; /* output bytes for all files */
221 char ifname
[MAX_PATH_LEN
]; /* input file name */
222 char ofname
[MAX_PATH_LEN
]; /* output file name */
223 static char dfname
[MAX_PATH_LEN
]; /* name of dir containing output file */
224 static struct stat istat
; /* status for input file */
225 int ifd
; /* input file descriptor */
226 int ofd
; /* output file descriptor */
227 static int dfd
= -1; /* output directory file descriptor */
228 unsigned insize
; /* valid bytes in inbuf */
229 unsigned inptr
; /* index of next byte to be processed in inbuf */
230 unsigned outcnt
; /* bytes in output buffer */
231 int rsync
= 0; /* make ryncable chunks */
233 static int handled_sig
[] =
235 /* SIGINT must be first, as 'foreground' depends on it. */
255 /* For long options that have no equivalent short option, use a
256 non-character as a pseudo short option, starting with CHAR_MAX + 1. */
259 PRESUME_INPUT_TTY_OPTION
= CHAR_MAX
+ 1,
263 /* A value greater than all valid long options, used as a flag to
264 distinguish options derived from the GZIP environment variable. */
268 static char const shortopts
[] = "ab:cdfhH?klLmMnNqrS:tvVZ123456789";
270 static const struct option longopts
[] =
272 /* { name has_arg *flag val } */
273 {"ascii", 0, 0, 'a'}, /* ascii text mode */
274 {"to-stdout", 0, 0, 'c'}, /* write output on standard output */
275 {"stdout", 0, 0, 'c'}, /* write output on standard output */
276 {"decompress", 0, 0, 'd'}, /* decompress */
277 {"uncompress", 0, 0, 'd'}, /* decompress */
278 /* {"encrypt", 0, 0, 'e'}, encrypt */
279 {"force", 0, 0, 'f'}, /* force overwrite of output file */
280 {"help", 0, 0, 'h'}, /* give help */
281 /* {"pkzip", 0, 0, 'k'}, force output in pkzip format */
282 {"keep", 0, 0, 'k'}, /* keep (don't delete) input files */
283 {"list", 0, 0, 'l'}, /* list .gz file contents */
284 {"license", 0, 0, 'L'}, /* display software license */
285 {"no-name", 0, 0, 'n'}, /* don't save or restore original name & time */
286 {"name", 0, 0, 'N'}, /* save or restore original name & time */
287 {"-presume-input-tty", no_argument
, NULL
, PRESUME_INPUT_TTY_OPTION
},
288 {"quiet", 0, 0, 'q'}, /* quiet mode */
289 {"silent", 0, 0, 'q'}, /* quiet mode */
290 {"synchronous",0, 0, SYNCHRONOUS_OPTION
},
291 {"recursive", 0, 0, 'r'}, /* recurse through directories */
292 {"suffix", 1, 0, 'S'}, /* use given suffix instead of .gz */
293 {"test", 0, 0, 't'}, /* test compressed file integrity */
294 {"verbose", 0, 0, 'v'}, /* verbose mode */
295 {"version", 0, 0, 'V'}, /* display version number */
296 {"fast", 0, 0, '1'}, /* compress faster */
297 {"best", 0, 0, '9'}, /* compress better */
298 {"lzw", 0, 0, 'Z'}, /* make output compatible with old compress */
299 {"bits", 1, 0, 'b'}, /* max number of bits per code (implies -Z) */
300 {"rsyncable", 0, 0, RSYNCABLE_OPTION
}, /* make rsync-friendly archive */
304 /* local functions */
306 local noreturn
void try_help (void);
307 local
void help (void);
308 local
void license (void);
309 local
void version (void);
310 local
int input_eof (void);
311 local
void treat_stdin (void);
312 local
void treat_file (char *iname
);
313 local
int create_outfile (void);
314 local
char *get_suffix (char *name
);
315 local
int open_input_file (char *iname
, struct stat
*sbuf
);
316 local
void discard_input_bytes (size_t nbytes
, unsigned int flags
);
317 local
int make_ofname (void);
318 local
void shorten_name (char *name
);
319 local
int get_method (int in
);
320 local
void do_list (int ifd
, int method
);
321 local
int check_ofname (void);
322 local
void copy_stat (struct stat
*ifstat
);
323 local
void install_signal_handlers (void);
324 static void remove_output_file (bool);
325 static void abort_gzip_signal (int);
326 local noreturn
void do_exit (int exitcode
);
327 static void finish_out (void);
328 int main (int argc
, char **argv
);
329 static int (*work
) (int infile
, int outfile
) = zip
; /* function to call */
332 local
void treat_dir (int fd
, char *dir
);
335 #define strequ(s1, s2) (strcmp((s1),(s2)) == 0)
340 fprintf (stderr
, "Try `%s --help' for more information.\n",
345 /* ======================================================================== */
348 static char const* const help_msg
[] = {
349 "Compress or uncompress FILEs (by default, compress FILES in-place).",
351 "Mandatory arguments to long options are mandatory for short options too.",
354 " -a, --ascii ascii text; convert end-of-line using local conventions",
356 " -c, --stdout write on standard output, keep original files unchanged",
357 " -d, --decompress decompress",
358 /* -e, --encrypt encrypt */
359 " -f, --force force overwrite of output file and compress links",
360 " -h, --help give this help",
361 /* -k, --pkzip force output in pkzip format */
362 " -k, --keep keep (don't delete) input files",
363 " -l, --list list compressed file contents",
364 " -L, --license display software license",
366 " -m do not save or restore the original modification time",
367 " -M, --time save or restore the original modification time",
369 " -n, --no-name do not save or restore the original name and timestamp",
370 " -N, --name save or restore the original name and timestamp",
371 " -q, --quiet suppress all warnings",
373 " -r, --recursive operate recursively on directories",
375 " --rsyncable make rsync-friendly archive",
376 " -S, --suffix=SUF use suffix SUF on compressed files",
377 " --synchronous synchronous output (safer if system crashes, but slower)",
378 " -t, --test test compressed file integrity",
379 " -v, --verbose verbose mode",
380 " -V, --version display version number",
381 " -1, --fast compress faster",
382 " -9, --best compress better",
384 " -Z, --lzw produce output compatible with old compress",
385 " -b, --bits=BITS max number of bits per code (implies -Z)",
388 "With no FILE, or when FILE is -, read standard input.",
390 "Report bugs to <bug-gzip@gnu.org>.",
392 char const *const *p
= help_msg
;
394 printf ("Usage: %s [OPTION]... [FILE]...\n", program_name
);
395 while (*p
) printf ("%s\n", *p
++);
398 /* ======================================================================== */
401 char const *const *p
= license_msg
;
403 printf ("%s %s\n", program_name
, Version
);
404 while (*p
) printf ("%s\n", *p
++);
407 /* ======================================================================== */
412 printf ("Written by Jean-loup Gailly.\n");
415 local
void progerror (char const *string
)
418 fprintf (stderr
, "%s: ", program_name
);
424 /* ======================================================================== */
425 int main (int argc
, char **argv
)
427 int file_count
; /* number of files to process */
428 size_t proglen
; /* length of program_name */
433 EXPAND(argc
, argv
); /* wild card expansion if necessary */
435 program_name
= gzip_base_name (argv
[0]);
436 proglen
= strlen (program_name
);
438 /* Suppress .exe for MSDOS and OS/2: */
439 if (4 < proglen
&& strequ (program_name
+ proglen
- 4, ".exe"))
440 program_name
[proglen
- 4] = '\0';
442 /* Add options in GZIP environment variable if there is one */
444 env
= add_envopt (&env_argc
, &argv_copy
, OPTIONS_VAR
);
445 env_argv
= env
? argv_copy
: NULL
;
448 # define GNU_STANDARD 1
451 /* For compatibility with old compress, use program name as an option.
452 * Unless you compile with -DGNU_STANDARD=0, this program will behave as
453 * gzip even if it is invoked under the name gunzip or zcat.
455 * Systems which do not support links can still use -d or -dc.
456 * Ignore an .exe extension for MSDOS and OS/2.
458 if (strncmp (program_name
, "un", 2) == 0 /* ungzip, uncompress */
459 || strncmp (program_name
, "gun", 3) == 0) /* gunzip */
461 else if (strequ (program_name
+ 1, "cat") /* zcat, pcat, gcat */
462 || strequ (program_name
, "gzcat")) /* gzcat */
463 decompress
= to_stdout
= 1;
467 z_len
= strlen(z_suffix
);
475 if (env_argv
[optind
] && strequ (env_argv
[optind
], "--"))
476 optc
= ENV_OPTION
+ '-';
479 optc
= getopt_long (env_argc
, env_argv
, shortopts
, longopts
,
485 if (optind
!= env_argc
)
488 ("%s: %s: non-option in "OPTIONS_VAR
489 " environment variable\n"),
490 program_name
, env_argv
[optind
]);
494 /* Wait until here before warning, so that GZIP='-q'
496 if (env_argc
!= 1 && !quiet
)
498 ("%s: warning: "OPTIONS_VAR
" environment variable"
499 " is deprecated; use an alias or script\n"),
502 /* Start processing ARGC and ARGV instead. */
512 optc
= getopt_long (argc
, argv
, shortopts
, longopts
, &longind
);
520 maxbits
= atoi(optarg
);
521 for (; *optarg
; optarg
++)
522 if (! ('0' <= *optarg
&& *optarg
<= '9'))
524 fprintf (stderr
, "%s: -b operand is not an integer\n",
530 to_stdout
= 1; break;
532 decompress
= 1; break;
536 help (); finish_out (); break;
540 list
= decompress
= to_stdout
= 1; break;
542 license (); finish_out (); break;
543 case 'm': /* undocumented, may change later */
545 case 'M': /* undocumented, may change later */
548 case 'n' + ENV_OPTION
:
549 no_name
= no_time
= 1; break;
551 case 'N' + ENV_OPTION
:
552 no_name
= no_time
= 0; break;
553 case PRESUME_INPUT_TTY_OPTION
:
554 presume_input_tty
= true; break;
556 case 'q' + ENV_OPTION
:
557 quiet
= 1; verbose
= 0; break;
560 fprintf (stderr
, "%s: -r not supported on this system\n",
568 case RSYNCABLE_OPTION
:
569 case RSYNCABLE_OPTION
+ ENV_OPTION
:
573 #ifdef NO_MULTIPLE_DOTS
574 if (*optarg
== '.') optarg
++;
576 z_len
= strlen(optarg
);
579 case SYNCHRONOUS_OPTION
:
583 test
= decompress
= to_stdout
= 1;
586 case 'v' + ENV_OPTION
:
587 verbose
++; quiet
= 0; break;
589 version (); finish_out (); break;
594 fprintf(stderr
, "%s: -Z not supported in this version\n",
599 case '1' + ENV_OPTION
: case '2' + ENV_OPTION
: case '3' + ENV_OPTION
:
600 case '4' + ENV_OPTION
: case '5' + ENV_OPTION
: case '6' + ENV_OPTION
:
601 case '7' + ENV_OPTION
: case '8' + ENV_OPTION
: case '9' + ENV_OPTION
:
604 case '1': case '2': case '3': case '4':
605 case '5': case '6': case '7': case '8': case '9':
610 if (ENV_OPTION
<= optc
&& optc
!= ENV_OPTION
+ '?')
612 /* Output a diagnostic, since getopt_long didn't. */
613 fprintf (stderr
, "%s: ", program_name
);
615 fprintf (stderr
, "-%c: ", optc
- ENV_OPTION
);
617 fprintf (stderr
, "--%s: ", longopts
[longind
].name
);
618 fprintf (stderr
, ("option not valid in "OPTIONS_VAR
619 " environment variable\n"));
623 } /* loop on all arguments */
625 /* By default, save name and timestamp on compression but do not
626 * restore them on decompression.
628 if (no_time
< 0) no_time
= decompress
;
629 if (no_name
< 0) no_name
= decompress
;
631 file_count
= argc
- optind
;
635 if (ascii
&& !quiet
) {
636 fprintf(stderr
, "%s: option --ascii ignored on this system\n",
640 if (z_len
== 0 || z_len
> MAX_SUFFIX
) {
641 fprintf(stderr
, "%s: invalid suffix '%s'\n", program_name
, z_suffix
);
645 if (do_lzw
&& !decompress
) work
= lzw
;
647 /* Allocate all global buffers (for DYN_ALLOC option) */
648 ALLOC(uch
, inbuf
, INBUFSIZ
+INBUF_EXTRA
);
649 ALLOC(uch
, outbuf
, OUTBUFSIZ
+OUTBUF_EXTRA
);
650 ALLOC(ush
, d_buf
, DIST_BUFSIZE
);
651 ALLOC(uch
, window
, 2L*WSIZE
);
653 ALLOC(ush
, tab_prefix
, 1L<<BITS
);
655 ALLOC(ush
, tab_prefix0
, 1L<<(BITS
-1));
656 ALLOC(ush
, tab_prefix1
, 1L<<(BITS
-1));
660 exiting_signal
= quiet
? SIGPIPE
: 0;
662 install_signal_handlers ();
664 /* And get to work */
665 if (file_count
!= 0) {
666 if (to_stdout
&& !test
&& !list
&& (!decompress
|| !ascii
)) {
667 SET_BINARY_MODE (STDOUT_FILENO
);
669 while (optind
< argc
) {
670 treat_file(argv
[optind
++]);
672 } else { /* Standard input */
675 if (stdin_was_read
&& close (STDIN_FILENO
) != 0)
677 strcpy (ifname
, "stdin");
682 /* Output any totals, and check for output errors. */
683 if (!quiet
&& 1 < file_count
)
685 if (fflush (stdout
) != 0)
690 && fdatasync (STDOUT_FILENO
) != 0 && errno
!= EINVAL
)
691 || close (STDOUT_FILENO
) != 0)
697 /* Return nonzero when at end of file on input. */
701 if (!decompress
|| last_member
)
706 if (insize
!= INBUFSIZ
|| fill_inbuf (1) == EOF
)
709 /* Unget the char that fill_inbuf got. */
717 get_input_size_and_time (void)
720 time_stamp
.tv_nsec
= -1;
722 /* Record the input file's size and timestamp only if it is a
723 regular file. Doing this for the timestamp helps to keep gzip's
724 output more reproducible when it is used as part of a
727 if (S_ISREG (istat
.st_mode
))
729 ifile_size
= istat
.st_size
;
730 if (!no_time
|| list
)
731 time_stamp
= get_stat_mtime (&istat
);
735 /* ========================================================================
736 * Compress or decompress stdin
738 local
void treat_stdin()
741 && (presume_input_tty
742 || isatty (decompress
? STDIN_FILENO
: STDOUT_FILENO
))) {
743 /* Do not send compressed data to the terminal or read it from
744 * the terminal. We get here when user invoked the program
745 * without parameters, so be helpful. According to the GNU standards:
747 * If there is one behavior you think is most useful when the output
748 * is to a terminal, and another that you think is most useful when
749 * the output is a file or a pipe, then it is usually best to make
750 * the default behavior the one that is useful with output to a
751 * terminal, and have an option for the other behavior.
753 * Here we use the --force option to get the other behavior.
757 ("%s: compressed data not %s a terminal."
758 " Use -f to force %scompression.\n"
759 "For help, type: %s -h\n"),
761 decompress
? "read from" : "written to",
762 decompress
? "de" : "",
767 if (decompress
|| !ascii
) {
768 SET_BINARY_MODE (STDIN_FILENO
);
770 if (!test
&& !list
&& (!decompress
|| !ascii
)) {
771 SET_BINARY_MODE (STDOUT_FILENO
);
773 strcpy(ifname
, "stdin");
774 strcpy(ofname
, "stdout");
776 /* Get the file's timestamp and size. */
777 if (fstat (STDIN_FILENO
, &istat
) != 0)
779 progerror ("standard input");
783 get_input_size_and_time ();
785 clear_bufs(); /* clear input and output buffers */
789 stdin_was_read
= true;
792 method
= get_method(ifd
);
794 do_exit(exit_code
); /* error message already emitted */
798 do_list(ifd
, method
);
802 /* Actually do the compression/decompression. Loop over zipped members.
805 if (work (STDIN_FILENO
, STDOUT_FILENO
) != OK
)
811 method
= get_method(ifd
);
812 if (method
< 0) return; /* error message already emitted */
813 bytes_out
= 0; /* required for length check */
818 fprintf(stderr
, " OK\n");
820 } else if (!decompress
) {
821 display_ratio(bytes_in
-(bytes_out
-header_bytes
), bytes_in
, stderr
);
822 fprintf(stderr
, "\n");
823 #ifdef DISPLAY_STDIN_RATIO
825 display_ratio(bytes_out
-(bytes_in
-header_bytes
), bytes_out
,stderr
);
826 fprintf(stderr
, "\n");
832 static char const dot
= '.';
834 /* True if the cached directory for calls to openat etc. is DIR, with
835 length DIRLEN. DIR need not be null-terminated. DIRLEN must be
836 less than MAX_PATH_LEN. */
838 atdir_eq (char const *dir
, ptrdiff_t dirlen
)
841 dir
= &dot
, dirlen
= 1;
842 return memcmp (dfname
, dir
, dirlen
) == 0 && !dfname
[dirlen
];
845 /* Set the directory used for calls to openat etc. to be the directory
846 DIR, with length DIRLEN. DIR need not be null-terminated.
847 DIRLEN must be less than MAX_PATH_LEN. Return a file descriptor for
848 the directory, or -1 if one could not be obtained. */
850 atdir_set (char const *dir
, ptrdiff_t dirlen
)
852 /* Don't bother opening directories on older systems that
853 lack openat and unlinkat. It's not worth the porting hassle. */
854 #if HAVE_OPENAT && HAVE_UNLINKAT
855 enum { try_opening_directories
= true };
857 enum { try_opening_directories
= false };
860 if (try_opening_directories
&& ! atdir_eq (dir
, dirlen
))
865 dir
= &dot
, dirlen
= 1;
866 memcpy (dfname
, dir
, dirlen
);
867 dfname
[dirlen
] = '\0';
868 dfd
= open (dfname
, O_SEARCH
| O_DIRECTORY
);
874 /* ========================================================================
875 * Compress or decompress the given file
877 local
void treat_file(iname
)
880 /* Accept "-" as synonym for stdin */
881 if (strequ(iname
, "-")) {
882 int cflag
= to_stdout
;
888 /* Check if the input file is present, set ifname and istat: */
889 ifd
= open_input_file (iname
, &istat
);
893 /* If the input name is that of a directory, recurse or ignore: */
894 if (S_ISDIR(istat
.st_mode
)) {
897 treat_dir (ifd
, iname
);
898 /* Warning: ifname is now garbage */
903 WARN ((stderr
, "%s: %s is a directory -- ignored\n",
904 program_name
, ifname
));
910 if (! S_ISREG (istat
.st_mode
))
913 "%s: %s is not a directory or a regular file - ignored\n",
914 program_name
, ifname
));
918 if (istat
.st_mode
& S_ISUID
)
920 WARN ((stderr
, "%s: %s is set-user-ID on execution - ignored\n",
921 program_name
, ifname
));
925 if (istat
.st_mode
& S_ISGID
)
927 WARN ((stderr
, "%s: %s is set-group-ID on execution - ignored\n",
928 program_name
, ifname
));
935 if (istat
.st_mode
& S_ISVTX
)
938 "%s: %s has the sticky bit set - file ignored\n",
939 program_name
, ifname
));
943 if (2 <= istat
.st_nlink
)
945 WARN ((stderr
, "%s: %s has %lu other link%s -- file ignored\n",
946 program_name
, ifname
,
947 (unsigned long int) istat
.st_nlink
- 1,
948 istat
.st_nlink
== 2 ? "" : "s"));
955 get_input_size_and_time ();
957 /* Generate output file name. For -r and (-t or -l), skip files
958 * without a valid gzip suffix (check done in make_ofname).
960 if (to_stdout
&& !list
&& !test
) {
961 strcpy(ofname
, "stdout");
963 } else if (make_ofname() != OK
) {
968 clear_bufs(); /* clear input and output buffers */
972 method
= get_method(ifd
); /* updates ofname if original given */
975 return; /* error message already emitted */
979 do_list(ifd
, method
);
980 if (close (ifd
) != 0)
985 /* If compressing to a file, check if ofname is not ambiguous
986 * because the operating system truncates names. Otherwise, generate
987 * a new ofname and save the original name in the compressed file.
991 /* Keep remove_ofname_fd negative. */
993 if (create_outfile() != OK
) return;
995 if (!decompress
&& save_orig_name
&& !verbose
&& !quiet
) {
996 fprintf(stderr
, "%s: %s compressed to %s\n",
997 program_name
, ifname
, ofname
);
1000 /* Keep the name even if not truncated except with --no-name: */
1001 if (!save_orig_name
) save_orig_name
= !no_name
;
1004 fprintf(stderr
, "%s:\t", ifname
);
1007 /* Actually do the compression/decompression. Loop over zipped members.
1010 if ((*work
)(ifd
, ofd
) != OK
) {
1011 method
= -1; /* force cleanup */
1018 method
= get_method(ifd
);
1019 if (method
< 0) break; /* error message already emitted */
1020 bytes_out
= 0; /* required for length check */
1023 if (close (ifd
) != 0)
1031 && ((0 <= dfd
&& fdatasync (dfd
) != 0 && errno
!= EINVAL
)
1032 || (fsync (ofd
) != 0 && errno
!= EINVAL
)))
1033 || close (ofd
) != 0)
1040 char *ifbase
= last_component (ifname
);
1041 int ufd
= atdir_eq (ifname
, ifbase
- ifname
) ? dfd
: -1;
1044 sigprocmask (SIG_BLOCK
, &caught_signals
, &oldset
);
1045 remove_ofname_fd
= -1;
1046 res
= ufd
< 0 ? xunlink (ifname
) : unlinkat (ufd
, ifbase
, 0);
1047 unlink_errno
= res
== 0 ? 0 : errno
;
1048 sigprocmask (SIG_SETMASK
, &oldset
, NULL
);
1052 WARN ((stderr
, "%s: ", program_name
));
1055 errno
= unlink_errno
;
1064 remove_output_file (false);
1068 /* Display statistics */
1071 fprintf(stderr
, " OK");
1072 } else if (decompress
) {
1073 display_ratio(bytes_out
-(bytes_in
-header_bytes
), bytes_out
,stderr
);
1075 display_ratio(bytes_in
-(bytes_out
-header_bytes
), bytes_in
, stderr
);
1077 if (!test
&& !to_stdout
)
1078 fprintf(stderr
, " -- %s %s", keep
? "created" : "replaced with",
1080 fprintf(stderr
, "\n");
1085 volatile_strcpy (char volatile *dst
, char const volatile *src
)
1087 while ((*dst
++ = *src
++))
1091 /* ========================================================================
1092 * Create the output file. Return OK or ERROR.
1093 * Try several times if necessary to avoid truncating the z_suffix. For
1094 * example, do not create a compressed file of name "1234567890123."
1095 * Sets save_orig_name to true if the file name has been truncated.
1096 * IN assertions: the input file has already been open (ifd is set) and
1097 * ofname has already been updated if there was an original name.
1098 * OUT assertions: ifd and ofd are closed in case of error.
1100 local
int create_outfile()
1102 int name_shortened
= 0;
1103 int flags
= (O_WRONLY
| O_CREAT
| O_EXCL
1104 | (ascii
&& decompress
? 0 : O_BINARY
));
1105 char const *base
= ofname
;
1106 int atfd
= AT_FDCWD
;
1110 char const *b
= last_component (ofname
);
1111 int f
= atdir_set (ofname
, b
- ofname
);
1124 volatile_strcpy (remove_ofname
, ofname
);
1126 sigprocmask (SIG_BLOCK
, &caught_signals
, &oldset
);
1127 remove_ofname_fd
= ofd
= openat (atfd
, base
, flags
, S_IRUSR
| S_IWUSR
);
1129 sigprocmask (SIG_SETMASK
, &oldset
, NULL
);
1138 shorten_name (ofname
);
1144 if (check_ofname () != OK
)
1158 if (name_shortened
&& decompress
)
1160 /* name might be too long if an original name was saved */
1161 WARN ((stderr
, "%s: %s: warning, name truncated\n",
1162 program_name
, ofname
));
1168 /* ========================================================================
1169 * Return a pointer to the 'z' suffix of a file name, or NULL. For all
1170 * systems, ".gz", ".z", ".Z", ".taz", ".tgz", "-gz", "-z" and "_z" are
1171 * accepted suffixes, in addition to the value of the --suffix option.
1172 * ".tgz" is a useful convention for tar.z files on systems limited
1173 * to 3 characters extensions. On such systems, ".?z" and ".??z" are
1174 * also accepted suffixes. For Unix, we do not want to accept any
1175 * .??z suffix as indicating a compressed file; some people use .xyz
1176 * to denote volume data.
1178 local
char *get_suffix(name
)
1182 char suffix
[MAX_SUFFIX
+3]; /* last chars of name, forced to lower case */
1183 static char const *known_suffixes
[] =
1184 {NULL
, ".gz", ".z", ".taz", ".tgz", "-gz", "-z", "_z",
1185 #ifdef MAX_EXT_CHARS
1190 bool suffix_of_builtin
= false;
1192 /* Normally put Z_SUFFIX at the start of KNOWN_SUFFIXES, but if it
1193 is a suffix of one of them, put it at the end. */
1194 for (suf
= known_suffixes
+ 1; *suf
; suf
++)
1196 size_t suflen
= strlen (*suf
);
1197 if (z_len
< suflen
&& strequ (z_suffix
, *suf
+ suflen
- z_len
))
1199 suffix_of_builtin
= true;
1204 char *z_lower
= xstrdup(z_suffix
);
1206 known_suffixes
[suffix_of_builtin
1207 ? sizeof known_suffixes
/ sizeof *known_suffixes
- 2
1209 suf
= known_suffixes
+ suffix_of_builtin
;
1211 nlen
= strlen(name
);
1212 if (nlen
<= MAX_SUFFIX
+2) {
1213 strcpy(suffix
, name
);
1215 strcpy(suffix
, name
+nlen
-MAX_SUFFIX
-2);
1218 slen
= strlen(suffix
);
1221 int s
= strlen(*suf
);
1222 if (slen
> s
&& ! ISSLASH (suffix
[slen
- s
- 1])
1223 && strequ(suffix
+ slen
- s
, *suf
)) {
1224 match
= name
+nlen
-s
;
1227 } while (*++suf
!= NULL
);
1234 /* Open file NAME with the given flags and store its status
1235 into *ST. Return a file descriptor to the newly opened file, or -1
1236 (setting errno) on failure. */
1238 open_and_stat (char *name
, int flags
, struct stat
*st
)
1241 int atfd
= AT_FDCWD
;
1242 char const *base
= name
;
1244 /* Refuse to follow symbolic links unless -c or -f. */
1245 if (!to_stdout
&& !force
)
1247 if (HAVE_WORKING_O_NOFOLLOW
)
1248 flags
|= O_NOFOLLOW
;
1252 if (lstat (name
, st
) != 0)
1254 else if (S_ISLNK (st
->st_mode
))
1265 char const *b
= last_component (name
);
1266 int f
= atdir_set (name
, b
- name
);
1274 fd
= openat (atfd
, base
, flags
);
1275 if (0 <= fd
&& fstat (fd
, st
) != 0)
1286 /* ========================================================================
1287 * Set ifname to the input file name (with a suffix appended if necessary)
1288 * and istat to its stats. For decompression, if no file exists with the
1289 * original name, try adding successively z_suffix, .gz, .z, -z and .Z.
1290 * For MSDOS, we try only z_suffix and z.
1291 * Return an open file descriptor or -1.
1294 open_input_file (iname
, sbuf
)
1298 int ilen
; /* strlen(ifname) */
1299 int z_suffix_errno
= 0;
1300 static char const *suffixes
[] = {NULL
, ".gz", ".z", "-z", ".Z", NULL
};
1301 char const **suf
= suffixes
;
1303 #ifdef NO_MULTIPLE_DOTS
1304 char *dot
; /* pointer to ifname extension, or NULL */
1307 int open_flags
= (O_RDONLY
| O_NONBLOCK
| O_NOCTTY
1308 | (ascii
&& !decompress
? 0 : O_BINARY
));
1312 if (sizeof ifname
- 1 <= strlen (iname
))
1315 strcpy(ifname
, iname
);
1317 /* If input file exists, return OK. */
1318 fd
= open_and_stat (ifname
, open_flags
, sbuf
);
1322 if (!decompress
|| errno
!= ENOENT
) {
1326 /* File.ext doesn't exist. Try adding a suffix. */
1327 s
= get_suffix(ifname
);
1329 progerror(ifname
); /* ifname already has z suffix and does not exist */
1332 #ifdef NO_MULTIPLE_DOTS
1333 dot
= strrchr(ifname
, '.');
1335 strcat(ifname
, ".");
1336 dot
= strrchr(ifname
, '.');
1339 ilen
= strlen(ifname
);
1340 if (strequ(z_suffix
, ".gz")) suf
++;
1342 /* Search for all suffixes */
1344 char const *s0
= s
= *suf
;
1345 strcpy (ifname
, iname
);
1346 #ifdef NO_MULTIPLE_DOTS
1348 if (*dot
== '\0') strcpy (dot
, ".");
1350 #ifdef MAX_EXT_CHARS
1351 if (MAX_EXT_CHARS
< strlen (s
) + strlen (dot
+ 1))
1352 dot
[MAX_EXT_CHARS
+ 1 - strlen (s
)] = '\0';
1354 if (sizeof ifname
<= ilen
+ strlen (s
))
1357 fd
= open_and_stat (ifname
, open_flags
, sbuf
);
1360 if (errno
!= ENOENT
)
1365 if (strequ (s0
, z_suffix
))
1366 z_suffix_errno
= errno
;
1367 } while (*++suf
!= NULL
);
1369 /* No suffix found, complain using z_suffix: */
1370 strcpy(ifname
, iname
);
1371 #ifdef NO_MULTIPLE_DOTS
1372 if (*dot
== '\0') strcpy(dot
, ".");
1374 #ifdef MAX_EXT_CHARS
1375 if (MAX_EXT_CHARS
< z_len
+ strlen (dot
+ 1))
1376 dot
[MAX_EXT_CHARS
+ 1 - z_len
] = '\0';
1378 strcat(ifname
, z_suffix
);
1379 errno
= z_suffix_errno
;
1384 fprintf (stderr
, "%s: %s: file name too long\n", program_name
, iname
);
1389 /* ========================================================================
1390 * Generate ofname given ifname. Return OK, or WARNING if file must be skipped.
1391 * Sets save_orig_name to true if the file name has been truncated.
1393 local
int make_ofname()
1395 char *suff
; /* ofname z suffix */
1397 strcpy(ofname
, ifname
);
1398 /* strip a version number if any and get the gzip suffix if present: */
1399 suff
= get_suffix(ofname
);
1403 /* With -t or -l, try all files (even without .gz suffix)
1404 * except with -r (behave as with just -dr).
1406 if (!recursive
&& (list
|| test
)) return OK
;
1408 /* Avoid annoying messages with -r */
1409 if (verbose
|| (!recursive
&& !quiet
)) {
1410 WARN((stderr
,"%s: %s: unknown suffix -- ignored\n",
1411 program_name
, ifname
));
1415 /* Make a special case for .tgz and .taz: */
1417 if (strequ(suff
, ".tgz") || strequ(suff
, ".taz")) {
1418 strcpy(suff
, ".tar");
1420 *suff
= '\0'; /* strip the z suffix */
1422 /* ofname might be changed later if infile contains an original name */
1424 } else if (suff
&& ! force
) {
1425 /* Avoid annoying messages with -r (see treat_dir()) */
1426 if (verbose
|| (!recursive
&& !quiet
)) {
1427 /* Don't use WARN, as it affects exit status. */
1428 fprintf (stderr
, "%s: %s already has %s suffix -- unchanged\n",
1429 program_name
, ifname
, suff
);
1435 #ifdef NO_MULTIPLE_DOTS
1436 suff
= strrchr(ofname
, '.');
1438 if (sizeof ofname
<= strlen (ofname
) + 1)
1440 strcat(ofname
, ".");
1441 # ifdef MAX_EXT_CHARS
1442 if (strequ(z_suffix
, "z")) {
1443 if (sizeof ofname
<= strlen (ofname
) + 2)
1445 strcat(ofname
, "gz"); /* enough room */
1448 /* On the Atari and some versions of MSDOS,
1449 * ENAMETOOLONG does not work correctly. So we
1450 * must truncate here.
1452 } else if (strlen(suff
)-1 + z_len
> MAX_SUFFIX
) {
1453 suff
[MAX_SUFFIX
+1-z_len
] = '\0';
1457 #endif /* NO_MULTIPLE_DOTS */
1458 if (sizeof ofname
<= strlen (ofname
) + z_len
)
1460 strcat(ofname
, z_suffix
);
1462 } /* decompress ? */
1466 WARN ((stderr
, "%s: %s: file name too long\n", program_name
, ifname
));
1470 /* Discard NBYTES input bytes from the input, or up through the next
1471 zero byte if NBYTES == (size_t) -1. If FLAGS say that the header
1472 CRC should be computed, update the CRC accordingly. */
1474 discard_input_bytes (nbytes
, flags
)
1480 uch c
= get_byte ();
1481 if (flags
& HEADER_CRC
)
1483 if (nbytes
!= (size_t) -1)
1490 /* ========================================================================
1491 * Check the magic number of the input file and update ofname if an
1492 * original name was given and to_stdout is not set.
1493 * Return the compression method, -1 for error, -2 for warning.
1494 * Set inptr to the offset of the next byte to be processed.
1495 * Updates time_stamp if there is one and neither -m nor -n is used.
1496 * This function may be called repeatedly for an input file consisting
1497 * of several contiguous gzip'ed members.
1498 * IN assertions: there is at least one remaining compressed member.
1499 * If the member is a zip file, it must be the only one.
1501 local
int get_method(in
)
1502 int in
; /* input file descriptor */
1504 uch flags
; /* compression flags */
1505 uch magic
[10]; /* magic header */
1506 int imagic0
; /* first magic byte or EOF */
1507 int imagic1
; /* like magic[1], but can represent EOF */
1508 ulg stamp
; /* timestamp */
1510 /* If --force and --stdout, zcat == cat, so do not complain about
1511 * premature end of file: use try_byte instead of get_byte.
1513 if (force
&& to_stdout
) {
1514 imagic0
= try_byte();
1516 imagic1
= try_byte ();
1518 /* If try_byte returned EOF, magic[1] == (char) EOF. */
1520 magic
[0] = get_byte ();
1523 magic
[1] = get_byte ();
1524 imagic1
= 0; /* avoid lint warning */
1526 imagic1
= try_byte ();
1530 method
= -1; /* unknown yet */
1531 part_nb
++; /* number of parts in gzip file */
1534 /* assume multiple members in gzip file except for record oriented I/O */
1536 if (memcmp(magic
, GZIP_MAGIC
, 2) == 0
1537 || memcmp(magic
, OLD_GZIP_MAGIC
, 2) == 0) {
1539 method
= (int)get_byte();
1540 if (method
!= DEFLATED
) {
1542 "%s: %s: unknown method %d -- not supported\n",
1543 program_name
, ifname
, method
);
1548 flags
= (uch
)get_byte();
1550 if ((flags
& ENCRYPTED
) != 0) {
1552 "%s: %s is encrypted -- not supported\n",
1553 program_name
, ifname
);
1557 if ((flags
& RESERVED
) != 0) {
1559 "%s: %s has flags 0x%x -- not supported\n",
1560 program_name
, ifname
, flags
);
1562 if (force
<= 1) return -1;
1564 stamp
= (ulg
)get_byte();
1565 stamp
|= ((ulg
)get_byte()) << 8;
1566 stamp
|= ((ulg
)get_byte()) << 16;
1567 stamp
|= ((ulg
)get_byte()) << 24;
1568 if (stamp
!= 0 && !no_time
)
1570 if (stamp
<= TYPE_MAXIMUM (time_t))
1572 time_stamp
.tv_sec
= stamp
;
1573 time_stamp
.tv_nsec
= 0;
1578 "%s: %s: MTIME %lu out of range for this platform\n",
1579 program_name
, ifname
, stamp
));
1580 time_stamp
.tv_sec
= TYPE_MAXIMUM (time_t);
1581 time_stamp
.tv_nsec
= TIMESPEC_RESOLUTION
- 1;
1585 magic
[8] = get_byte (); /* Ignore extra flags. */
1586 magic
[9] = get_byte (); /* Ignore OS type. */
1588 if (flags
& HEADER_CRC
)
1590 magic
[2] = DEFLATED
;
1592 magic
[4] = stamp
& 0xff;
1593 magic
[5] = (stamp
>> 8) & 0xff;
1594 magic
[6] = (stamp
>> 16) & 0xff;
1595 magic
[7] = stamp
>> 24;
1600 if ((flags
& EXTRA_FIELD
) != 0) {
1602 unsigned int len
= lenbuf
[0] = get_byte ();
1603 len
|= (lenbuf
[1] = get_byte ()) << 8;
1605 fprintf(stderr
,"%s: %s: extra field of %u bytes ignored\n",
1606 program_name
, ifname
, len
);
1608 if (flags
& HEADER_CRC
)
1610 discard_input_bytes (len
, flags
);
1613 /* Get original file name if it was truncated */
1614 if ((flags
& ORIG_NAME
) != 0) {
1615 if (no_name
|| (to_stdout
&& !list
) || part_nb
> 1) {
1616 /* Discard the old name */
1617 discard_input_bytes (-1, flags
);
1619 /* Copy the base name. Keep a directory prefix intact. */
1620 char *p
= gzip_base_name (ofname
);
1623 *p
= (char) get_byte ();
1624 if (*p
++ == '\0') break;
1625 if (p
>= ofname
+sizeof(ofname
)) {
1626 gzip_error ("corrupted input -- file name too large");
1629 if (flags
& HEADER_CRC
)
1630 updcrc ((uch
*) base
, p
- base
);
1631 p
= gzip_base_name (base
);
1632 memmove (base
, p
, strlen (p
) + 1);
1633 /* If necessary, adapt the name to local OS conventions: */
1635 MAKE_LEGAL_NAME(base
);
1636 if (base
) list
=0; /* avoid warning about unused variable */
1638 } /* no_name || to_stdout */
1641 /* Discard file comment if any */
1642 if ((flags
& COMMENT
) != 0) {
1643 discard_input_bytes (-1, flags
);
1646 if (flags
& HEADER_CRC
)
1648 unsigned int crc16
= updcrc (magic
, 0) & 0xffff;
1649 unsigned int header16
= get_byte ();
1650 header16
|= ((unsigned int) get_byte ()) << 8;
1651 if (header16
!= crc16
)
1654 "%s: %s: header checksum 0x%04x != computed checksum 0x%04x\n",
1655 program_name
, ifname
, header16
, crc16
);
1663 header_bytes
= inptr
+ 2*4; /* include crc and size */
1666 } else if (memcmp(magic
, PKZIP_MAGIC
, 2) == 0 && inptr
== 2
1667 && memcmp((char*)inbuf
, PKZIP_MAGIC
, 4) == 0) {
1668 /* To simplify the code, we support a zip file when alone only.
1669 * We are thus guaranteed that the entire local header fits in inbuf.
1673 if (check_zipfile(in
) != OK
) return -1;
1674 /* check_zipfile may get ofname from the local header */
1677 } else if (memcmp(magic
, PACK_MAGIC
, 2) == 0) {
1681 } else if (memcmp(magic
, LZW_MAGIC
, 2) == 0) {
1683 method
= COMPRESSED
;
1686 } else if (memcmp(magic
, LZH_MAGIC
, 2) == 0) {
1691 } else if (force
&& to_stdout
&& !list
) { /* pass input unchanged */
1697 if (imagic0
!= EOF
) {
1698 write_buf (STDOUT_FILENO
, magic
, 1);
1702 if (method
>= 0) return method
;
1705 fprintf (stderr
, "\n%s: %s: not in gzip format\n",
1706 program_name
, ifname
);
1713 for (inbyte
= imagic1
; inbyte
== 0; inbyte
= try_byte ())
1718 WARN ((stderr
, "\n%s: %s: decompression OK, trailing zero bytes ignored\n",
1719 program_name
, ifname
));
1724 WARN((stderr
, "\n%s: %s: decompression OK, trailing garbage ignored\n",
1725 program_name
, ifname
));
1730 /* ========================================================================
1731 * Display the characteristics of the compressed file.
1732 * If the given method is < 0, display the accumulated totals.
1733 * IN assertions: time_stamp, header_bytes and ifile_size are initialized.
1735 local
void do_list(ifd
, method
)
1736 int ifd
; /* input file descriptor */
1737 int method
; /* compression method */
1739 ulg crc
; /* original crc */
1740 static int first_time
= 1;
1741 static char const *const methods
[MAX_METHODS
] = {
1746 "", "", "", "", /* 4 to 7 reserved */
1748 int positive_off_t_width
= INT_STRLEN_BOUND (off_t
) - 1;
1750 if (first_time
&& method
>= 0) {
1753 printf("method crc date time ");
1756 printf("%*.*s %*.*s ratio uncompressed_name\n",
1757 positive_off_t_width
, positive_off_t_width
, "compressed",
1758 positive_off_t_width
, positive_off_t_width
, "uncompressed");
1760 } else if (method
< 0) {
1761 if (total_in
<= 0 || total_out
<= 0) return;
1765 if (verbose
|| !quiet
) {
1766 fprint_off(stdout
, total_in
, positive_off_t_width
);
1768 fprint_off(stdout
, total_out
, positive_off_t_width
);
1771 display_ratio(total_out
-(total_in
-header_bytes
), total_out
, stdout
);
1772 /* header_bytes is not meaningful but used to ensure the same
1773 * ratio if there is a single file.
1775 printf(" (totals)\n");
1778 crc
= (ulg
)~0; /* unknown */
1780 bytes_in
= ifile_size
;
1782 if (method
== DEFLATED
&& !last_member
) {
1783 /* Get the crc and uncompressed size for gzip'ed (not zip'ed) files.
1784 * If the lseek fails, we could use read() to get to the end, but
1785 * --list is used to get quick results.
1786 * Use "gunzip < foo.gz | wc -c" to get the uncompressed size if
1787 * you are not concerned about speed.
1789 bytes_in
= lseek(ifd
, (off_t
)(-8), SEEK_END
);
1790 if (bytes_in
!= -1L) {
1793 if (read(ifd
, (char*)buf
, sizeof(buf
)) != sizeof(buf
)) {
1797 bytes_out
= LG(buf
+4);
1803 static char const month_abbr
[][4]
1804 = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1805 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
1806 struct tm
*tm
= localtime (&time_stamp
.tv_sec
);
1807 printf ("%5s %08lx ", methods
[method
], crc
);
1809 printf ("%s%3d %02d:%02d ", month_abbr
[tm
->tm_mon
],
1810 tm
->tm_mday
, tm
->tm_hour
, tm
->tm_min
);
1812 printf ("??? ?? ??:?? ");
1814 fprint_off(stdout
, bytes_in
, positive_off_t_width
);
1816 fprint_off(stdout
, bytes_out
, positive_off_t_width
);
1818 if (bytes_in
== -1L) {
1820 bytes_in
= bytes_out
= header_bytes
= 0;
1821 } else if (total_in
>= 0) {
1822 total_in
+= bytes_in
;
1824 if (bytes_out
== -1L) {
1826 bytes_in
= bytes_out
= header_bytes
= 0;
1827 } else if (total_out
>= 0) {
1828 total_out
+= bytes_out
;
1830 display_ratio(bytes_out
-(bytes_in
-header_bytes
), bytes_out
, stdout
);
1831 printf(" %s\n", ofname
);
1834 /* ========================================================================
1835 * Shorten the given name by one character, or replace a .tar extension
1836 * with .tgz. Truncate the last part of the name which is longer than
1837 * MIN_PART characters: 1234.678.012.gz -> 123.678.012.gz. If the name
1838 * has only parts shorter than MIN_PART truncate the longest part.
1839 * For decompression, just remove the last character of the name.
1841 * IN assertion: for compression, the suffix of the given name is z_suffix.
1843 local
void shorten_name(name
)
1846 int len
; /* length of name without z_suffix */
1847 char *trunc
= NULL
; /* character to be truncated */
1848 int plen
; /* current part length */
1849 int min_part
= MIN_PART
; /* current minimum part length */
1855 gzip_error ("name too short");
1859 p
= get_suffix(name
);
1861 gzip_error ("can't recover suffix\n");
1865 /* compress 1234567890.tar to 1234567890.tgz */
1866 if (len
> 4 && strequ(p
-4, ".tar")) {
1867 strcpy(p
-4, ".tgz");
1870 /* Try keeping short extensions intact:
1871 * 1234.678.012.gz -> 123.678.012.gz
1874 p
= last_component (name
);
1876 plen
= strcspn(p
, PART_SEP
);
1878 if (plen
> min_part
) trunc
= p
-1;
1881 } while (trunc
== NULL
&& --min_part
!= 0);
1883 if (trunc
!= NULL
) {
1885 trunc
[0] = trunc
[1];
1889 trunc
= strrchr(name
, PART_SEP
[0]);
1891 gzip_error ("internal error in shorten_name");
1892 if (trunc
[1] == '\0') trunc
--; /* force truncation */
1894 strcpy(trunc
, z_suffix
);
1897 /* ========================================================================
1898 * The compressed file already exists, so ask for confirmation.
1899 * Return ERROR if the file must be skipped.
1901 local
int check_ofname()
1903 /* Ask permission to overwrite the existing file */
1906 fprintf (stderr
, "%s: %s already exists;", program_name
, ofname
);
1907 if (foreground
&& (presume_input_tty
|| isatty (STDIN_FILENO
))) {
1908 fprintf(stderr
, " do you wish to overwrite (y or n)? ");
1913 fprintf(stderr
, "\tnot overwritten\n");
1914 if (exit_code
== OK
) exit_code
= WARNING
;
1918 if (xunlink (ofname
)) {
1925 /* Change the owner and group of a file. FD is a file descriptor for
1926 the file and NAME its name. Change it to user UID and to group GID.
1927 If UID or GID is -1, though, do not change the corresponding user
1929 #if ! (HAVE_FCHOWN || HAVE_CHOWN)
1930 /* The types uid_t and gid_t do not exist on mingw, so don't assume them. */
1931 # define do_chown(fd, name, uid, gid) ((void) 0)
1934 do_chown (int fd
, char const *name
, uid_t uid
, gid_t gid
)
1937 ignore_value (fchown (fd
, uid
, gid
));
1939 ignore_value (chown (name
, uid
, gid
));
1944 /* ========================================================================
1945 * Copy modes, times, ownership from input file to output file.
1946 * IN assertion: to_stdout is false.
1948 local
void copy_stat(ifstat
)
1949 struct stat
*ifstat
;
1951 mode_t mode
= ifstat
->st_mode
& S_IRWXUGO
;
1956 struct timespec timespec
[2];
1957 timespec
[0] = get_stat_atime (ifstat
);
1958 timespec
[1] = get_stat_mtime (ifstat
);
1959 restoring
= (decompress
&& 0 <= time_stamp
.tv_nsec
1960 && ! (timespec
[1].tv_sec
== time_stamp
.tv_sec
1961 && timespec
[1].tv_nsec
== time_stamp
.tv_nsec
));
1963 timespec
[1] = time_stamp
;
1965 if (fdutimens (ofd
, ofname
, timespec
) == 0)
1967 if (restoring
&& 1 < verbose
) {
1968 fprintf(stderr
, "%s: timestamp restored\n", ofname
);
1974 WARN ((stderr
, "%s: ", program_name
));
1983 /* Change the group first, then the permissions, then the owner.
1984 That way, the permissions will be correct on systems that allow
1985 users to give away files, without introducing a security hole.
1986 Security depends on permissions not containing the setuid or
1989 do_chown (ofd
, ofname
, -1, ifstat
->st_gid
);
1992 r
= fchmod (ofd
, mode
);
1994 r
= chmod (ofname
, mode
);
1998 WARN ((stderr
, "%s: ", program_name
));
2005 do_chown (ofd
, ofname
, ifstat
->st_uid
, -1);
2010 /* ========================================================================
2011 * Recurse through the given directory.
2013 local
void treat_dir (fd
, dir
)
2018 char nbuf
[MAX_PATH_LEN
];
2023 dirp
= fdopendir (fd
);
2031 entries
= streamsavedir (dirp
, SAVEDIR_SORT_NONE
);
2034 if (closedir (dirp
) != 0)
2039 for (entry
= entries
; *entry
; entry
+= entrylen
+ 1) {
2040 size_t len
= strlen (dir
);
2041 entrylen
= strlen (entry
);
2042 if (strequ (entry
, ".") || strequ (entry
, ".."))
2044 if (len
+ entrylen
< MAX_PATH_LEN
- 2) {
2046 if (*last_component (nbuf
) && !ISSLASH (nbuf
[len
- 1]))
2048 strcpy (nbuf
+ len
, entry
);
2051 fprintf(stderr
,"%s: %s/%s: pathname too long\n",
2052 program_name
, dir
, entry
);
2058 #endif /* ! NO_DIR */
2060 /* Make sure signals get handled properly. */
2063 install_signal_handlers ()
2065 int nsigs
= sizeof handled_sig
/ sizeof handled_sig
[0];
2067 struct sigaction act
;
2069 sigemptyset (&caught_signals
);
2070 for (i
= 0; i
< nsigs
; i
++)
2072 sigaction (handled_sig
[i
], NULL
, &act
);
2073 if (act
.sa_handler
!= SIG_IGN
)
2074 sigaddset (&caught_signals
, handled_sig
[i
]);
2077 act
.sa_handler
= abort_gzip_signal
;
2078 act
.sa_mask
= caught_signals
;
2081 for (i
= 0; i
< nsigs
; i
++)
2082 if (sigismember (&caught_signals
, handled_sig
[i
]))
2086 sigaction (handled_sig
[i
], &act
, NULL
);
2090 /* ========================================================================
2091 * Free all dynamically allocated variables and exit with the given code.
2093 local
void do_exit(exitcode
)
2096 static int in_exit
= 0;
2098 if (in_exit
) exit(exitcode
);
2118 if (fclose (stdout
) != 0)
2123 /* ========================================================================
2124 * Close and unlink the output file.
2127 remove_output_file (bool signals_already_blocked
)
2132 if (!signals_already_blocked
)
2133 sigprocmask (SIG_BLOCK
, &caught_signals
, &oldset
);
2134 fd
= remove_ofname_fd
;
2137 char fname
[MAX_PATH_LEN
];
2138 remove_ofname_fd
= -1;
2140 volatile_strcpy (fname
, remove_ofname
);
2143 if (!signals_already_blocked
)
2144 sigprocmask (SIG_SETMASK
, &oldset
, NULL
);
2147 /* ========================================================================
2153 remove_output_file (false);
2157 /* ========================================================================
2161 abort_gzip_signal (int sig
)
2163 remove_output_file (true);
2164 if (sig
== exiting_signal
)
2166 signal (sig
, SIG_DFL
);