(root)/
gzip-1.13/
gzip.c
       1  /* gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
       2  
       3     Copyright (C) 1999, 2001-2002, 2006-2007, 2009-2023 Free Software
       4     Foundation, Inc.
       5     Copyright (C) 1992-1993 Jean-loup Gailly
       6  
       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.
      11  
      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.
      16  
      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.  */
      20  
      21  /*
      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.
      26   *
      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.
      29   */
      30  
      31  static char const *const license_msg[] = {
      32  "Copyright (C) 2023 Free Software Foundation, Inc.",
      33  "Copyright (C) 1993 Jean-loup Gailly.",
      34  "This is free software.  You may redistribute copies of it under the terms of",
      35  "the GNU General Public License <https://www.gnu.org/licenses/gpl.html>.",
      36  "There is NO WARRANTY, to the extent permitted by law.",
      37  0};
      38  
      39  /* Compress files with zip algorithm and 'compress' interface.
      40   * See help() function below for all options.
      41   * Outputs:
      42   *        file.gz:   compressed file with same mode, owner, and utimes
      43   *     or stdout with -c option or if stdin used as input.
      44   * If the output file name had to be truncated, the original name is kept
      45   * in the compressed file.
      46   * On MSDOS, file.tmp -> file.tmz.
      47   *
      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.
      53   *
      54   * For the meaning of all compilation flags, see comments in Makefile.in.
      55   */
      56  
      57  #include <config.h>
      58  #include <ctype.h>
      59  #include <sys/types.h>
      60  #include <signal.h>
      61  #include <stddef.h>
      62  #include <sys/stat.h>
      63  #include <errno.h>
      64  
      65  #include "tailor.h"
      66  #include "gzip.h"
      67  #include "intprops.h"
      68  #include "lzw.h"
      69  #include "revision.h"
      70  #include "timespec.h"
      71  
      72  #include "dirname.h"
      73  #include "fcntl--.h"
      74  #include "filename.h"
      75  #include "getopt.h"
      76  #include "ignore-value.h"
      77  #include "stat-time.h"
      78  #include "version.h"
      79  #include "xalloc.h"
      80  #include "yesno.h"
      81  
      82                  /* configuration */
      83  
      84  #include <limits.h>
      85  #include <unistd.h>
      86  #include <stdlib.h>
      87  #include <errno.h>
      88  
      89  #ifndef NO_DIR
      90  # define NO_DIR 0
      91  #endif
      92  #if !NO_DIR
      93  # include <dirent.h>
      94  # include <savedir.h>
      95  #endif
      96  
      97  #ifndef NO_UTIME
      98  #  include <utimens.h>
      99  #endif
     100  
     101  #ifndef MAX_PATH_LEN
     102  #  define MAX_PATH_LEN   1024 /* max pathname length */
     103  #endif
     104  
     105  #ifndef SEEK_END
     106  #  define SEEK_END 2
     107  #endif
     108  
     109  #ifndef CHAR_BIT
     110  #  define CHAR_BIT 8
     111  #endif
     112  
     113  #ifdef off_t
     114    off_t lseek (int fd, off_t offset, int whence);
     115  #endif
     116  
     117  #ifndef HAVE_WORKING_O_NOFOLLOW
     118  # define HAVE_WORKING_O_NOFOLLOW 0
     119  #endif
     120  
     121  /* Separator for file name parts (see shorten_name()) */
     122  #ifdef NO_MULTIPLE_DOTS
     123  #  define PART_SEP "-"
     124  #else
     125  #  define PART_SEP "."
     126  #endif
     127  
     128                  /* global buffers */
     129  
     130  /* With IBM_Z_DFLTCC, DEFLATE COMPRESSION works faster with
     131     page-aligned input and output buffers, and requires page-aligned
     132     windows; the alignment requirement is 4096.  On other platforms
     133     alignment doesn't hurt, and alignment up to 4096 is portable so
     134     let's do that.  */
     135  #if defined HAVE_C_ALIGNASOF || defined alignas
     136  # define BUFFER_ALIGNED alignas (4096)
     137  #else
     138  # define BUFFER_ALIGNED /**/
     139  #endif
     140  DECLARE(uch BUFFER_ALIGNED, inbuf,  INBUFSIZ +INBUF_EXTRA);
     141  DECLARE(uch BUFFER_ALIGNED, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
     142  DECLARE(ush, d_buf,  DIST_BUFSIZE);
     143  DECLARE(uch BUFFER_ALIGNED, window, 2L*WSIZE);
     144  #ifndef MAXSEG_64K
     145      DECLARE(ush, tab_prefix, 1L<<BITS);
     146  #else
     147      DECLARE(ush, tab_prefix0, 1L<<(BITS-1));
     148      DECLARE(ush, tab_prefix1, 1L<<(BITS-1));
     149  #endif
     150  
     151                  /* local variables */
     152  
     153  /* If true, pretend that standard input is a tty.  This option
     154     is deliberately not documented, and only for testing.  */
     155  static bool presume_input_tty;
     156  
     157  /* If true, transfer output data to the output file's storage device
     158     when supported.  Otherwise, if the system crashes around the time
     159     gzip is run, the user might lose both input and output data.  See:
     160     Pillai TS et al.  All file systems are not created equal: on the
     161     complexity of crafting crash-consistent applications. OSDI'14. 2014:433-48.
     162     https://www.usenix.org/conference/osdi14/technical-sessions/presentation/pillai */
     163  static bool synchronous;
     164  
     165  static int ascii = 0;        /* convert end-of-lines to local OS conventions */
     166         int to_stdout = 0;    /* output to stdout (-c) */
     167  static int decompress = 0;   /* decompress (-d) */
     168  static int force = 0;        /* don't ask questions, compress links (-f) */
     169  static int keep = 0;         /* keep (don't delete) input files */
     170  static int no_name = -1;     /* don't save or restore the original file name */
     171  static int no_time = -1;     /* don't save or restore the original file time */
     172  static int recursive = 0;    /* recurse through directories (-r) */
     173  static int list = 0;         /* list the file contents (-l) */
     174  #ifndef DEBUG
     175  static
     176  #endif
     177         int verbose = 0;      /* be verbose (-v) */
     178         int quiet = 0;        /* be very quiet (-q) */
     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) */
     193  
     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;
     201  
     202  /* The set of signals that are caught.  */
     203  static sigset_t caught_signals;
     204  
     205  /* If nonnegative, close this file descriptor and unlink remove_ofname
     206     on error.  */
     207  static int volatile remove_ofname_fd = -1;
     208  static char volatile remove_ofname[MAX_PATH_LEN];
     209  
     210  static bool stdin_was_read;
     211  
     212  off_t bytes_in;             /* number of input bytes */
     213  off_t bytes_out;            /* number of output bytes */
     214  static off_t total_in;      /* input bytes for all files */
     215  static off_t total_out;	    /* output bytes for all files */
     216  char ifname[MAX_PATH_LEN]; /* input file name */
     217  char ofname[MAX_PATH_LEN]; /* output file name */
     218  static char dfname[MAX_PATH_LEN]; /* name of dir containing output file */
     219  static struct stat istat;         /* status for input file */
     220  int  ifd;                  /* input file descriptor */
     221  int  ofd;                  /* output file descriptor */
     222  static int dfd = -1;       /* output directory file descriptor */
     223  unsigned insize;           /* valid bytes in inbuf */
     224  unsigned inptr;            /* index of next byte to be processed in inbuf */
     225  unsigned outcnt;           /* bytes in output buffer */
     226  int rsync = 0;             /* make rsyncable chunks */
     227  
     228  static int handled_sig[] =
     229    {
     230      /* SIGINT must be first, as 'foreground' depends on it.  */
     231      SIGINT
     232  
     233  #ifdef SIGHUP
     234      , SIGHUP
     235  #endif
     236  #if SIGPIPE
     237      , SIGPIPE
     238  #endif
     239  #ifdef SIGTERM
     240      , SIGTERM
     241  #endif
     242  #ifdef SIGXCPU
     243      , SIGXCPU
     244  #endif
     245  #ifdef SIGXFSZ
     246      , SIGXFSZ
     247  #endif
     248    };
     249  
     250  /* For long options that have no equivalent short option, use a
     251     non-character as a pseudo short option, starting with CHAR_MAX + 1.  */
     252  enum
     253  {
     254    PRESUME_INPUT_TTY_OPTION = CHAR_MAX + 1,
     255    RSYNCABLE_OPTION,
     256    SYNCHRONOUS_OPTION,
     257  
     258    /* A value greater than all valid long options, used as a flag to
     259       distinguish options derived from the GZIP environment variable.  */
     260    ENV_OPTION
     261  };
     262  
     263  static char const shortopts[] = "ab:cdfhH?klLmMnNqrS:tvVZ123456789";
     264  
     265  static const struct option longopts[] =
     266  {
     267   /* { name  has_arg  *flag  val } */
     268      {"ascii",      0, 0, 'a'}, /* ascii text mode */
     269      {"to-stdout",  0, 0, 'c'}, /* write output on standard output */
     270      {"stdout",     0, 0, 'c'}, /* write output on standard output */
     271      {"decompress", 0, 0, 'd'}, /* decompress */
     272      {"uncompress", 0, 0, 'd'}, /* decompress */
     273   /* {"encrypt",    0, 0, 'e'},    encrypt */
     274      {"force",      0, 0, 'f'}, /* force overwrite of output file */
     275      {"help",       0, 0, 'h'}, /* give help */
     276   /* {"pkzip",      0, 0, 'k'},    force output in pkzip format */
     277      {"keep",       0, 0, 'k'}, /* keep (don't delete) input files */
     278      {"list",       0, 0, 'l'}, /* list .gz file contents */
     279      {"license",    0, 0, 'L'}, /* display software license */
     280      {"no-name",    0, 0, 'n'}, /* don't save or restore original name & time */
     281      {"name",       0, 0, 'N'}, /* save or restore original name & time */
     282      {"-presume-input-tty", no_argument, NULL, PRESUME_INPUT_TTY_OPTION},
     283      {"quiet",      0, 0, 'q'}, /* quiet mode */
     284      {"silent",     0, 0, 'q'}, /* quiet mode */
     285      {"synchronous",0, 0, SYNCHRONOUS_OPTION},
     286      {"recursive",  0, 0, 'r'}, /* recurse through directories */
     287      {"suffix",     1, 0, 'S'}, /* use given suffix instead of .gz */
     288      {"test",       0, 0, 't'}, /* test compressed file integrity */
     289      {"verbose",    0, 0, 'v'}, /* verbose mode */
     290      {"version",    0, 0, 'V'}, /* display version number */
     291      {"fast",       0, 0, '1'}, /* compress faster */
     292      {"best",       0, 0, '9'}, /* compress better */
     293      {"lzw",        0, 0, 'Z'}, /* make output compatible with old compress */
     294      {"bits",       1, 0, 'b'}, /* max number of bits per code (implies -Z) */
     295      {"rsyncable",  0, 0, RSYNCABLE_OPTION}, /* make rsync-friendly archive */
     296      { 0, 0, 0, 0 }
     297  };
     298  
     299  /* local functions */
     300  
     301  _Noreturn static void try_help (void);
     302  static void help (void);
     303  static void license (void);
     304  static void version (void);
     305  static int input_eof (void);
     306  static void treat_stdin (void);
     307  static void treat_file (char *iname);
     308  static int create_outfile (void);
     309  static char *get_suffix (char *name);
     310  static int  open_input_file (char *iname, struct stat *sbuf);
     311  static void discard_input_bytes (size_t nbytes, unsigned int flags);
     312  static int  make_ofname (void);
     313  static void shorten_name (char *name);
     314  static int  get_method (int in);
     315  static void do_list (int method);
     316  static int  check_ofname (void);
     317  static void copy_stat (struct stat *ifstat);
     318  static void install_signal_handlers (void);
     319  static void remove_output_file (bool);
     320  static void abort_gzip_signal (int);
     321  _Noreturn static void do_exit (int exitcode);
     322  static void finish_out (void);
     323        int main          (int argc, char **argv);
     324  static int (*work) (int infile, int outfile) = zip; /* function to call */
     325  
     326  #if ! NO_DIR
     327  static void treat_dir (int fd, char *dir);
     328  #endif
     329  
     330  #define strequ(s1, s2) (strcmp((s1),(s2)) == 0)
     331  
     332  static void
     333  try_help ()
     334  {
     335    fprintf (stderr, "Try `%s --help' for more information.\n",
     336             program_name);
     337    do_exit (ERROR);
     338  }
     339  
     340  /* ======================================================================== */
     341  static void
     342  help ()
     343  {
     344      static char const* const help_msg[] = {
     345   "Compress or uncompress FILEs (by default, compress FILES in-place).",
     346   "",
     347   "Mandatory arguments to long options are mandatory for short options too.",
     348   "",
     349  #if O_BINARY
     350   "  -a, --ascii       ascii text; convert end-of-line using local conventions",
     351  #endif
     352   "  -c, --stdout      write on standard output, keep original files unchanged",
     353   "  -d, --decompress  decompress",
     354  /*  -e, --encrypt     encrypt */
     355   "  -f, --force       force overwrite of output file and compress links",
     356   "  -h, --help        give this help",
     357  /*  -k, --pkzip       force output in pkzip format */
     358   "  -k, --keep        keep (don't delete) input files",
     359   "  -l, --list        list compressed file contents",
     360   "  -L, --license     display software license",
     361  #ifdef UNDOCUMENTED
     362   "  -m                do not save or restore the original modification time",
     363   "  -M, --time        save or restore the original modification time",
     364  #endif
     365   "  -n, --no-name     do not save or restore the original name and timestamp",
     366   "  -N, --name        save or restore the original name and timestamp",
     367   "  -q, --quiet       suppress all warnings",
     368  #if ! NO_DIR
     369   "  -r, --recursive   operate recursively on directories",
     370  #endif
     371   "      --rsyncable   make rsync-friendly archive",
     372   "  -S, --suffix=SUF  use suffix SUF on compressed files",
     373   "      --synchronous synchronous output (safer if system crashes, but slower)",
     374   "  -t, --test        test compressed file integrity",
     375   "  -v, --verbose     verbose mode",
     376   "  -V, --version     display version number",
     377   "  -1, --fast        compress faster",
     378   "  -9, --best        compress better",
     379   "",
     380   "With no FILE, or when FILE is -, read standard input.",
     381   "",
     382   "Report bugs to <bug-gzip@gnu.org>.",
     383    0};
     384      char const *const *p = help_msg;
     385  
     386      printf ("Usage: %s [OPTION]... [FILE]...\n", program_name);
     387      while (*p) printf ("%s\n", *p++);
     388  }
     389  
     390  /* ======================================================================== */
     391  static void
     392  license ()
     393  {
     394      char const *const *p = license_msg;
     395  
     396      printf ("%s %s\n", program_name, Version);
     397      while (*p) printf ("%s\n", *p++);
     398  }
     399  
     400  /* ======================================================================== */
     401  static void
     402  version ()
     403  {
     404      license ();
     405      printf ("\n");
     406      printf ("Written by Jean-loup Gailly.\n");
     407  }
     408  
     409  static void
     410  progerror (char const *string)
     411  {
     412      fprintf (stderr, "%s: %s: %s\n", program_name, string, strerror (errno));
     413      exit_code = ERROR;
     414  }
     415  
     416  /* ======================================================================== */
     417  int main (int argc, char **argv)
     418  {
     419      int file_count;     /* number of files to process */
     420      size_t proglen;     /* length of program_name */
     421      char **argv_copy;
     422      int env_argc;
     423      char **env_argv;
     424  
     425      EXPAND(argc, argv); /* wild card expansion if necessary */
     426  
     427      program_name = gzip_base_name (argv[0]);
     428      proglen = strlen (program_name);
     429  
     430      /* Suppress .exe for MSDOS and OS/2: */
     431      if (4 < proglen && strequ (program_name + proglen - 4, ".exe"))
     432        program_name[proglen - 4] = '\0';
     433  
     434      /* Add options in GZIP environment variable if there is one */
     435      argv_copy = argv;
     436      env = add_envopt (&env_argc, &argv_copy, OPTIONS_VAR);
     437      env_argv = env ? argv_copy : NULL;
     438  
     439  #ifndef GNU_STANDARD
     440  # define GNU_STANDARD 1
     441  #endif
     442  #if !GNU_STANDARD
     443      /* For compatibility with old compress, use program name as an option.
     444       * Unless you compile with -DGNU_STANDARD=0, this program will behave as
     445       * gzip even if it is invoked under the name gunzip or zcat.
     446       *
     447       * Systems which do not support links can still use -d or -dc.
     448       * Ignore an .exe extension for MSDOS and OS/2.
     449       */
     450      if (strncmp (program_name, "un",  2) == 0     /* ungzip, uncompress */
     451          || strncmp (program_name, "gun", 3) == 0) /* gunzip */
     452          decompress = 1;
     453      else if (strequ (program_name + 1, "cat")     /* zcat, pcat, gcat */
     454               || strequ (program_name, "gzcat"))   /* gzcat */
     455          decompress = to_stdout = 1;
     456  #endif
     457  
     458      z_suffix = Z_SUFFIX;
     459      z_len = strlen(z_suffix);
     460  
     461      while (true) {
     462          int optc;
     463          int longind = -1;
     464  
     465          if (env_argv)
     466            {
     467              if (env_argv[optind] && strequ (env_argv[optind], "--"))
     468                optc = ENV_OPTION + '-';
     469              else
     470                {
     471                  optc = getopt_long (env_argc, env_argv, shortopts, longopts,
     472                                      &longind);
     473                  if (0 <= optc)
     474                    optc += ENV_OPTION;
     475                  else
     476                    {
     477                      if (optind != env_argc)
     478                        {
     479                          fprintf (stderr,
     480                                   ("%s: %s: non-option in "OPTIONS_VAR
     481                                    " environment variable\n"),
     482                                   program_name, env_argv[optind]);
     483                          try_help ();
     484                        }
     485  
     486                      /* Wait until here before warning, so that GZIP='-q'
     487                         doesn't warn.  */
     488                      if (env_argc != 1 && !quiet)
     489                        fprintf (stderr,
     490                                 ("%s: warning: "OPTIONS_VAR" environment variable"
     491                                  " is deprecated; use an alias or script\n"),
     492                                 program_name);
     493  
     494                      /* Start processing ARGC and ARGV instead.  */
     495                      free (env_argv);
     496                      env_argv = NULL;
     497                      optind = 1;
     498                      longind = -1;
     499                    }
     500                }
     501            }
     502  
     503          if (!env_argv)
     504            optc = getopt_long (argc, argv, shortopts, longopts, &longind);
     505          if (optc < 0)
     506            break;
     507  
     508          switch (optc) {
     509          case 'a':
     510              ascii = 1; break;
     511          case 'b':
     512              maxbits = atoi(optarg);
     513              for (; *optarg; optarg++)
     514                if (! ('0' <= *optarg && *optarg <= '9'))
     515                  {
     516                    fprintf (stderr, "%s: -b operand is not an integer\n",
     517                             program_name);
     518                    try_help ();
     519                  }
     520              break;
     521          case 'c':
     522              to_stdout = 1; break;
     523          case 'd':
     524              decompress = 1; break;
     525          case 'f':
     526              force++; break;
     527          case 'h': case 'H':
     528              help (); finish_out (); break;
     529          case 'k':
     530              keep = 1; break;
     531          case 'l':
     532              list = decompress = test = to_stdout = 1; break;
     533          case 'L':
     534              license (); finish_out (); break;
     535          case 'm': /* undocumented, may change later */
     536              no_time = 1; break;
     537          case 'M': /* undocumented, may change later */
     538              no_time = 0; break;
     539          case 'n':
     540          case 'n' + ENV_OPTION:
     541              no_name = no_time = 1; break;
     542          case 'N':
     543          case 'N' + ENV_OPTION:
     544              no_name = no_time = 0; break;
     545          case PRESUME_INPUT_TTY_OPTION:
     546              presume_input_tty = true; break;
     547          case 'q':
     548          case 'q' + ENV_OPTION:
     549              quiet = 1; verbose = 0; break;
     550          case 'r':
     551  #if NO_DIR
     552              fprintf (stderr, "%s: -r not supported on this system\n",
     553                       program_name);
     554              try_help ();
     555  #else
     556              recursive = 1;
     557  #endif
     558              break;
     559  
     560          case RSYNCABLE_OPTION:
     561          case RSYNCABLE_OPTION + ENV_OPTION:
     562              rsync = 1;
     563              break;
     564          case 'S':
     565  #ifdef NO_MULTIPLE_DOTS
     566              if (*optarg == '.') optarg++;
     567  #endif
     568              z_len = strlen(optarg);
     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;
     596  
     597          default:
     598              if (ENV_OPTION <= optc && optc != ENV_OPTION + '?')
     599                {
     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"));
     608                }
     609              try_help ();
     610          }
     611      } /* loop on all arguments */
     612  
     613      /* By default, save name and timestamp on compression but do not
     614       * restore them on decompression.
     615       */
     616      if (no_time < 0) no_time = decompress;
     617      if (no_name < 0) no_name = decompress;
     618  
     619      file_count = argc - optind;
     620  
     621  #if O_BINARY
     622  #else
     623      if (ascii && !quiet) {
     624          fprintf(stderr, "%s: option --ascii ignored on this system\n",
     625                  program_name);
     626      }
     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);
     631      }
     632  
     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
     644  
     645      /* And get to work */
     646      if (file_count != 0) {
     647          if (to_stdout && !test && (!decompress || !ascii)) {
     648              SET_BINARY_MODE (STDOUT_FILENO);
     649          }
     650          while (optind < argc) {
     651              treat_file(argv[optind++]);
     652          }
     653      } else {  /* Standard input */
     654          treat_stdin();
     655      }
     656      if (stdin_was_read && close (STDIN_FILENO) != 0)
     657        {
     658          strcpy (ifname, "stdin");
     659          read_error ();
     660        }
     661      if (list)
     662        {
     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 ();
     668        }
     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);
     676  }
     677  
     678  /* Return nonzero when at end of file on input.  */
     679  static int
     680  input_eof ()
     681  {
     682    if (!decompress || last_member)
     683      return 1;
     684  
     685    if (inptr == insize)
     686      {
     687        if (insize != INBUFSIZ || fill_inbuf (1) == EOF)
     688          return 1;
     689  
     690        /* Unget the char that fill_inbuf got.  */
     691        inptr = 0;
     692      }
     693  
     694    return 0;
     695  }
     696  
     697  static void
     698  get_input_size_and_time (void)
     699  {
     700    ifile_size = -1;
     701    time_stamp.tv_nsec = -1;
     702  
     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.  */
     707  
     708    if (S_ISREG (istat.st_mode))
     709      {
     710        ifile_size = istat.st_size;
     711        if (!no_time || list)
     712          time_stamp = get_stat_mtime (&istat);
     713      }
     714  }
     715  
     716  /* ========================================================================
     717   * Compress or decompress stdin
     718   */
     719  static void
     720  treat_stdin ()
     721  {
     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:
     728           *
     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.
     734           *
     735           * Here we use the --force option to get the other behavior.
     736           */
     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);
     747      }
     748  
     749      if (decompress || !ascii) {
     750        SET_BINARY_MODE (STDIN_FILENO);
     751      }
     752      if (!test && (!decompress || !ascii)) {
     753        SET_BINARY_MODE (STDOUT_FILENO);
     754      }
     755      strcpy(ifname, "stdin");
     756      strcpy(ofname, "stdout");
     757  
     758      /* Get the file's timestamp and size.  */
     759      if (fstat (STDIN_FILENO, &istat) != 0)
     760        {
     761          progerror ("standard input");
     762          do_exit (ERROR);
     763        }
     764  
     765      get_input_size_and_time ();
     766  
     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;
     772  
     773      if (decompress) {
     774          method = get_method(ifd);
     775          if (method < 0) {
     776              do_exit(exit_code); /* error message already emitted */
     777          }
     778      }
     779  
     780      /* Actually do the compression/decompression. Loop over zipped members.
     781       */
     782      for (;;) {
     783          if (work (STDIN_FILENO, STDOUT_FILENO) != OK)
     784            return;
     785  
     786          if (input_eof ())
     787            break;
     788  
     789          method = get_method(ifd);
     790          if (method < 0) return; /* error message already emitted */
     791          bytes_out = 0;            /* required for length check */
     792      }
     793  
     794      if (list)
     795        {
     796          do_list (method);
     797          return;
     798        }
     799  
     800      if (verbose) {
     801          if (test) {
     802              fprintf(stderr, " OK\n");
     803  
     804          } else if (!decompress) {
     805              display_ratio(bytes_in-(bytes_out-header_bytes), bytes_in, stderr);
     806              fprintf(stderr, "\n");
     807  #ifdef DISPLAY_STDIN_RATIO
     808          } else {
     809              display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out,stderr);
     810              fprintf(stderr, "\n");
     811  #endif
     812          }
     813      }
     814  }
     815  
     816  static char const dot = '.';
     817  
     818  /* True if the cached directory for calls to openat etc. is DIR, with
     819     length DIRLEN.  DIR need not be null-terminated.  DIRLEN must be
     820     less than MAX_PATH_LEN.  */
     821  static bool
     822  atdir_eq (char const *dir, ptrdiff_t dirlen)
     823  {
     824    if (dirlen == 0)
     825      dir = &dot, dirlen = 1;
     826    return memcmp (dfname, dir, dirlen) == 0 && !dfname[dirlen];
     827  }
     828  
     829  /* Set the directory used for calls to openat etc. to be the directory
     830     DIR, with length DIRLEN.  DIR need not be null-terminated.
     831     DIRLEN must be less than MAX_PATH_LEN.  Return a file descriptor for
     832     the directory, or -1 if one could not be obtained.  */
     833  static int
     834  atdir_set (char const *dir, ptrdiff_t dirlen)
     835  {
     836    /* Don't bother opening directories on older systems that
     837       lack openat and unlinkat.  It's not worth the porting hassle.  */
     838    #if HAVE_OPENAT && HAVE_UNLINKAT
     839      enum { try_opening_directories = true };
     840    #else
     841      enum { try_opening_directories = false };
     842    #endif
     843  
     844    if (try_opening_directories && ! atdir_eq (dir, dirlen))
     845      {
     846        if (0 <= dfd)
     847          close (dfd);
     848        if (dirlen == 0)
     849          dir = &dot, dirlen = 1;
     850        memcpy (dfname, dir, dirlen);
     851        dfname[dirlen] = '\0';
     852        dfd = open (dfname, O_SEARCH | O_DIRECTORY);
     853      }
     854  
     855    return dfd;
     856  }
     857  
     858  /* ========================================================================
     859   * Compress or decompress the given file
     860   */
     861  static void
     862  treat_file (char *iname)
     863  {
     864      /* Accept "-" as synonym for stdin */
     865      if (strequ(iname, "-")) {
     866          int cflag = to_stdout;
     867          treat_stdin();
     868          to_stdout = cflag;
     869          return;
     870      }
     871  
     872      /* Check if the input file is present, set ifname and istat: */
     873      ifd = open_input_file (iname, &istat);
     874      if (ifd < 0)
     875        return;
     876  
     877      /* If the input name is that of a directory, recurse or ignore: */
     878      if (S_ISDIR(istat.st_mode)) {
     879  #if ! NO_DIR
     880          if (recursive) {
     881              treat_dir (ifd, iname);
     882              /* Warning: ifname is now garbage */
     883              return;
     884          }
     885  #endif
     886          close (ifd);
     887          WARN ((stderr, "%s: %s is a directory -- ignored\n",
     888                 program_name, ifname));
     889          return;
     890      }
     891  
     892      if (! to_stdout)
     893        {
     894          if (! S_ISREG (istat.st_mode))
     895            {
     896              WARN ((stderr,
     897                     "%s: %s is not a directory or a regular file - ignored\n",
     898                     program_name, ifname));
     899              close (ifd);
     900              return;
     901            }
     902          if (istat.st_mode & S_ISUID)
     903            {
     904              WARN ((stderr, "%s: %s is set-user-ID on execution - ignored\n",
     905                     program_name, ifname));
     906              close (ifd);
     907              return;
     908            }
     909          if (istat.st_mode & S_ISGID)
     910            {
     911              WARN ((stderr, "%s: %s is set-group-ID on execution - ignored\n",
     912                     program_name, ifname));
     913              close (ifd);
     914              return;
     915            }
     916  
     917          if (! force)
     918            {
     919              if (istat.st_mode & S_ISVTX)
     920                {
     921                  WARN ((stderr,
     922                         "%s: %s has the sticky bit set - file ignored\n",
     923                         program_name, ifname));
     924                  close (ifd);
     925                  return;
     926                }
     927              if (2 <= istat.st_nlink)
     928                {
     929                  WARN ((stderr, "%s: %s has %lu other link%s -- file ignored\n",
     930                         program_name, ifname,
     931                         (unsigned long int) istat.st_nlink - 1,
     932                         istat.st_nlink == 2 ? "" : "s"));
     933                  close (ifd);
     934                  return;
     935                }
     936            }
     937        }
     938  
     939      get_input_size_and_time ();
     940  
     941      /* Generate output file name. For -r and (-t or -l), skip files
     942       * without a valid gzip suffix (check done in make_ofname).
     943       */
     944      if (to_stdout && !test) {
     945          strcpy(ofname, "stdout");
     946  
     947      } else if (make_ofname() != OK) {
     948          close (ifd);
     949          return;
     950      }
     951  
     952      clear_bufs(); /* clear input and output buffers */
     953      part_nb = 0;
     954  
     955      if (decompress) {
     956          method = get_method(ifd); /* updates ofname if original given */
     957          if (method < 0) {
     958              close(ifd);
     959              return;               /* error message already emitted */
     960          }
     961      }
     962  
     963      /* If compressing to a file, check if ofname is not ambiguous
     964       * because the operating system truncates names. Otherwise, generate
     965       * a new ofname and save the original name in the compressed file.
     966       */
     967      if (to_stdout) {
     968          ofd = STDOUT_FILENO;
     969          /* Keep remove_ofname_fd negative.  */
     970      } else {
     971          if (create_outfile() != OK) return;
     972  
     973          if (!decompress && save_orig_name && !verbose && !quiet) {
     974              fprintf(stderr, "%s: %s compressed to %s\n",
     975                      program_name, ifname, ofname);
     976          }
     977      }
     978      /* Keep the name even if not truncated except with --no-name: */
     979      if (!save_orig_name) save_orig_name = !no_name;
     980  
     981      if (verbose && !list) {
     982          fprintf(stderr, "%s:\t", ifname);
     983      }
     984  
     985      /* Actually do the compression/decompression. Loop over zipped members.
     986       */
     987      for (;;) {
     988          if ((*work)(ifd, ofd) != OK) {
     989              method = -1; /* force cleanup */
     990              break;
     991          }
     992  
     993          if (input_eof ())
     994            break;
     995  
     996          method = get_method(ifd);
     997          if (method < 0) break;    /* error message already emitted */
     998          bytes_out = 0;            /* required for length check */
     999      }
    1000  
    1001      if (close (ifd) != 0)
    1002        read_error ();
    1003  
    1004      if (list)
    1005        {
    1006          do_list (method);
    1007          return;
    1008        }
    1009  
    1010      if (!to_stdout)
    1011        {
    1012          copy_stat (&istat);
    1013  
    1014          if ((synchronous
    1015               && ((0 <= dfd && fdatasync (dfd) != 0 && errno != EINVAL)
    1016                   || (fsync (ofd) != 0 && errno != EINVAL)))
    1017              || close (ofd) != 0)
    1018            write_error ();
    1019  
    1020          if (!keep)
    1021            {
    1022              sigset_t oldset;
    1023              int unlink_errno;
    1024              char *ifbase = last_component (ifname);
    1025              int ufd = atdir_eq (ifname, ifbase - ifname) ? dfd : -1;
    1026              int res;
    1027  
    1028              sigprocmask (SIG_BLOCK, &caught_signals, &oldset);
    1029              remove_ofname_fd = -1;
    1030              res = ufd < 0 ? xunlink (ifname) : unlinkat (ufd, ifbase, 0);
    1031              unlink_errno = res == 0 ? 0 : errno;
    1032              sigprocmask (SIG_SETMASK, &oldset, NULL);
    1033  
    1034              if (unlink_errno)
    1035                WARN ((stderr, "%s: %s: %s\n", program_name, ifname,
    1036                       strerror (unlink_errno)));
    1037            }
    1038        }
    1039  
    1040      if (method == -1) {
    1041          if (!to_stdout)
    1042            remove_output_file (false);
    1043          return;
    1044      }
    1045  
    1046      /* Display statistics */
    1047      if(verbose) {
    1048          if (test) {
    1049              fprintf(stderr, " OK");
    1050          } else if (decompress) {
    1051              display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out,stderr);
    1052          } else {
    1053              display_ratio(bytes_in-(bytes_out-header_bytes), bytes_in, stderr);
    1054          }
    1055          if (!test)
    1056            fprintf(stderr, " -- %s %s", keep ? "created" : "replaced with",
    1057                    ofname);
    1058          fprintf(stderr, "\n");
    1059      }
    1060  }
    1061  
    1062  static void
    1063  volatile_strcpy (char volatile *dst, char const volatile *src)
    1064  {
    1065    while ((*dst++ = *src++))
    1066      continue;
    1067  }
    1068  
    1069  /* ========================================================================
    1070   * Create the output file. Return OK or ERROR.
    1071   * Try several times if necessary to avoid truncating the z_suffix. For
    1072   * example, do not create a compressed file of name "1234567890123."
    1073   * Sets save_orig_name to true if the file name has been truncated.
    1074   * IN assertions: the input file has already been open (ifd is set) and
    1075   *   ofname has already been updated if there was an original name.
    1076   * OUT assertions: ifd and ofd are closed in case of error.
    1077   */
    1078  static int
    1079  create_outfile ()
    1080  {
    1081    static bool signal_handlers_installed;
    1082    int name_shortened = 0;
    1083    int flags = (O_WRONLY | O_CREAT | O_EXCL
    1084                 | (ascii && decompress ? 0 : O_BINARY));
    1085    char const *base = ofname;
    1086    int atfd = AT_FDCWD;
    1087  
    1088    if (!keep)
    1089      {
    1090        char const *b = last_component (ofname);
    1091        int f = atdir_set (ofname, b - ofname);
    1092        if (0 <= f)
    1093          {
    1094            base = b;
    1095            atfd = f;
    1096          }
    1097      }
    1098  
    1099    if (!signal_handlers_installed)
    1100      {
    1101        signal_handlers_installed = true;
    1102        install_signal_handlers ();
    1103      }
    1104  
    1105    for (;;)
    1106      {
    1107        int open_errno;
    1108        sigset_t oldset;
    1109  
    1110        volatile_strcpy (remove_ofname, ofname);
    1111  
    1112        sigprocmask (SIG_BLOCK, &caught_signals, &oldset);
    1113        remove_ofname_fd = ofd = openat (atfd, base, flags, S_IRUSR | S_IWUSR);
    1114        open_errno = errno;
    1115        sigprocmask (SIG_SETMASK, &oldset, NULL);
    1116  
    1117        if (0 <= ofd)
    1118          break;
    1119  
    1120        switch (open_errno)
    1121          {
    1122  #ifdef ENAMETOOLONG
    1123          case ENAMETOOLONG:
    1124            shorten_name (ofname);
    1125            name_shortened = 1;
    1126            break;
    1127  #endif
    1128  
    1129          case EEXIST:
    1130            if (check_ofname () != OK)
    1131              {
    1132                close (ifd);
    1133                return ERROR;
    1134              }
    1135            break;
    1136  
    1137          default:
    1138            write_error ();
    1139            close (ifd);
    1140            return ERROR;
    1141          }
    1142      }
    1143  
    1144    if (name_shortened && decompress)
    1145      {
    1146        /* name might be too long if an original name was saved */
    1147        WARN ((stderr, "%s: %s: warning, name truncated\n",
    1148               program_name, ofname));
    1149      }
    1150  
    1151    return OK;
    1152  }
    1153  
    1154  /* ========================================================================
    1155   * Return a pointer to the 'z' suffix of a file name, or NULL. For all
    1156   * systems, ".gz", ".z", ".Z", ".taz", ".tgz", "-gz", "-z" and "_z" are
    1157   * accepted suffixes, in addition to the value of the --suffix option.
    1158   * ".tgz" is a useful convention for tar.z files on systems limited
    1159   * to 3 characters extensions. On such systems, ".?z" and ".??z" are
    1160   * also accepted suffixes. For Unix, we do not want to accept any
    1161   * .??z suffix as indicating a compressed file; some people use .xyz
    1162   * to denote volume data.
    1163   */
    1164  static char *
    1165  get_suffix (char *name)
    1166  {
    1167      int nlen, slen;
    1168      char suffix[MAX_SUFFIX+3]; /* last chars of name, forced to lower case */
    1169      static char const *known_suffixes[] =
    1170         {NULL, ".gz", ".z", ".taz", ".tgz", "-gz", "-z", "_z",
    1171  #ifdef MAX_EXT_CHARS
    1172            "z",
    1173  #endif
    1174          NULL, NULL};
    1175      char const **suf;
    1176      bool suffix_of_builtin = false;
    1177  
    1178      /* Normally put Z_SUFFIX at the start of KNOWN_SUFFIXES, but if it
    1179         is a suffix of one of them, put it at the end.  */
    1180      for (suf = known_suffixes + 1; *suf; suf++)
    1181        {
    1182          size_t suflen = strlen (*suf);
    1183          if (z_len < suflen && strequ (z_suffix, *suf + suflen - z_len))
    1184            {
    1185              suffix_of_builtin = true;
    1186              break;
    1187            }
    1188        }
    1189  
    1190      char *z_lower = xstrdup(z_suffix);
    1191      strlwr(z_lower);
    1192      known_suffixes[suffix_of_builtin
    1193                     ? sizeof known_suffixes / sizeof *known_suffixes - 2
    1194                     : 0] = z_lower;
    1195      suf = known_suffixes + suffix_of_builtin;
    1196  
    1197      nlen = strlen(name);
    1198      if (nlen <= MAX_SUFFIX+2) {
    1199          strcpy(suffix, name);
    1200      } else {
    1201          strcpy(suffix, name+nlen-MAX_SUFFIX-2);
    1202      }
    1203      strlwr(suffix);
    1204      slen = strlen(suffix);
    1205      char *match = NULL;
    1206      do {
    1207         int s = strlen(*suf);
    1208         if (slen > s && ! ISSLASH (suffix[slen - s - 1])
    1209             && strequ(suffix + slen - s, *suf)) {
    1210             match = name+nlen-s;
    1211             break;
    1212         }
    1213      } while (*++suf != NULL);
    1214      free(z_lower);
    1215  
    1216      return match;
    1217  }
    1218  
    1219  
    1220  /* Open file NAME with the given flags and store its status
    1221     into *ST.  Return a file descriptor to the newly opened file, or -1
    1222     (setting errno) on failure.  */
    1223  static int
    1224  open_and_stat (char *name, int flags, struct stat *st)
    1225  {
    1226    int fd;
    1227    int atfd = AT_FDCWD;
    1228    char const *base = name;
    1229  
    1230    /* Refuse to follow symbolic links unless -c or -f.  */
    1231    if (!to_stdout && !force)
    1232      {
    1233        if (HAVE_WORKING_O_NOFOLLOW)
    1234          flags |= O_NOFOLLOW;
    1235        else
    1236          {
    1237  #ifdef S_ISLNK
    1238            if (lstat (name, st) != 0)
    1239              return -1;
    1240            else if (S_ISLNK (st->st_mode))
    1241              {
    1242                errno = ELOOP;
    1243                return -1;
    1244              }
    1245  #endif
    1246          }
    1247      }
    1248  
    1249    if (!keep)
    1250      {
    1251        char const *b = last_component (name);
    1252        int f = atdir_set (name, b - name);
    1253        if (0 <= f)
    1254          {
    1255            base = b;
    1256            atfd = f;
    1257          }
    1258      }
    1259  
    1260    fd = openat (atfd, base, flags);
    1261    if (0 <= fd && fstat (fd, st) != 0)
    1262      {
    1263        int e = errno;
    1264        close (fd);
    1265        errno = e;
    1266        return -1;
    1267      }
    1268    return fd;
    1269  }
    1270  
    1271  
    1272  /* ========================================================================
    1273   * Set ifname to the input file name (with a suffix appended if necessary)
    1274   * and istat to its stats. For decompression, if no file exists with the
    1275   * original name, try adding successively z_suffix, .gz, .z, -z and .Z.
    1276   * For MSDOS, we try only z_suffix and z.
    1277   * Return an open file descriptor or -1.
    1278   */
    1279  static int
    1280  open_input_file (char *iname, struct stat *sbuf)
    1281  {
    1282      int ilen;  /* strlen(ifname) */
    1283      int z_suffix_errno = 0;
    1284      static char const *suffixes[] = {NULL, ".gz", ".z", "-z", ".Z", NULL};
    1285      char const **suf = suffixes;
    1286      char const *s;
    1287  #ifdef NO_MULTIPLE_DOTS
    1288      char *dot; /* pointer to ifname extension, or NULL */
    1289  #endif
    1290      int fd;
    1291      int open_flags = (O_RDONLY | O_NONBLOCK | O_NOCTTY
    1292                        | (ascii && !decompress ? 0 : O_BINARY));
    1293  
    1294      *suf = z_suffix;
    1295  
    1296      if (sizeof ifname - 1 <= strlen (iname))
    1297          goto name_too_long;
    1298  
    1299      strcpy(ifname, iname);
    1300  
    1301      /* If input file exists, return OK. */
    1302      fd = open_and_stat (ifname, open_flags, sbuf);
    1303      if (0 <= fd)
    1304        return fd;
    1305  
    1306      if (!decompress || errno != ENOENT) {
    1307          progerror(ifname);
    1308          return -1;
    1309      }
    1310      /* File.ext doesn't exist.  Try adding a suffix.  */
    1311      s = get_suffix(ifname);
    1312      if (s != NULL) {
    1313          progerror(ifname); /* ifname already has z suffix and does not exist */
    1314          return -1;
    1315      }
    1316  #ifdef NO_MULTIPLE_DOTS
    1317      dot = strrchr(ifname, '.');
    1318      if (dot == NULL) {
    1319          strcat(ifname, ".");
    1320          dot = strrchr(ifname, '.');
    1321      }
    1322  #endif
    1323      ilen = strlen(ifname);
    1324      if (strequ(z_suffix, ".gz")) suf++;
    1325  
    1326      /* Search for all suffixes */
    1327      do {
    1328          char const *s0 = s = *suf;
    1329          strcpy (ifname, iname);
    1330  #ifdef NO_MULTIPLE_DOTS
    1331          if (*s == '.') s++;
    1332          if (*dot == '\0') strcpy (dot, ".");
    1333  #endif
    1334  #ifdef MAX_EXT_CHARS
    1335          if (MAX_EXT_CHARS < strlen (s) + strlen (dot + 1))
    1336            dot[MAX_EXT_CHARS + 1 - strlen (s)] = '\0';
    1337  #endif
    1338          if (sizeof ifname <= ilen + strlen (s))
    1339            goto name_too_long;
    1340          strcat(ifname, s);
    1341          fd = open_and_stat (ifname, open_flags, sbuf);
    1342          if (0 <= fd)
    1343            return fd;
    1344          if (errno != ENOENT)
    1345            {
    1346              progerror (ifname);
    1347              return -1;
    1348            }
    1349          if (strequ (s0, z_suffix))
    1350            z_suffix_errno = errno;
    1351      } while (*++suf != NULL);
    1352  
    1353      /* No suffix found, complain using z_suffix: */
    1354      strcpy(ifname, iname);
    1355  #ifdef NO_MULTIPLE_DOTS
    1356      if (*dot == '\0') strcpy(dot, ".");
    1357  #endif
    1358  #ifdef MAX_EXT_CHARS
    1359      if (MAX_EXT_CHARS < z_len + strlen (dot + 1))
    1360        dot[MAX_EXT_CHARS + 1 - z_len] = '\0';
    1361  #endif
    1362      strcat(ifname, z_suffix);
    1363      errno = z_suffix_errno;
    1364      progerror(ifname);
    1365      return -1;
    1366  
    1367   name_too_long:
    1368      fprintf (stderr, "%s: %s: file name too long\n", program_name, iname);
    1369      exit_code = ERROR;
    1370      return -1;
    1371  }
    1372  
    1373  /* ========================================================================
    1374   * Generate ofname given ifname. Return OK, or WARNING if file must be skipped.
    1375   * Sets save_orig_name to true if the file name has been truncated.
    1376   */
    1377  static int
    1378  make_ofname ()
    1379  {
    1380      char *suff;            /* ofname z suffix */
    1381  
    1382      strcpy(ofname, ifname);
    1383      /* strip a version number if any and get the gzip suffix if present: */
    1384      suff = get_suffix(ofname);
    1385  
    1386      if (decompress) {
    1387          if (suff == NULL) {
    1388              /* With -t or -l, try all files (even without .gz suffix)
    1389               * except with -r (behave as with just -dr).
    1390               */
    1391              if (!recursive && test)
    1392                return OK;
    1393  
    1394              /* Avoid annoying messages with -r */
    1395              if (verbose || (!recursive && !quiet)) {
    1396                  WARN((stderr,"%s: %s: unknown suffix -- ignored\n",
    1397                        program_name, ifname));
    1398              }
    1399              return WARNING;
    1400          }
    1401          /* Make a special case for .tgz and .taz: */
    1402          strlwr(suff);
    1403          if (strequ(suff, ".tgz") || strequ(suff, ".taz")) {
    1404              strcpy(suff, ".tar");
    1405          } else {
    1406              *suff = '\0'; /* strip the z suffix */
    1407          }
    1408          /* ofname might be changed later if infile contains an original name */
    1409  
    1410      } else if (suff && ! force) {
    1411          /* Avoid annoying messages with -r (see treat_dir()) */
    1412          if (verbose || (!recursive && !quiet)) {
    1413              /* Don't use WARN, as it affects exit status.  */
    1414              fprintf (stderr, "%s: %s already has %s suffix -- unchanged\n",
    1415                       program_name, ifname, suff);
    1416          }
    1417          return WARNING;
    1418      } else {
    1419          save_orig_name = 0;
    1420  
    1421  #ifdef NO_MULTIPLE_DOTS
    1422          suff = strrchr(ofname, '.');
    1423          if (suff == NULL) {
    1424              if (sizeof ofname <= strlen (ofname) + 1)
    1425                  goto name_too_long;
    1426              strcat(ofname, ".");
    1427  #  ifdef MAX_EXT_CHARS
    1428              if (strequ(z_suffix, "z")) {
    1429                  if (sizeof ofname <= strlen (ofname) + 2)
    1430                      goto name_too_long;
    1431                  strcat(ofname, "gz"); /* enough room */
    1432                  return OK;
    1433              }
    1434          /* On the Atari and some versions of MSDOS,
    1435           * ENAMETOOLONG does not work correctly.  So we
    1436           * must truncate here.
    1437           */
    1438          } else if (strlen(suff)-1 + z_len > MAX_SUFFIX) {
    1439              suff[MAX_SUFFIX+1-z_len] = '\0';
    1440              save_orig_name = 1;
    1441  #  endif
    1442          }
    1443  #endif /* NO_MULTIPLE_DOTS */
    1444          if (sizeof ofname <= strlen (ofname) + z_len)
    1445              goto name_too_long;
    1446          strcat(ofname, z_suffix);
    1447  
    1448      } /* decompress ? */
    1449      return OK;
    1450  
    1451   name_too_long:
    1452      WARN ((stderr, "%s: %s: file name too long\n", program_name, ifname));
    1453      return WARNING;
    1454  }
    1455  
    1456  /* Discard NBYTES input bytes from the input, or up through the next
    1457     zero byte if NBYTES == (size_t) -1.  If FLAGS say that the header
    1458     CRC should be computed, update the CRC accordingly.  */
    1459  static void
    1460  discard_input_bytes (size_t nbytes, unsigned int flags)
    1461  {
    1462    while (nbytes != 0)
    1463      {
    1464        uch c = get_byte ();
    1465        if (flags & HEADER_CRC)
    1466          updcrc (&c, 1);
    1467        if (nbytes != (size_t) -1)
    1468          nbytes--;
    1469        else if (! c)
    1470          break;
    1471      }
    1472  }
    1473  
    1474  /* ========================================================================
    1475   * Check the magic number of the input file and update ofname if an
    1476   * original name was given and to_stdout is not set.
    1477   * Return the compression method, -1 for error, -2 for warning.
    1478   * Set inptr to the offset of the next byte to be processed.
    1479   * Updates time_stamp if there is one and neither -m nor -n is used.
    1480   * This function may be called repeatedly for an input file consisting
    1481   * of several contiguous gzip'ed members.
    1482   * 'in' is the input file descriptor.
    1483   * IN assertions: there is at least one remaining compressed member.
    1484   *   If the member is a zip file, it must be the only one.
    1485   */
    1486  static int
    1487  get_method (int in)
    1488  {
    1489      uch flags;     /* compression flags */
    1490      uch magic[10]; /* magic header */
    1491      int imagic0;   /* first magic byte or EOF */
    1492      int imagic1;   /* like magic[1], but can represent EOF */
    1493      ulg stamp;     /* timestamp */
    1494  
    1495      /* If --force and --stdout, zcat == cat, so do not complain about
    1496       * premature end of file: use try_byte instead of get_byte.
    1497       */
    1498      if (force && to_stdout) {
    1499          imagic0 = try_byte();
    1500          magic[0] = imagic0;
    1501          imagic1 = try_byte ();
    1502          magic[1] = imagic1;
    1503          /* If try_byte returned EOF, magic[1] == (char) EOF.  */
    1504      } else {
    1505          magic[0] = get_byte ();
    1506          imagic0 = 0;
    1507          if (magic[0]) {
    1508              magic[1] = get_byte ();
    1509              imagic1 = 0; /* avoid lint warning */
    1510          } else {
    1511              imagic1 = try_byte ();
    1512              magic[1] = imagic1;
    1513          }
    1514      }
    1515      method = -1;                 /* unknown yet */
    1516      part_nb++;                   /* number of parts in gzip file */
    1517      header_bytes = 0;
    1518      last_member = 0;
    1519      /* assume multiple members in gzip file except for record oriented I/O */
    1520  
    1521      if (memcmp(magic, GZIP_MAGIC, 2) == 0
    1522          || memcmp(magic, OLD_GZIP_MAGIC, 2) == 0) {
    1523  
    1524          method = (int)get_byte();
    1525          if (method != DEFLATED) {
    1526              fprintf(stderr,
    1527                      "%s: %s: unknown method %d -- not supported\n",
    1528                      program_name, ifname, method);
    1529              exit_code = ERROR;
    1530              return -1;
    1531          }
    1532          work = unzip;
    1533          flags  = (uch)get_byte();
    1534  
    1535          if ((flags & ENCRYPTED) != 0) {
    1536              fprintf(stderr,
    1537                      "%s: %s is encrypted -- not supported\n",
    1538                      program_name, ifname);
    1539              exit_code = ERROR;
    1540              return -1;
    1541          }
    1542          if ((flags & RESERVED) != 0) {
    1543              fprintf(stderr,
    1544                      "%s: %s has flags 0x%x -- not supported\n",
    1545                      program_name, ifname, flags);
    1546              exit_code = ERROR;
    1547              if (force <= 1) return -1;
    1548          }
    1549          stamp  = (ulg)get_byte();
    1550          stamp |= ((ulg)get_byte()) << 8;
    1551          stamp |= ((ulg)get_byte()) << 16;
    1552          stamp |= ((ulg)get_byte()) << 24;
    1553          if (stamp != 0 && !no_time)
    1554            {
    1555              if (stamp <= TYPE_MAXIMUM (time_t))
    1556                {
    1557                  time_stamp.tv_sec = stamp;
    1558                  time_stamp.tv_nsec = 0;
    1559                }
    1560              else
    1561                {
    1562                  WARN ((stderr,
    1563                         "%s: %s: MTIME %lu out of range for this platform\n",
    1564                         program_name, ifname, stamp));
    1565                  time_stamp.tv_sec = TYPE_MAXIMUM (time_t);
    1566                  time_stamp.tv_nsec = TIMESPEC_RESOLUTION - 1;
    1567                }
    1568            }
    1569  
    1570          magic[8] = get_byte ();  /* Ignore extra flags.  */
    1571          magic[9] = get_byte ();  /* Ignore OS type.  */
    1572  
    1573          if (flags & HEADER_CRC)
    1574            {
    1575              magic[2] = DEFLATED;
    1576              magic[3] = flags;
    1577              magic[4] = stamp & 0xff;
    1578              magic[5] = (stamp >> 8) & 0xff;
    1579              magic[6] = (stamp >> 16) & 0xff;
    1580              magic[7] = stamp >> 24;
    1581              updcrc (NULL, 0);
    1582              updcrc (magic, 10);
    1583            }
    1584  
    1585          if ((flags & EXTRA_FIELD) != 0) {
    1586              uch lenbuf[2];
    1587              unsigned int len = lenbuf[0] = get_byte ();
    1588              len |= (lenbuf[1] = get_byte ()) << 8;
    1589              if (verbose) {
    1590                  fprintf(stderr,"%s: %s: extra field of %u bytes ignored\n",
    1591                          program_name, ifname, len);
    1592              }
    1593              if (flags & HEADER_CRC)
    1594                updcrc (lenbuf, 2);
    1595              discard_input_bytes (len, flags);
    1596          }
    1597  
    1598          /* Get original file name if it was truncated */
    1599          if ((flags & ORIG_NAME) != 0) {
    1600              if (no_name || (to_stdout && !list) || part_nb > 1) {
    1601                  /* Discard the old name */
    1602                  discard_input_bytes (-1, flags);
    1603              } else {
    1604                  /* Copy the base name. Keep a directory prefix intact. */
    1605                  char *p = gzip_base_name (ofname);
    1606                  char *base = p;
    1607                  for (;;) {
    1608                      *p = (char) get_byte ();
    1609                      if (*p++ == '\0') break;
    1610                      if (p >= ofname+sizeof(ofname)) {
    1611                          gzip_error ("corrupted input -- file name too large");
    1612                      }
    1613                  }
    1614                  if (flags & HEADER_CRC)
    1615                    updcrc ((uch *) base, p - base);
    1616                  p = gzip_base_name (base);
    1617                  memmove (base, p, strlen (p) + 1);
    1618                  /* If necessary, adapt the name to local OS conventions: */
    1619                  if (!list) {
    1620                     MAKE_LEGAL_NAME(base);
    1621                     if (base) list=0; /* avoid warning about unused variable */
    1622                  }
    1623              } /* no_name || to_stdout */
    1624          } /* ORIG_NAME */
    1625  
    1626          /* Discard file comment if any */
    1627          if ((flags & COMMENT) != 0) {
    1628              discard_input_bytes (-1, flags);
    1629          }
    1630  
    1631          if (flags & HEADER_CRC)
    1632            {
    1633              unsigned int crc16 = updcrc (magic, 0) & 0xffff;
    1634              unsigned int header16 = get_byte ();
    1635              header16 |= ((unsigned int) get_byte ()) << 8;
    1636              if (header16 != crc16)
    1637                {
    1638                  fprintf (stderr,
    1639                           "%s: %s: header checksum 0x%04x != computed checksum 0x%04x\n",
    1640                           program_name, ifname, header16, crc16);
    1641                  exit_code = ERROR;
    1642                  if (force <= 1)
    1643                    return -1;
    1644                }
    1645            }
    1646  
    1647          if (part_nb == 1) {
    1648              header_bytes = inptr + 2*4; /* include crc and size */
    1649          }
    1650  
    1651      } else if (memcmp(magic, PKZIP_MAGIC, 2) == 0 && inptr == 2
    1652              && memcmp((char*)inbuf, PKZIP_MAGIC, 4) == 0) {
    1653          /* To simplify the code, we support a zip file when alone only.
    1654           * We are thus guaranteed that the entire local header fits in inbuf.
    1655           */
    1656          inptr = 0;
    1657          work = unzip;
    1658          if (check_zipfile(in) != OK) return -1;
    1659          /* check_zipfile may get ofname from the local header */
    1660          last_member = 1;
    1661  
    1662      } else if (memcmp(magic, PACK_MAGIC, 2) == 0) {
    1663          work = unpack;
    1664          method = PACKED;
    1665  
    1666      } else if (memcmp(magic, LZW_MAGIC, 2) == 0) {
    1667          work = unlzw;
    1668          method = COMPRESSED;
    1669          last_member = 1;
    1670  
    1671      } else if (memcmp(magic, LZH_MAGIC, 2) == 0) {
    1672          work = unlzh;
    1673          method = LZHED;
    1674          last_member = 1;
    1675  
    1676      } else if (force && to_stdout && !list) { /* pass input unchanged */
    1677          method = STORED;
    1678          work = copy;
    1679          if (imagic1 != EOF)
    1680              inptr--;
    1681          last_member = 1;
    1682          if (imagic0 != EOF) {
    1683              write_buf (STDOUT_FILENO, magic, 1);
    1684          }
    1685      }
    1686      if (method >= 0) return method;
    1687  
    1688      if (part_nb == 1) {
    1689          fprintf (stderr, "\n%s: %s: not in gzip format\n",
    1690                   program_name, ifname);
    1691          exit_code = ERROR;
    1692          return -1;
    1693      } else {
    1694          if (magic[0] == 0)
    1695            {
    1696              int inbyte;
    1697              for (inbyte = imagic1;  inbyte == 0;  inbyte = try_byte ())
    1698                continue;
    1699              if (inbyte == EOF)
    1700                {
    1701                  if (verbose)
    1702                    WARN ((stderr, "\n%s: %s: decompression OK, trailing zero bytes ignored\n",
    1703                           program_name, ifname));
    1704                  return -3;
    1705                }
    1706            }
    1707  
    1708          WARN((stderr, "\n%s: %s: decompression OK, trailing garbage ignored\n",
    1709                program_name, ifname));
    1710          return -2;
    1711      }
    1712  }
    1713  
    1714  /* ========================================================================
    1715   * Display the characteristics of the compressed file.
    1716   * If the given method is < 0, display the accumulated totals.
    1717   * IN assertions: time_stamp, header_bytes and ifile_size are initialized.
    1718   */
    1719  static void
    1720  do_list (int method)
    1721  {
    1722      ulg crc;  /* original crc */
    1723      static int first_time = 1;
    1724      static char const *const methods[MAX_METHODS] = {
    1725          "store",  /* 0 */
    1726          "compr",  /* 1 */
    1727          "pack ",  /* 2 */
    1728          "lzh  ",  /* 3 */
    1729          "", "", "", "", /* 4 to 7 reserved */
    1730          "defla"}; /* 8 */
    1731      int positive_off_t_width = INT_STRLEN_BOUND (off_t) - 1;
    1732  
    1733      if (first_time && method >= 0) {
    1734          first_time = 0;
    1735          if (verbose)  {
    1736              printf("method  crc     date  time  ");
    1737          }
    1738          if (!quiet) {
    1739              printf("%*.*s %*.*s  ratio uncompressed_name\n",
    1740                     positive_off_t_width, positive_off_t_width, "compressed",
    1741                     positive_off_t_width, positive_off_t_width, "uncompressed");
    1742          }
    1743      } else if (method < 0) {
    1744          if (total_in <= 0 || total_out <= 0) return;
    1745          if (verbose) {
    1746              printf("                            ");
    1747          }
    1748          if (verbose || !quiet) {
    1749              fprint_off(stdout, total_in, positive_off_t_width);
    1750              printf(" ");
    1751              fprint_off(stdout, total_out, positive_off_t_width);
    1752              printf(" ");
    1753          }
    1754          display_ratio(total_out-(total_in-header_bytes), total_out, stdout);
    1755          /* header_bytes is not meaningful but used to ensure the same
    1756           * ratio if there is a single file.
    1757           */
    1758          printf(" (totals)\n");
    1759          return;
    1760      }
    1761      crc = (ulg)~0; /* unknown */
    1762  
    1763      if (method == DEFLATED && !last_member) {
    1764        crc = unzip_crc;
    1765      }
    1766  
    1767      if (verbose)
    1768        {
    1769          static char const month_abbr[][4]
    1770            = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
    1771                "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
    1772          struct tm *tm = localtime (&time_stamp.tv_sec);
    1773          printf ("%5s %08lx ", methods[method], crc);
    1774          if (tm)
    1775            printf ("%s%3d %02d:%02d ", month_abbr[tm->tm_mon],
    1776                    tm->tm_mday, tm->tm_hour, tm->tm_min);
    1777          else
    1778            printf ("??? ?? ??:?? ");
    1779        }
    1780      fprint_off(stdout, bytes_in, positive_off_t_width);
    1781      printf(" ");
    1782      fprint_off(stdout, bytes_out, positive_off_t_width);
    1783      printf(" ");
    1784      if (bytes_in  == -1L) {
    1785          total_in = -1L;
    1786          bytes_in = bytes_out = header_bytes = 0;
    1787      } else if (total_in >= 0) {
    1788          total_in  += bytes_in;
    1789      }
    1790      if (bytes_out == -1L) {
    1791          total_out = -1L;
    1792          bytes_in = bytes_out = header_bytes = 0;
    1793      } else if (total_out >= 0) {
    1794          total_out += bytes_out;
    1795      }
    1796      display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out, stdout);
    1797      printf(" %s\n", ofname);
    1798  }
    1799  
    1800  /* ========================================================================
    1801   * Shorten the given name by one character, or replace a .tar extension
    1802   * with .tgz. Truncate the last part of the name which is longer than
    1803   * MIN_PART characters: 1234.678.012.gz -> 123.678.012.gz. If the name
    1804   * has only parts shorter than MIN_PART truncate the longest part.
    1805   * For decompression, just remove the last character of the name.
    1806   *
    1807   * IN assertion: for compression, the suffix of the given name is z_suffix.
    1808   */
    1809  static void
    1810  shorten_name (char *name)
    1811  {
    1812      int len;                 /* length of name without z_suffix */
    1813      char *trunc = NULL;      /* character to be truncated */
    1814      int plen;                /* current part length */
    1815      int min_part = MIN_PART; /* current minimum part length */
    1816      char *p;
    1817  
    1818      len = strlen(name);
    1819      if (decompress) {
    1820          if (len <= 1)
    1821            gzip_error ("name too short");
    1822          name[len-1] = '\0';
    1823          return;
    1824      }
    1825      p = get_suffix(name);
    1826      if (! p)
    1827        gzip_error ("can't recover suffix\n");
    1828      *p = '\0';
    1829      save_orig_name = 1;
    1830  
    1831      /* compress 1234567890.tar to 1234567890.tgz */
    1832      if (len > 4 && strequ(p-4, ".tar")) {
    1833          strcpy(p-4, ".tgz");
    1834          return;
    1835      }
    1836      /* Try keeping short extensions intact:
    1837       * 1234.678.012.gz -> 123.678.012.gz
    1838       */
    1839      do {
    1840          p = last_component (name);
    1841          while (*p) {
    1842              plen = strcspn(p, PART_SEP);
    1843              p += plen;
    1844              if (plen > min_part) trunc = p-1;
    1845              if (*p) p++;
    1846          }
    1847      } while (trunc == NULL && --min_part != 0);
    1848  
    1849      if (trunc != NULL) {
    1850          do {
    1851              trunc[0] = trunc[1];
    1852          } while (*trunc++);
    1853          trunc--;
    1854      } else {
    1855          trunc = strrchr(name, PART_SEP[0]);
    1856          if (!trunc)
    1857            gzip_error ("internal error in shorten_name");
    1858          if (trunc[1] == '\0') trunc--; /* force truncation */
    1859      }
    1860      strcpy(trunc, z_suffix);
    1861  }
    1862  
    1863  /* ========================================================================
    1864   * The compressed file already exists, so ask for confirmation.
    1865   * Return ERROR if the file must be skipped.
    1866   */
    1867  static int
    1868  check_ofname ()
    1869  {
    1870      /* Ask permission to overwrite the existing file */
    1871      if (!force) {
    1872          int ok = 0;
    1873          fprintf (stderr, "%s: %s already exists;", program_name, ofname);
    1874          if (foreground && (presume_input_tty || isatty (STDIN_FILENO))) {
    1875              fprintf(stderr, " do you wish to overwrite (y or n)? ");
    1876              fflush(stderr);
    1877              ok = yesno();
    1878          }
    1879          if (!ok) {
    1880              fprintf(stderr, "\tnot overwritten\n");
    1881              if (exit_code == OK) exit_code = WARNING;
    1882              return ERROR;
    1883          }
    1884      }
    1885      if (xunlink (ofname)) {
    1886          progerror(ofname);
    1887          return ERROR;
    1888      }
    1889      return OK;
    1890  }
    1891  
    1892  /* Change the owner and group of a file.  FD is a file descriptor for
    1893     the file and NAME its name.  Change it to user UID and to group GID.
    1894     If UID or GID is -1, though, do not change the corresponding user
    1895     or group.  */
    1896  #if ! (HAVE_FCHOWN || HAVE_CHOWN)
    1897  /* The types uid_t and gid_t do not exist on mingw, so don't assume them.  */
    1898  # define do_chown(fd, name, uid, gid) ((void) 0)
    1899  #else
    1900  static void
    1901  do_chown (int fd, char const *name, uid_t uid, gid_t gid)
    1902  {
    1903  # if HAVE_FCHOWN
    1904    ignore_value (fchown (fd, uid, gid));
    1905  # else
    1906    ignore_value (chown (name, uid, gid));
    1907  # endif
    1908  }
    1909  #endif
    1910  
    1911  /* ========================================================================
    1912   * Copy modes, times, ownership from input file to output file.
    1913   * IN assertion: to_stdout is false.
    1914   */
    1915  static void
    1916  copy_stat (struct stat *ifstat)
    1917  {
    1918      mode_t mode = ifstat->st_mode & S_IRWXUGO;
    1919      int r;
    1920  
    1921  #ifndef NO_UTIME
    1922      bool restoring;
    1923      struct timespec timespec[2];
    1924      timespec[0] = get_stat_atime (ifstat);
    1925      timespec[1] = get_stat_mtime (ifstat);
    1926      restoring = (decompress && 0 <= time_stamp.tv_nsec
    1927                   && ! (timespec[1].tv_sec == time_stamp.tv_sec
    1928                         && timespec[1].tv_nsec == time_stamp.tv_nsec));
    1929      if (restoring)
    1930        timespec[1] = time_stamp;
    1931  
    1932      if (fdutimens (ofd, ofname, timespec) == 0)
    1933        {
    1934          if (restoring && 1 < verbose) {
    1935              fprintf(stderr, "%s: timestamp restored\n", ofname);
    1936          }
    1937        }
    1938      else
    1939        WARN ((stderr, "%s: %s: %s\n", program_name, ofname, strerror (errno)));
    1940  #endif
    1941  
    1942      /* Change the group first, then the permissions, then the owner.
    1943         That way, the permissions will be correct on systems that allow
    1944         users to give away files, without introducing a security hole.
    1945         Security depends on permissions not containing the setuid or
    1946         setgid bits.  */
    1947  
    1948      do_chown (ofd, ofname, -1, ifstat->st_gid);
    1949  
    1950  #if HAVE_FCHMOD
    1951      r = fchmod (ofd, mode);
    1952  #else
    1953      r = chmod (ofname, mode);
    1954  #endif
    1955      if (r != 0)
    1956        WARN ((stderr, "%s: %s: %s\n", program_name, ofname, strerror (errno)));
    1957  
    1958      do_chown (ofd, ofname, ifstat->st_uid, -1);
    1959  }
    1960  
    1961  #if ! NO_DIR
    1962  
    1963  /* ========================================================================
    1964   * Recurse through the given directory.
    1965   */
    1966  static void
    1967  treat_dir (int fd, char *dir)
    1968  {
    1969      DIR      *dirp;
    1970      char     nbuf[MAX_PATH_LEN];
    1971      char *entries;
    1972      char const *entry;
    1973      size_t entrylen;
    1974  
    1975      dirp = fdopendir (fd);
    1976  
    1977      if (dirp == NULL) {
    1978          progerror(dir);
    1979          close (fd);
    1980          return ;
    1981      }
    1982  
    1983      entries = streamsavedir (dirp, SAVEDIR_SORT_NONE);
    1984      if (! entries)
    1985        progerror (dir);
    1986      if (closedir (dirp) != 0)
    1987        progerror (dir);
    1988      if (! entries)
    1989        return;
    1990  
    1991      for (entry = entries; *entry; entry += entrylen + 1) {
    1992          size_t len = strlen (dir);
    1993          entrylen = strlen (entry);
    1994          if (strequ (entry, ".") || strequ (entry, ".."))
    1995            continue;
    1996          if (len + entrylen < MAX_PATH_LEN - 2) {
    1997              strcpy(nbuf,dir);
    1998              if (*last_component (nbuf) && !ISSLASH (nbuf[len - 1]))
    1999                nbuf[len++] = '/';
    2000              strcpy (nbuf + len, entry);
    2001              treat_file(nbuf);
    2002          } else {
    2003              fprintf(stderr,"%s: %s/%s: pathname too long\n",
    2004                      program_name, dir, entry);
    2005              exit_code = ERROR;
    2006          }
    2007      }
    2008      free (entries);
    2009  }
    2010  #endif /* ! NO_DIR */
    2011  
    2012  /* Make sure signals get handled properly.  */
    2013  
    2014  static void
    2015  install_signal_handlers ()
    2016  {
    2017    int nsigs = sizeof handled_sig / sizeof handled_sig[0];
    2018    int i;
    2019    struct sigaction act;
    2020  
    2021    sigemptyset (&caught_signals);
    2022    for (i = 0; i < nsigs; i++)
    2023      {
    2024        sigaction (handled_sig[i], NULL, &act);
    2025        if (act.sa_handler != SIG_IGN)
    2026          sigaddset (&caught_signals, handled_sig[i]);
    2027      }
    2028  
    2029    act.sa_handler = abort_gzip_signal;
    2030    act.sa_mask = caught_signals;
    2031    act.sa_flags = 0;
    2032  
    2033    for (i = 0; i < nsigs; i++)
    2034      if (sigismember (&caught_signals, handled_sig[i]))
    2035        {
    2036          if (i == 0)
    2037            foreground = 1;
    2038          sigaction (handled_sig[i], &act, NULL);
    2039        }
    2040  }
    2041  
    2042  /* ========================================================================
    2043   * Free all dynamically allocated variables and exit with the given code.
    2044   */
    2045  static void
    2046  do_exit (int exitcode)
    2047  {
    2048      static int in_exit = 0;
    2049  
    2050      if (in_exit) exit(exitcode);
    2051      in_exit = 1;
    2052      free(env);
    2053      env  = NULL;
    2054      FREE(inbuf);
    2055      FREE(outbuf);
    2056      FREE(d_buf);
    2057      FREE(window);
    2058  #ifndef MAXSEG_64K
    2059      FREE(tab_prefix);
    2060  #else
    2061      FREE(tab_prefix0);
    2062      FREE(tab_prefix1);
    2063  #endif
    2064      exit(exitcode);
    2065  }
    2066  
    2067  static void
    2068  finish_out ()
    2069  {
    2070    if (fclose (stdout) != 0)
    2071      write_error ();
    2072    do_exit (OK);
    2073  }
    2074  
    2075  /* ========================================================================
    2076   * Close and unlink the output file.
    2077   */
    2078  static void
    2079  remove_output_file (bool signals_already_blocked)
    2080  {
    2081    int fd;
    2082    sigset_t oldset;
    2083  
    2084    if (!signals_already_blocked)
    2085      sigprocmask (SIG_BLOCK, &caught_signals, &oldset);
    2086    fd = remove_ofname_fd;
    2087    if (0 <= fd)
    2088      {
    2089        char fname[MAX_PATH_LEN];
    2090        remove_ofname_fd = -1;
    2091        close (fd);
    2092        volatile_strcpy (fname, remove_ofname);
    2093        xunlink (fname);
    2094      }
    2095    if (!signals_already_blocked)
    2096      sigprocmask (SIG_SETMASK, &oldset, NULL);
    2097  }
    2098  
    2099  /* ========================================================================
    2100   * Error handler.
    2101   */
    2102  void
    2103  finish_up_gzip (int exitcode)
    2104  {
    2105    if (0 <= remove_ofname_fd)
    2106      remove_output_file (false);
    2107    do_exit (exitcode);
    2108  }
    2109  void
    2110  abort_gzip ()
    2111  {
    2112    finish_up_gzip (ERROR);
    2113  }
    2114  /* ========================================================================
    2115   * Signal handler.
    2116   */
    2117  static void
    2118  abort_gzip_signal (int sig)
    2119  {
    2120     remove_output_file (true);
    2121     signal (sig, SIG_DFL);
    2122     raise (sig);
    2123  }