From 47439c3033f3ada7993c0c8b3bd11f104453fced Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sat, 28 Sep 2002 07:38:43 +0000 Subject: [PATCH] gzip 1.3.5 --- gzip.c | 478 +++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 294 insertions(+), 184 deletions(-) diff --git a/gzip.c b/gzip.c index f73c2f4..9a52570 100644 --- a/gzip.c +++ b/gzip.c @@ -1,4 +1,5 @@ /* gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface + * Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. * Copyright (C) 1992-1993 Jean-loup Gailly * The unzip code was written and put in the public domain by Mark Adler. * Portions of the lzw code are derived from the public domain 'compress' @@ -10,20 +11,12 @@ */ static char *license_msg[] = { -" Copyright (C) 1992-1993 Jean-loup Gailly", -" This program is free software; you can redistribute it and/or modify", -" it under the terms of the GNU General Public License as published by", -" the Free Software Foundation; either version 2, or (at your option)", -" any later version.", -"", -" This program is distributed in the hope that it will be useful,", -" but WITHOUT ANY WARRANTY; without even the implied warranty of", -" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", -" GNU General Public License for more details.", -"", -" You should have received a copy of the GNU General Public License", -" along with this program; if not, write to the Free Software", -" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.", +"Copyright 2002 Free Software Foundation", +"Copyright 1992-1993 Jean-loup Gailly", +"This program comes with ABSOLUTELY NO WARRANTY.", +"You may redistribute copies of this program", +"under the terms of the GNU General Public License.", +"For more information about these matters, see the file named COPYING.", 0}; /* Compress files with zip algorithm and 'compress' interface. @@ -48,6 +41,7 @@ static char *license_msg[] = { static char rcsid[] = "$Id$"; #endif +#include #include #include #include @@ -62,57 +56,69 @@ static char rcsid[] = "$Id$"; /* configuration */ -#ifdef NO_TIME_H -# include -#else +#ifdef HAVE_TIME_H # include +#else +# include #endif -#ifndef NO_FCNTL_H +#ifdef HAVE_FCNTL_H # include #endif +#ifdef HAVE_LIMITS_H +# include +#endif + #ifdef HAVE_UNISTD_H # include #endif -#if defined(STDC_HEADERS) || !defined(NO_STDLIB_H) +#if defined STDC_HEADERS || defined HAVE_STDLIB_H # include #else extern int errno; #endif -#if defined(DIRENT) +#ifdef HAVE_DIRENT_H # include - typedef struct dirent dir_type; -# define NLENGTH(dirent) ((int)strlen((dirent)->d_name)) +# define NAMLEN(direct) strlen((direct)->d_name) # define DIR_OPT "DIRENT" #else -# define NLENGTH(dirent) ((dirent)->d_namlen) -# ifdef SYSDIR +# define dirent direct +# define NAMLEN(direct) ((direct)->d_namlen) +# ifdef HAVE_SYS_NDIR_H +# include +# define DIR_OPT "SYS_NDIR" +# endif +# ifdef HAVE_SYS_DIR_H # include - typedef struct direct dir_type; -# define DIR_OPT "SYSDIR" -# else -# ifdef SYSNDIR -# include - typedef struct direct dir_type; -# define DIR_OPT "SYSNDIR" -# else -# ifdef NDIR -# include - typedef struct direct dir_type; -# define DIR_OPT "NDIR" -# else -# define NO_DIR -# define DIR_OPT "NO_DIR" -# endif -# endif +# define DIR_OPT "SYS_DIR" +# endif +# ifdef HAVE_NDIR_H +# include +# define DIR_OPT "NDIR" # endif +# ifndef DIR_OPT +# define DIR_OPT "NO_DIR" +# endif +#endif +#ifndef NO_DIR +# define NO_DIR 0 #endif -#ifndef NO_UTIME -# ifndef NO_UTIME_H +#ifdef CLOSEDIR_VOID +# define CLOSEDIR(d) (closedir(d), 0) +#else +# define CLOSEDIR(d) closedir(d) +#endif + +#if !defined(HAVE_LSTAT) && !defined(lstat) +# define lstat(name, buf) stat(name, buf) +#endif + +#ifdef HAVE_UTIME +# ifdef HAVE_UTIME_H # include # define TIME_OPT "UTIME" # else @@ -124,7 +130,7 @@ static char rcsid[] = "$Id$"; time_t actime; time_t modtime; }; -# define TIME_OPT "" +# define TIME_OPT "STRUCT_UTIMBUF" # endif # endif #else @@ -171,11 +177,22 @@ typedef RETSIGTYPE (*sig_type) OF((int)); # define SEEK_END 2 #endif -#ifdef NO_OFF_T - typedef long off_t; +#ifndef CHAR_BIT +# define CHAR_BIT 8 +#endif + +#ifdef off_t off_t lseek OF((int fd, off_t offset, int whence)); #endif +#ifndef OFF_T_MIN +#define OFF_T_MIN (~ (off_t) 0 << (sizeof (off_t) * CHAR_BIT - 1)) +#endif + +#ifndef OFF_T_MAX +#define OFF_T_MAX (~ (off_t) 0 - OFF_T_MIN) +#endif + /* Separator for file name parts (see shorten_name()) */ #ifdef NO_MULTIPLE_DOTS # define PART_SEP "-" @@ -219,17 +236,17 @@ int exit_code = OK; /* program exit code */ int save_orig_name; /* set if original name must be saved */ int last_member; /* set for .zip and .Z files */ int part_nb; /* number of parts in .gz file */ -long time_stamp; /* original time stamp (modification time) */ -long ifile_size; /* input file size, -1 for devices (debug only) */ +time_t time_stamp; /* original time stamp (modification time) */ +off_t ifile_size; /* input file size, -1 for devices (debug only) */ char *env; /* contents of GZIP env variable */ char **args = NULL; /* argv pointer if GZIP env variable defined */ -char z_suffix[MAX_SUFFIX+1]; /* default suffix (can be set with --suffix) */ -int z_len; /* strlen(z_suffix) */ +char *z_suffix; /* default suffix (can be set with --suffix) */ +size_t z_len; /* strlen(z_suffix) */ -long bytes_in; /* number of input bytes */ -long bytes_out; /* number of output bytes */ -long total_in = 0; /* input bytes for all files */ -long total_out = 0; /* output bytes for all files */ +off_t bytes_in; /* number of input bytes */ +off_t bytes_out; /* number of output bytes */ +off_t total_in; /* input bytes for all files */ +off_t total_out; /* output bytes for all files */ char ifname[MAX_PATH_LEN]; /* input file name */ char ofname[MAX_PATH_LEN]; /* output file name */ int remove_ofname = 0; /* remove output file on error */ @@ -277,6 +294,7 @@ local void usage OF((void)); local void help OF((void)); local void license OF((void)); local void version OF((void)); +local int input_eof OF((void)); local void treat_stdin OF((void)); local void treat_file OF((char *iname)); local int create_outfile OF((void)); @@ -295,10 +313,10 @@ local void do_exit OF((int exitcode)); int main OF((int argc, char **argv)); int (*work) OF((int infile, int outfile)) = zip; /* function to call */ -#ifndef NO_DIR +#if ! NO_DIR local void treat_dir OF((char *dir)); #endif -#ifndef NO_UTIME +#ifdef HAVE_UTIME local void reset_times OF((char *name, struct stat *statb)); #endif @@ -307,19 +325,9 @@ local void reset_times OF((char *name, struct stat *statb)); /* ======================================================================== */ local void usage() { - fprintf(stderr, "usage: %s [-%scdfhlLnN%stvV19] [-S suffix] [file ...]\n", + printf ("usage: %s [-%scdfhlLnN%stvV19] [-S suffix] [file ...]\n", progname, -#if O_BINARY - "a", -#else - "", -#endif -#ifdef NO_DIR - "" -#else - "r" -#endif - ); + O_BINARY ? "a" : "", NO_DIR ? "" : "r"); } /* ======================================================================== */ @@ -344,7 +352,7 @@ local void help() " -n --no-name do not save or restore the original name and time stamp", " -N --name save or restore the original name and time stamp", " -q --quiet suppress all warnings", -#ifndef NO_DIR +#if ! NO_DIR " -r --recursive operate recursively on directories", #endif " -S .suf --suffix .suf use suffix .suf on compressed files", @@ -358,12 +366,13 @@ local void help() " -b --bits maxbits max number of bits per code (implies -Z)", #endif " file... files to (de)compress. If none given, use standard input.", + "Report bugs to .", 0}; char **p = help_msg; - fprintf(stderr,"%s %s (%s)\n", progname, VERSION, REVDATE); + printf ("%s %s\n(%s)\n", progname, VERSION, REVDATE); usage(); - while (*p) fprintf(stderr, "%s\n", *p++); + while (*p) printf ("%s\n", *p++); } /* ======================================================================== */ @@ -371,53 +380,63 @@ local void license() { char **p = license_msg; - fprintf(stderr,"%s %s (%s)\n", progname, VERSION, REVDATE); - while (*p) fprintf(stderr, "%s\n", *p++); + printf ("%s %s\n(%s)\n", progname, VERSION, REVDATE); + while (*p) printf ("%s\n", *p++); } /* ======================================================================== */ local void version() { - fprintf(stderr,"%s %s (%s)\n", progname, VERSION, REVDATE); - - fprintf(stderr, "Compilation options:\n%s %s ", DIR_OPT, TIME_OPT); + license (); + printf ("Compilation options:\n%s %s ", DIR_OPT, TIME_OPT); #ifdef STDC_HEADERS - fprintf(stderr, "STDC_HEADERS "); + printf ("STDC_HEADERS "); #endif #ifdef HAVE_UNISTD_H - fprintf(stderr, "HAVE_UNISTD_H "); + printf ("HAVE_UNISTD_H "); #endif -#ifdef NO_MEMORY_H - fprintf(stderr, "NO_MEMORY_H "); +#ifdef HAVE_MEMORY_H + printf ("HAVE_MEMORY_H "); #endif -#ifdef NO_STRING_H - fprintf(stderr, "NO_STRING_H "); +#ifdef HAVE_STRING_H + printf ("HAVE_STRING_H "); #endif -#ifdef NO_SYMLINK - fprintf(stderr, "NO_SYMLINK "); +#ifdef HAVE_LSTAT + printf ("HAVE_LSTAT "); #endif #ifdef NO_MULTIPLE_DOTS - fprintf(stderr, "NO_MULTIPLE_DOTS "); + printf ("NO_MULTIPLE_DOTS "); #endif -#ifdef NO_CHOWN - fprintf(stderr, "NO_CHOWN "); +#ifdef HAVE_CHOWN + printf ("HAVE_CHOWN "); #endif #ifdef PROTO - fprintf(stderr, "PROTO "); + printf ("PROTO "); #endif #ifdef ASMV - fprintf(stderr, "ASMV "); + printf ("ASMV "); #endif #ifdef DEBUG - fprintf(stderr, "DEBUG "); + printf ("DEBUG "); #endif #ifdef DYN_ALLOC - fprintf(stderr, "DYN_ALLOC "); + printf ("DYN_ALLOC "); #endif #ifdef MAXSEG_64K - fprintf(stderr, "MAXSEG_64K"); + printf ("MAXSEG_64K"); #endif - fprintf(stderr, "\n"); + printf ("\n"); + printf ("Written by Jean-loup Gailly.\n"); +} + +local void progerror (string) + char *string; +{ + int e = errno; + fprintf(stderr, "%s: ", progname); + errno = e; + perror(string); + exit_code = ERROR; } /* ======================================================================== */ @@ -431,7 +450,7 @@ int main (argc, argv) EXPAND(argc, argv); /* wild card expansion if necessary */ - progname = basename(argv[0]); + progname = base_name (argv[0]); proglen = strlen(progname); /* Suppress .exe for MSDOS, OS/2 and VMS: */ @@ -475,16 +494,24 @@ int main (argc, argv) } #endif - strncpy(z_suffix, Z_SUFFIX, sizeof(z_suffix)-1); + z_suffix = Z_SUFFIX; z_len = strlen(z_suffix); while ((optc = getopt_long (argc, argv, "ab:cdfhH?lLmMnNqrS:tvVZ123456789", - longopts, (int *)0)) != EOF) { + longopts, (int *)0)) != -1) { switch (optc) { case 'a': ascii = 1; break; case 'b': maxbits = atoi(optarg); + for (; *optarg; optarg++) + if (! ('0' <= *optarg && *optarg <= '9')) + { + fprintf (stderr, "%s: -b operand is not an integer\n", + progname); + usage (); + do_exit (ERROR); + } break; case 'c': to_stdout = 1; break; @@ -509,7 +536,7 @@ int main (argc, argv) case 'q': quiet = 1; verbose = 0; break; case 'r': -#ifdef NO_DIR +#if NO_DIR fprintf(stderr, "%s: -r not supported on this system\n", progname); usage(); do_exit(ERROR); break; @@ -521,7 +548,7 @@ int main (argc, argv) if (*optarg == '.') optarg++; #endif z_len = strlen(optarg); - strcpy(z_suffix, optarg); + z_suffix = optarg; break; case 't': test = decompress = to_stdout = 1; @@ -550,6 +577,12 @@ int main (argc, argv) } } /* loop on all arguments */ +#ifdef SIGPIPE + /* Ignore "Broken Pipe" message with --quiet */ + if (quiet && signal (SIGPIPE, SIG_IGN) != SIG_IGN) + signal (SIGPIPE, (sig_type) abort_gzip); +#endif + /* By default, save name and timestamp on compression but do not * restore them on decompression. */ @@ -567,7 +600,7 @@ int main (argc, argv) #endif if ((z_len == 0 && !decompress) || z_len > MAX_SUFFIX) { fprintf(stderr, "%s: incorrect suffix '%s'\n", - progname, optarg); + progname, z_suffix); do_exit(ERROR); } if (do_lzw && !decompress) work = lzw; @@ -602,6 +635,25 @@ int main (argc, argv) return exit_code; /* just to avoid lint warning */ } +/* Return nonzero when at end of file on input. */ +local int +input_eof () +{ + if (!decompress || last_member) + return 1; + + if (inptr == insize) + { + if (insize != INBUFSIZ || fill_inbuf (1) == EOF) + return 1; + + /* Unget the char that fill_inbuf got. */ + inptr = 0; + } + + return 0; +} + /* ======================================================================== * Compress or decompress stdin */ @@ -644,7 +696,8 @@ local void treat_stdin() #ifndef NO_STDIN_FSTAT if (list || !no_time) { if (fstat(fileno(stdin), &istat) != 0) { - error("fstat(stdin)"); + progerror("standard input"); + do_exit(ERROR); } # ifdef NO_PIPE_TIMESTAMP if (S_ISREG(istat.st_mode)) @@ -674,8 +727,8 @@ local void treat_stdin() for (;;) { if ((*work)(fileno(stdin), fileno(stdout)) != OK) return; - if (!decompress || last_member || inptr == insize) break; - /* end of file */ + if (input_eof ()) + break; method = get_method(ifd); if (method < 0) return; /* error message already emitted */ @@ -717,7 +770,7 @@ local void treat_file(iname) /* If the input name is that of a directory, recurse or ignore: */ if (S_ISDIR(istat.st_mode)) { -#ifndef NO_DIR +#if ! NO_DIR if (recursive) { struct stat st; st = istat; @@ -738,9 +791,9 @@ local void treat_file(iname) return; } if (istat.st_nlink > 1 && !to_stdout && !force) { - WARN((stderr, "%s: %s has %d other link%c -- unchanged\n", - progname, ifname, - (int)istat.st_nlink - 1, istat.st_nlink > 2 ? 's' : ' ')); + WARN((stderr, "%s: %s has %lu other link%c -- unchanged\n", + progname, ifname, (unsigned long) istat.st_nlink - 1, + istat.st_nlink > 2 ? 's' : ' ')); return; } @@ -764,9 +817,7 @@ local void treat_file(iname) ifd = OPEN(ifname, ascii && !decompress ? O_RDONLY : O_RDONLY | O_BINARY, RW_USER); if (ifd == -1) { - fprintf(stderr, "%s: ", progname); - perror(ifname); - exit_code = ERROR; + progerror(ifname); return; } clear_bufs(); /* clear input and output buffers */ @@ -804,8 +855,7 @@ local void treat_file(iname) if (!save_orig_name) save_orig_name = !no_name; if (verbose) { - fprintf(stderr, "%s:\t%s", ifname, (int)strlen(ifname) >= 15 ? - "" : ((int)strlen(ifname) >= 7 ? "\t" : "\t\t")); + fprintf(stderr, "%s:\t", ifname); } /* Actually do the compression/decompression. Loop over zipped members. @@ -815,8 +865,9 @@ local void treat_file(iname) method = -1; /* force cleanup */ break; } - if (!decompress || last_member || inptr == insize) break; - /* end of file */ + + if (input_eof ()) + break; method = get_method(ifd); if (method < 0) break; /* error message already emitted */ @@ -828,7 +879,7 @@ local void treat_file(iname) write_error(); } if (method == -1) { - if (!to_stdout) unlink (ofname); + if (!to_stdout) xunlink (ofname); return; } /* Display statistics */ @@ -878,9 +929,8 @@ local int create_outfile() remove_ofname = 1; ofd = OPEN(ofname, flags, RW_USER); if (ofd == -1) { - perror(ofname); + progerror(ofname); close(ifd); - exit_code = ERROR; return ERROR; } @@ -890,11 +940,9 @@ local int create_outfile() #else if (fstat(ofd, &ostat) != 0) { #endif - fprintf(stderr, "%s: ", progname); - perror(ofname); + progerror(ofname); close(ifd); close(ofd); - unlink(ofname); - exit_code = ERROR; + xunlink (ofname); return ERROR; } if (!name_too_long(ofname, &ostat)) return OK; @@ -906,7 +954,7 @@ local int create_outfile() return OK; } close(ofd); - unlink(ofname); + xunlink (ofname); #ifdef NO_MULTIPLE_DOTS /* Should never happen, see check_ofname() */ fprintf(stderr, "%s: %s: name too long\n", progname, ofname); @@ -925,11 +973,9 @@ local int do_stat(name, sbuf) struct stat *sbuf; { errno = 0; -#if (defined(S_IFLNK) || defined (S_ISLNK)) && !defined(NO_SYMLINK) if (!to_stdout && !force) { return lstat(name, sbuf); } -#endif return stat(name, sbuf); } @@ -951,13 +997,14 @@ local char *get_suffix(name) int nlen, slen; char suffix[MAX_SUFFIX+3]; /* last chars of name, forced to lower case */ static char *known_suffixes[] = - {z_suffix, ".gz", ".z", ".taz", ".tgz", "-gz", "-z", "_z", + {NULL, ".gz", ".z", ".taz", ".tgz", "-gz", "-z", "_z", #ifdef MAX_EXT_CHARS "z", #endif NULL}; char **suf = known_suffixes; + *suf = z_suffix; if (strequ(z_suffix, "z")) suf++; /* check long suffixes first */ #ifdef SUFFIX_SEP @@ -999,21 +1046,26 @@ local int get_istat(iname, sbuf) struct stat *sbuf; { int ilen; /* strlen(ifname) */ - static char *suffixes[] = {z_suffix, ".gz", ".z", "-z", ".Z", NULL}; + int z_suffix_errno = 0; + static char *suffixes[] = {NULL, ".gz", ".z", "-z", ".Z", NULL}; char **suf = suffixes; char *s; #ifdef NO_MULTIPLE_DOTS char *dot; /* pointer to ifname extension, or NULL */ #endif + *suf = z_suffix; + + if (sizeof ifname - 1 <= strlen (iname)) + goto name_too_long; + strcpy(ifname, iname); /* If input file exists, return OK. */ if (do_stat(ifname, sbuf) == 0) return OK; if (!decompress || errno != ENOENT) { - perror(ifname); - exit_code = ERROR; + progerror(ifname); return ERROR; } /* file.ext doesn't exist, try adding a suffix (after removing any @@ -1021,8 +1073,7 @@ local int get_istat(iname, sbuf) */ s = get_suffix(ifname); if (s != NULL) { - perror(ifname); /* ifname already has z suffix and does not exist */ - exit_code = ERROR; + progerror(ifname); /* ifname already has z suffix and does not exist */ return ERROR; } #ifdef NO_MULTIPLE_DOTS @@ -1037,30 +1088,40 @@ local int get_istat(iname, sbuf) /* Search for all suffixes */ do { - s = *suf; + char *s0 = s = *suf; + strcpy (ifname, iname); #ifdef NO_MULTIPLE_DOTS if (*s == '.') s++; + if (*dot == '\0') strcpy (dot, "."); #endif #ifdef MAX_EXT_CHARS - strcpy(ifname, iname); - /* Needed if the suffixes are not sorted by increasing length */ - - if (*dot == '\0') strcpy(dot, "."); - dot[MAX_EXT_CHARS+1-strlen(s)] = '\0'; + if (MAX_EXT_CHARS < strlen (s) + strlen (dot + 1)) + dot[MAX_EXT_CHARS + 1 - strlen (s)] = '\0'; #endif + if (sizeof ifname <= ilen + strlen (s)) + goto name_too_long; strcat(ifname, s); if (do_stat(ifname, sbuf) == 0) return OK; - ifname[ilen] = '\0'; + if (strequ (s0, z_suffix)) + z_suffix_errno = errno; } while (*++suf != NULL); /* No suffix found, complain using z_suffix: */ -#ifdef MAX_EXT_CHARS strcpy(ifname, iname); +#ifdef NO_MULTIPLE_DOTS if (*dot == '\0') strcpy(dot, "."); - dot[MAX_EXT_CHARS+1-z_len] = '\0'; +#endif +#ifdef MAX_EXT_CHARS + if (MAX_EXT_CHARS < z_len + strlen (dot + 1)) + dot[MAX_EXT_CHARS + 1 - z_len] = '\0'; #endif strcat(ifname, z_suffix); - perror(ifname); + errno = z_suffix_errno; + progerror(ifname); + return ERROR; + + name_too_long: + fprintf (stderr, "%s: %s: file name too long\n", progname, iname); exit_code = ERROR; return ERROR; } @@ -1079,7 +1140,7 @@ local int make_ofname() if (decompress) { if (suff == NULL) { - /* Whith -t or -l, try all files (even without .gz suffix) + /* With -t or -l, try all files (even without .gz suffix) * except with -r (behave as with just -dr). */ if (!recursive && (list || test)) return OK; @@ -1103,10 +1164,9 @@ local int make_ofname() } else if (suff != NULL) { /* Avoid annoying messages with -r (see treat_dir()) */ if (verbose || (!recursive && !quiet)) { - fprintf(stderr, "%s: %s already has %s suffix -- unchanged\n", - progname, ifname, suff); + WARN((stderr, "%s: %s already has %s suffix -- unchanged\n", + progname, ifname, suff)); } - if (exit_code == OK) exit_code = WARNING; return WARNING; } else { save_orig_name = 0; @@ -1114,9 +1174,13 @@ local int make_ofname() #ifdef NO_MULTIPLE_DOTS suff = strrchr(ofname, '.'); if (suff == NULL) { + if (sizeof ofname <= strlen (ofname) + 1) + goto name_too_long; strcat(ofname, "."); # ifdef MAX_EXT_CHARS if (strequ(z_suffix, "z")) { + if (sizeof ofname <= strlen (ofname) + 2) + goto name_too_long; strcat(ofname, "gz"); /* enough room */ return OK; } @@ -1130,10 +1194,16 @@ local int make_ofname() # endif } #endif /* NO_MULTIPLE_DOTS */ + if (sizeof ofname <= strlen (ofname) + z_len) + goto name_too_long; strcat(ofname, z_suffix); } /* decompress ? */ return OK; + + name_too_long: + WARN ((stderr, "%s: %s: file name too long\n", progname, ifname)); + return WARNING; } @@ -1153,6 +1223,7 @@ local int get_method(in) { uch flags; /* compression flags */ char magic[2]; /* magic header */ + int imagic1; /* like magic[1], but can represent EOF */ ulg stamp; /* time stamp */ /* If --force and --stdout, zcat == cat, so do not complain about @@ -1160,11 +1231,13 @@ local int get_method(in) */ if (force && to_stdout) { magic[0] = (char)try_byte(); - magic[1] = (char)try_byte(); - /* If try_byte returned EOF, magic[1] == 0xff */ + imagic1 = try_byte (); + magic[1] = (char) imagic1; + /* If try_byte returned EOF, magic[1] == (char) EOF. */ } else { magic[0] = (char)get_byte(); magic[1] = (char)get_byte(); + imagic1 = 0; /* avoid lint warning */ } method = -1; /* unknown yet */ part_nb++; /* number of parts in gzip file */ @@ -1178,7 +1251,7 @@ local int get_method(in) method = (int)get_byte(); if (method != DEFLATED) { fprintf(stderr, - "%s: %s: unknown method %d -- get newer version of gzip\n", + "%s: %s: unknown method %d -- not supported\n", progname, ifname, method); exit_code = ERROR; return -1; @@ -1188,21 +1261,21 @@ local int get_method(in) if ((flags & ENCRYPTED) != 0) { fprintf(stderr, - "%s: %s is encrypted -- get newer version of gzip\n", + "%s: %s is encrypted -- not supported\n", progname, ifname); exit_code = ERROR; return -1; } if ((flags & CONTINUATION) != 0) { fprintf(stderr, - "%s: %s is a a multi-part gzip file -- get newer version of gzip\n", + "%s: %s is a a multi-part gzip file -- not supported\n", progname, ifname); exit_code = ERROR; if (force <= 1) return -1; } if ((flags & RESERVED) != 0) { fprintf(stderr, - "%s: %s has flags 0x%x -- get newer version of gzip\n", + "%s: %s has flags 0x%x -- not supported\n", progname, ifname, flags); exit_code = ERROR; if (force <= 1) return -1; @@ -1242,7 +1315,7 @@ local int get_method(in) do {c=get_byte();} while (c != 0); } else { /* Copy the base name. Keep a directory prefix intact. */ - char *p = basename(ofname); + char *p = base_name (ofname); char *base = p; for (;;) { *p = (char)get_char(); @@ -1305,6 +1378,20 @@ local int get_method(in) exit_code = ERROR; return -1; } else { + if (magic[0] == 0) + { + int inbyte; + for (inbyte = imagic1; inbyte == 0; inbyte = try_byte ()) + continue; + if (inbyte == EOF) + { + if (verbose) + WARN ((stderr, "\n%s: %s: decompression OK, trailing zero bytes ignored\n", + progname, ifname)); + return -3; + } + } + WARN((stderr, "\n%s: %s: decompression OK, trailing garbage ignored\n", progname, ifname)); return -2; @@ -1330,6 +1417,12 @@ local void do_list(ifd, method) "", "", "", "", /* 4 to 7 reserved */ "defla"}; /* 8 */ char *date; + int positive_off_t_width = 1; + off_t o; + + for (o = OFF_T_MAX; 9 < o; o /= 10) { + positive_off_t_width++; + } if (first_time && method >= 0) { first_time = 0; @@ -1337,15 +1430,20 @@ local void do_list(ifd, method) printf("method crc date time "); } if (!quiet) { - printf("compressed uncompr. ratio uncompressed_name\n"); + printf("%*.*s %*.*s ratio uncompressed_name\n", + positive_off_t_width, positive_off_t_width, "compressed", + positive_off_t_width, positive_off_t_width, "uncompressed"); } } else if (method < 0) { if (total_in <= 0 || total_out <= 0) return; if (verbose) { - printf(" %9lu %9lu ", - total_in, total_out); - } else if (!quiet) { - printf("%9ld %9ld ", total_in, total_out); + printf(" "); + } + if (verbose || !quiet) { + fprint_off(stdout, total_in, positive_off_t_width); + printf(" "); + fprint_off(stdout, total_out, positive_off_t_width); + printf(" "); } display_ratio(total_out-(total_in-header_bytes), total_out, stdout); /* header_bytes is not meaningful but used to ensure the same @@ -1366,7 +1464,7 @@ local void do_list(ifd, method) * Use "gunzip < foo.gz | wc -c" to get the uncompressed size if * you are not concerned about speed. */ - bytes_in = (long)lseek(ifd, (off_t)(-8), SEEK_END); + bytes_in = lseek(ifd, (off_t)(-8), SEEK_END); if (bytes_in != -1L) { uch buf[8]; bytes_in += 8L; @@ -1383,7 +1481,10 @@ local void do_list(ifd, method) if (verbose) { printf("%5s %08lx %11s ", methods[method], crc, date); } - printf("%9ld %9ld ", bytes_in, bytes_out); + fprint_off(stdout, bytes_in, positive_off_t_width); + printf(" "); + fprint_off(stdout, bytes_out, positive_off_t_width); + printf(" "); if (bytes_in == -1L) { total_in = -1L; bytes_in = bytes_out = header_bytes = 0; @@ -1437,7 +1538,7 @@ local int name_too_long(name, statb) tstat = *statb; /* Just in case OS does not fill all fields */ name[s-1] = '\0'; - res = stat(name, &tstat) == 0 && same_file(statb, &tstat); + res = lstat(name, &tstat) == 0 && same_file(statb, &tstat); name[s-1] = c; Trace((stderr, " too_long(%s) => %d\n", name, res)); return res; @@ -1527,12 +1628,12 @@ local int check_ofname() * instead of silently truncating filenames). */ errno = 0; - while (stat(ofname, &ostat) != 0) { + while (lstat(ofname, &ostat) != 0) { if (errno != ENAMETOOLONG) return 0; /* ofname does not exist */ shorten_name(ofname); } #else - if (stat(ofname, &ostat) != 0) return 0; + if (lstat(ofname, &ostat) != 0) return 0; #endif /* Check for name truncation on existing file. Do this even on systems * defining ENAMETOOLONG, because on most systems the strict Posix @@ -1540,7 +1641,7 @@ local int check_ofname() */ if (!decompress && name_too_long(ofname, &ostat)) { shorten_name(ofname); - if (stat(ofname, &ostat) != 0) return 0; + if (lstat(ofname, &ostat) != 0) return 0; } /* Check that the input and output files are different (could be @@ -1559,25 +1660,21 @@ local int check_ofname() } /* Ask permission to overwrite the existing file */ if (!force) { - char response[80]; - strcpy(response,"n"); + int ok = 0; fprintf(stderr, "%s: %s already exists;", progname, ofname); if (foreground && isatty(fileno(stdin))) { fprintf(stderr, " do you wish to overwrite (y or n)? "); fflush(stderr); - (void)fgets(response, sizeof(response)-1, stdin); + ok = yesno(); } - if (tolow(*response) != 'y') { + if (!ok) { fprintf(stderr, "\tnot overwritten\n"); if (exit_code == OK) exit_code = WARNING; return ERROR; } } - (void) chmod(ofname, 0777); - if (unlink(ofname)) { - fprintf(stderr, "%s: ", progname); - perror(ofname); - exit_code = ERROR; + if (xunlink (ofname)) { + progerror(ofname); return ERROR; } return OK; @@ -1600,8 +1697,12 @@ local void reset_times (name, statb) /* Some systems (at least OS/2) do not support utime on directories */ if (utime(name, &timep) && !S_ISDIR(statb->st_mode)) { + int e = errno; WARN((stderr, "%s: ", progname)); - if (!quiet) perror(ofname); + if (!quiet) { + errno = e; + perror(ofname); + } } } #endif @@ -1625,22 +1726,29 @@ local void copy_stat(ifstat) #endif /* Copy the protection modes */ if (chmod(ofname, ifstat->st_mode & 07777)) { + int e = errno; WARN((stderr, "%s: ", progname)); - if (!quiet) perror(ofname); + if (!quiet) { + errno = e; + perror(ofname); + } } #ifndef NO_CHOWN chown(ofname, ifstat->st_uid, ifstat->st_gid); /* Copy ownership */ #endif remove_ofname = 0; /* It's now safe to remove the input file: */ - (void) chmod(ifname, 0777); - if (unlink(ifname)) { + if (xunlink (ifname)) { + int e = errno; WARN((stderr, "%s: ", progname)); - if (!quiet) perror(ifname); + if (!quiet) { + errno = e; + perror(ifname); + } } } -#ifndef NO_DIR +#if ! NO_DIR /* ======================================================================== * Recurse through the given directory. This code is taken from ncompress. @@ -1648,7 +1756,7 @@ local void copy_stat(ifstat) local void treat_dir(dir) char *dir; { - dir_type *dp; + struct dirent *dp; DIR *dirp; char nbuf[MAX_PATH_LEN]; int len; @@ -1656,8 +1764,7 @@ local void treat_dir(dir) dirp = opendir(dir); if (dirp == NULL) { - fprintf(stderr, "%s: %s unreadable\n", progname, dir); - exit_code = ERROR; + progerror(dir); return ; } /* @@ -1676,13 +1783,13 @@ local void treat_dir(dir) ** (An other alternative might be two passes to avoid depth-first.) */ - while ((dp = readdir(dirp)) != NULL) { + while ((errno = 0, dp = readdir(dirp)) != NULL) { if (strequ(dp->d_name,".") || strequ(dp->d_name,"..")) { continue; } len = strlen(dir); - if (len + NLENGTH(dp) + 1 < MAX_PATH_LEN - 1) { + if (len + NAMLEN(dp) + 1 < MAX_PATH_LEN - 1) { strcpy(nbuf,dir); if (len != 0 /* dir = "" means current dir on Amiga */ #ifdef PATH_SEP2 @@ -1702,9 +1809,12 @@ local void treat_dir(dir) exit_code = ERROR; } } - closedir(dirp); + if (errno != 0) + progerror(dir); + if (CLOSEDIR(dirp) != 0) + progerror(dir); } -#endif /* ? NO_DIR */ +#endif /* ! NO_DIR */ /* ======================================================================== * Free all dynamically allocated variables and exit with the given code. @@ -1738,7 +1848,7 @@ RETSIGTYPE abort_gzip() { if (remove_ofname) { close(ofd); - unlink (ofname); + xunlink (ofname); } do_exit(ERROR); } -- 2.47.2