patch up the patch... sigh
[debian/gzip] / gzip.c
diff --git a/gzip.c b/gzip.c
index 1b5b3b2dba343df4ee5375ac2667682107584876..b867350f08ef11bc43ee344a64f2091c52b9dbe8 100644 (file)
--- a/gzip.c
+++ b/gzip.c
@@ -1,11 +1,12 @@
 /* gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
 
-   Copyright (C) 1999, 2001, 2002, 2006 Free Software Foundation, Inc.
+   Copyright (C) 1999, 2001-2002, 2006-2007, 2009-2010 Free Software
+   Foundation, Inc.
    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)
+   the Free Software Foundation; either version 3, or (at your option)
    any later version.
 
    This program is distributed in the hope that it will be useful,
@@ -27,8 +28,8 @@
  * See the file algorithm.doc for the compression algorithms and file formats.
  */
 
-static char  *license_msg[] = {
-"Copyright (C) 2006 Free Software Foundation, Inc.",
+static char const *const license_msg[] = {
+"Copyright (C) 2007 Free Software Foundation, Inc.",
 "Copyright (C) 1993 Jean-loup Gailly.",
 "This is free software.  You may redistribute copies of it under the terms of",
 "the GNU General Public License <http://www.gnu.org/licenses/gpl.html>.",
@@ -53,10 +54,6 @@ static char  *license_msg[] = {
  * For the meaning of all compilation flags, see comments in Makefile.in.
  */
 
-#ifdef RCSID
-static char rcsid[] = "$Id: gzip.c,v 1.11 2006/12/12 00:03:17 eggert Exp $";
-#endif
-
 #include <config.h>
 #include <ctype.h>
 #include <sys/types.h>
@@ -64,6 +61,7 @@ static char rcsid[] = "$Id: gzip.c,v 1.11 2006/12/12 00:03:17 eggert Exp $";
 #include <sys/stat.h>
 #include <errno.h>
 
+#include "closein.h"
 #include "tailor.h"
 #include "gzip.h"
 #include "lzw.h"
@@ -71,34 +69,16 @@ static char rcsid[] = "$Id: gzip.c,v 1.11 2006/12/12 00:03:17 eggert Exp $";
 
 #include "fcntl-safer.h"
 #include "getopt.h"
+#include "ignore-value.h"
 #include "stat-time.h"
-#include "timespec.h"
 
                /* configuration */
 
-#ifdef HAVE_TIME_H
-#  include <time.h>
-#else
-#  include <sys/time.h>
-#endif
-
-#ifdef HAVE_FCNTL_H
-#  include <fcntl.h>
-#endif
-
-#ifdef HAVE_LIMITS_H
-#  include <limits.h>
-#endif
-
-#ifdef HAVE_UNISTD_H
-#  include <unistd.h>
-#endif
-
-#if defined STDC_HEADERS || defined HAVE_STDLIB_H
-#  include <stdlib.h>
-#else
-   extern int errno;
-#endif
+#include <fcntl.h>
+#include <limits.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
 
 #ifndef NO_DIR
 # define NO_DIR 0
@@ -199,7 +179,7 @@ int verbose = 0;      /* be verbose (-v) */
 int quiet = 0;        /* be very quiet (-q) */
 int do_lzw = 0;       /* generate output compatible with old compress (-Z) */
 int test = 0;         /* test .gz file integrity */
-int foreground;       /* set if program run in foreground */
+int foreground = 0;   /* set if program run in foreground */
 char *program_name;   /* program name */
 int maxbits = BITS;   /* max bits per code for LZW */
 int method = DEFLATED;/* compression method */
@@ -212,13 +192,13 @@ struct timespec 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;       /* default suffix (can be set with --suffix) */
+char const *z_suffix; /* default suffix (can be set with --suffix) */
 size_t z_len;         /* strlen(z_suffix) */
 
 /* The set of signals that are caught.  */
 static sigset_t caught_signals;
 
-/* If nonzero then exit with status 1, rather than with the usual
+/* If nonzero then exit with status WARNING, rather than with the usual
    signal status, on receipt of a signal with this value.  This
    suppresses a "Broken Pipe" message with some shells.  */
 static int volatile exiting_signal;
@@ -238,6 +218,31 @@ int  ofd;                  /* output file descriptor */
 unsigned insize;           /* valid bytes in inbuf */
 unsigned inptr;            /* index of next byte to be processed in inbuf */
 unsigned outcnt;           /* bytes in output buffer */
+int rsync = 0;             /* make ryncable chunks */
+
+static int handled_sig[] =
+  {
+    /* SIGINT must be first, as 'foreground' depends on it.  */
+    SIGINT
+
+#ifdef SIGHUP
+    , SIGHUP
+#endif
+#ifdef SIGPIPE
+    , SIGPIPE
+#else
+# define SIGPIPE 0
+#endif
+#ifdef SIGTERM
+    , SIGTERM
+#endif
+#ifdef SIGXCPU
+    , SIGXCPU
+#endif
+#ifdef SIGXFSZ
+    , SIGXFSZ
+#endif
+  };
 
 struct option longopts[] =
 {
@@ -267,6 +272,7 @@ struct option longopts[] =
     {"best",       0, 0, '9'}, /* compress better */
     {"lzw",        0, 0, 'Z'}, /* make output compatible with old compress */
     {"bits",       1, 0, 'b'}, /* max number of bits per code (implies -Z) */
+    {"rsyncable",  0, 0, 'R'}, /* make rsync-friendly archive */
     { 0, 0, 0, 0 }
 };
 
@@ -312,7 +318,7 @@ try_help ()
 /* ======================================================================== */
 local void help()
 {
-    static char  *help_msg[] = {
+    static char const* const help_msg[] = {
  "Compress or uncompress FILEs (by default, compress FILES in-place).",
  "",
  "Mandatory arguments to long options are mandatory for short options too.",
@@ -348,12 +354,13 @@ local void help()
  "  -Z, --lzw         produce output compatible with old compress",
  "  -b, --bits=BITS   max number of bits per code (implies -Z)",
 #endif
+ "  --rsyncable       Make rsync-friendly archive",
  "",
  "With no FILE, or when FILE is -, read standard input.",
  "",
  "Report bugs to <bug-gzip@gnu.org>.",
   0};
-    char **p = help_msg;
+    char const *const *p = help_msg;
 
     printf ("Usage: %s [OPTION]... [FILE]...\n", program_name);
     while (*p) printf ("%s\n", *p++);
@@ -362,7 +369,7 @@ local void help()
 /* ======================================================================== */
 local void license()
 {
-    char **p = license_msg;
+    char const *const *p = license_msg;
 
     printf ("%s %s\n", program_name, VERSION);
     while (*p) printf ("%s\n", *p++);
@@ -376,8 +383,7 @@ local void version()
     printf ("Written by Jean-loup Gailly.\n");
 }
 
-local void progerror (string)
-    char *string;
+local void progerror (char const *string)
 {
     int e = errno;
     fprintf (stderr, "%s: ", program_name);
@@ -387,9 +393,7 @@ local void progerror (string)
 }
 
 /* ======================================================================== */
-int main (argc, argv)
-    int argc;
-    char **argv;
+int main (int argc, char **argv)
 {
     int file_count;     /* number of files to process */
     size_t proglen;     /* length of program_name */
@@ -400,6 +404,8 @@ int main (argc, argv)
     program_name = gzip_base_name (argv[0]);
     proglen = strlen (program_name);
 
+    atexit (close_stdin);
+
     /* Suppress .exe for MSDOS, OS/2 and VMS: */
     if (4 < proglen && strequ (program_name + proglen - 4, ".exe"))
       program_name[proglen - 4] = '\0';
@@ -409,8 +415,11 @@ int main (argc, argv)
     if (env != NULL) args = argv;
 
 #ifndef GNU_STANDARD
+# define GNU_STANDARD 1
+#endif
+#if !GNU_STANDARD
     /* For compatibility with old compress, use program name as an option.
-     * If you compile with -DGNU_STANDARD, this program will behave as
+     * Unless you compile with -DGNU_STANDARD=0, this program will behave as
      * gzip even if it is invoked under the name gunzip or zcat.
      *
      * Systems which do not support links can still use -d or -dc.
@@ -473,6 +482,9 @@ int main (argc, argv)
            recursive = 1;
 #endif
            break;
+        case 'R':
+           rsync = 1; break;
+
        case 'S':
 #ifdef NO_MULTIPLE_DOTS
             if (*optarg == '.') optarg++;
@@ -616,26 +628,21 @@ local void treat_stdin()
     strcpy(ifname, "stdin");
     strcpy(ofname, "stdout");
 
-    /* Get the time stamp on the input file. */
-    time_stamp.tv_nsec = -1;  /* The time is unknown by default.  */
-
-#ifndef NO_STDIN_FSTAT
-    if (list || !no_time) {
-       if (fstat(fileno(stdin), &istat) != 0) {
-           progerror("standard input");
-           do_exit(ERROR);
-       }
-# ifdef NO_PIPE_TIMESTAMP
-       if (S_ISREG(istat.st_mode))
-# endif
-           time_stamp = get_stat_mtime (&istat);
-#endif /* NO_STDIN_FSTAT */
-    }
-    ifile_size = -1L; /* convention for unknown size */
+    /* Get the file's time stamp and size.  */
+    if (fstat (fileno (stdin), &istat) != 0)
+      {
+       progerror ("standard input");
+       do_exit (ERROR);
+      }
+    ifile_size = S_ISREG (istat.st_mode) ? istat.st_size : -1;
+    time_stamp.tv_nsec = -1;
+    if (!no_time || list)
+      time_stamp = get_stat_mtime (&istat);
 
     clear_bufs(); /* clear input and output buffers */
     to_stdout = 1;
     part_nb = 0;
+    ifd = fileno(stdin);
 
     if (decompress) {
        method = get_method(ifd);
@@ -710,48 +717,57 @@ local void treat_file(iname)
               program_name, ifname));
        return;
     }
-    if (!S_ISREG(istat.st_mode)) {
-       WARN((stderr,
-             "%s: %s is not a directory or a regular file - ignored\n",
-             program_name, ifname));
-       close (ifd);
-       return;
-    }
 
-    if (istat.st_mode & S_ISUID)
-      {
-       WARN ((stderr, "%s: %s is set-user-ID on execution - ignored\n",
-              program_name, ifname));
-       close (ifd);
-       return;
-      }
-    if (istat.st_mode & S_ISGID)
+    if (! to_stdout)
       {
-       WARN ((stderr, "%s: %s is set-group-ID on execution - ignored\n",
-              program_name, ifname));
-       close (ifd);
-       return;
-      }
-    if (istat.st_mode & S_ISVTX)
-      {
-       WARN ((stderr, "%s: %s has the sticky bit set - file ignored\n",
-              program_name, ifname));
-       close (ifd);
-       return;
-      }
+       if (! S_ISREG (istat.st_mode))
+         {
+           WARN ((stderr,
+                  "%s: %s is not a directory or a regular file - ignored\n",
+                  program_name, ifname));
+           close (ifd);
+           return;
+         }
+       if (istat.st_mode & S_ISUID)
+         {
+           WARN ((stderr, "%s: %s is set-user-ID on execution - ignored\n",
+                  program_name, ifname));
+           close (ifd);
+           return;
+         }
+       if (istat.st_mode & S_ISGID)
+         {
+           WARN ((stderr, "%s: %s is set-group-ID on execution - ignored\n",
+                  program_name, ifname));
+           close (ifd);
+           return;
+         }
 
-    if (istat.st_nlink > 1 && !to_stdout && !force) {
-       WARN((stderr, "%s: %s has %lu other link%c -- unchanged\n",
-             program_name, ifname, (unsigned long) istat.st_nlink - 1,
-             istat.st_nlink > 2 ? 's' : ' '));
-       close (ifd);
-       return;
-    }
+       if (! force)
+         {
+           if (istat.st_mode & S_ISVTX)
+             {
+               WARN ((stderr,
+                      "%s: %s has the sticky bit set - file ignored\n",
+                      program_name, ifname));
+               close (ifd);
+               return;
+             }
+           if (2 <= istat.st_nlink)
+             {
+               WARN ((stderr, "%s: %s has %lu other link%c -- unchanged\n",
+                      program_name, ifname,
+                      (unsigned long int) istat.st_nlink - 1,
+                      istat.st_nlink == 2 ? ' ' : 's'));
+               close (ifd);
+               return;
+             }
+         }
+      }
 
-    ifile_size = istat.st_size;
-    if (no_time && !list)
-      time_stamp.tv_nsec = -1;
-    else
+    ifile_size = S_ISREG (istat.st_mode) ? istat.st_size : -1;
+    time_stamp.tv_nsec = -1;
+    if (!no_time || list)
       time_stamp = get_stat_mtime (&istat);
 
     /* Generate output file name. For -r and (-t or -l), skip files
@@ -949,13 +965,13 @@ 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[] =
+    static char const *known_suffixes[] =
        {NULL, ".gz", ".z", ".taz", ".tgz", "-gz", "-z", "_z",
 #ifdef MAX_EXT_CHARS
           "z",
 #endif
           NULL};
-    char **suf = known_suffixes;
+    char const **suf = known_suffixes;
 
     *suf = z_suffix;
     if (strequ(z_suffix, "z")) suf++; /* check long suffixes first */
@@ -1040,9 +1056,9 @@ open_input_file (iname, sbuf)
 {
     int ilen;  /* strlen(ifname) */
     int z_suffix_errno = 0;
-    static char *suffixes[] = {NULL, ".gz", ".z", "-z", ".Z", NULL};
-    char **suf = suffixes;
-    char *s;
+    static char const *suffixes[] = {NULL, ".gz", ".z", "-z", ".Z", NULL};
+    char const **suf = suffixes;
+    char const *s;
 #ifdef NO_MULTIPLE_DOTS
     char *dot; /* pointer to ifname extension, or NULL */
 #endif
@@ -1086,7 +1102,7 @@ open_input_file (iname, sbuf)
 
     /* Search for all suffixes */
     do {
-        char *s0 = s = *suf;
+        char const *s0 = s = *suf;
         strcpy (ifname, iname);
 #ifdef NO_MULTIPLE_DOTS
         if (*s == '.') s++;
@@ -1166,7 +1182,7 @@ local int make_ofname()
        }
         /* ofname might be changed later if infile contains an original name */
 
-    } else if (suff != NULL) {
+    } else if (suff && ! force) {
        /* Avoid annoying messages with -r (see treat_dir()) */
        if (verbose || (!recursive && !quiet)) {
            /* Don't use WARN, as it affects exit status.  */
@@ -1242,8 +1258,13 @@ local int get_method(in)
        /* 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 */
+       if (magic[0]) {
+           magic[1] = (char)get_byte();
+           imagic1 = 0; /* avoid lint warning */
+       } else {
+           imagic1 = try_byte ();
+           magic[1] = (char) imagic1;
+       }
     }
     method = -1;                 /* unknown yet */
     part_nb++;                   /* number of parts in gzip file */
@@ -1274,7 +1295,7 @@ local int get_method(in)
        }
        if ((flags & CONTINUATION) != 0) {
            fprintf(stderr,
-                   "%s: %s is a multi-part gzip file -- not supported\n",
+                   "%s: %s is a multi-part gzip file -- not supported\n",
                    program_name, ifname);
            exit_code = ERROR;
            if (force <= 1) return -1;
@@ -1422,7 +1443,7 @@ local void do_list(ifd, method)
 {
     ulg crc;  /* original crc */
     static int first_time = 1;
-    static char* methods[MAX_METHODS] = {
+    static char const *const methods[MAX_METHODS] = {
         "store",  /* 0 */
         "compr",  /* 1 */
         "pack ",  /* 2 */
@@ -1638,7 +1659,7 @@ local void copy_stat(ifstat)
        }
       }
 
-    if (futimens (ofd, ofname, timespec) != 0)
+    if (gl_futimens (ofd, ofname, timespec) != 0)
       {
        int e = errno;
        WARN ((stderr, "%s: ", program_name));
@@ -1651,10 +1672,11 @@ local void copy_stat(ifstat)
 #endif
 
 #ifndef NO_CHOWN
+    /* Copy ownership */
 # if HAVE_FCHOWN
-    fchown (ofd, ifstat->st_uid, ifstat->st_gid);  /* Copy ownership */
+    ignore_value (fchown (ofd, ifstat->st_uid, ifstat->st_gid));
 # elif HAVE_CHOWN
-    chown(ofname, ifstat->st_uid, ifstat->st_gid);  /* Copy ownership */
+    ignore_value (chown (ofname, ifstat->st_uid, ifstat->st_gid));
 # endif
 #endif
 
@@ -1688,18 +1710,11 @@ local void treat_dir (fd, dir)
     char     nbuf[MAX_PATH_LEN];
     int      len;
 
-#if HAVE_FDOPENDIR
     dirp = fdopendir (fd);
-#else
-    close (fd);
-    dirp = opendir(dir);
-#endif
 
     if (dirp == NULL) {
        progerror(dir);
-#if HAVE_FDOPENDIR
        close (fd);
-#endif
        return ;
     }
     /*
@@ -1756,30 +1771,7 @@ local void treat_dir (fd, dir)
 static void
 install_signal_handlers ()
 {
-  static int sig[] =
-    {
-      /* SIGINT must be first, as 'foreground' depends on it.  */
-      SIGINT
-
-#ifdef SIGHUP
-      , SIGHUP
-#endif
-#ifdef SIGPIPE
-      , SIGPIPE
-#else
-# define SIGPIPE 0
-#endif
-#ifdef SIGTERM
-      , SIGTERM
-#endif
-#ifdef SIGXCPU
-      , SIGXCPU
-#endif
-#ifdef SIGXFSZ
-      , SIGXFSZ
-#endif
-    };
-  int nsigs = sizeof sig / sizeof sig[0];
+  int nsigs = sizeof handled_sig / sizeof handled_sig[0];
   int i;
 
 #if SA_NOCLDSTOP
@@ -1788,9 +1780,9 @@ install_signal_handlers ()
   sigemptyset (&caught_signals);
   for (i = 0; i < nsigs; i++)
     {
-      sigaction (sig[i], NULL, &act);
+      sigaction (handled_sig[i], NULL, &act);
       if (act.sa_handler != SIG_IGN)
-       sigaddset (&caught_signals, sig[i]);
+       sigaddset (&caught_signals, handled_sig[i]);
     }
 
   act.sa_handler = abort_gzip_signal;
@@ -1798,20 +1790,20 @@ install_signal_handlers ()
   act.sa_flags = 0;
 
   for (i = 0; i < nsigs; i++)
-    if (sigismember (&caught_signals, sig[i]))
+    if (sigismember (&caught_signals, handled_sig[i]))
       {
        if (i == 0)
          foreground = 1;
-       sigaction (sig[i], &act, NULL);
+       sigaction (handled_sig[i], &act, NULL);
       }
 #else
   for (i = 0; i < nsigs; i++)
-    if (signal (sig[i], SIG_IGN) != SIG_IGN)
+    if (signal (handled_sig[i], SIG_IGN) != SIG_IGN)
       {
        if (i == 0)
          foreground = 1;
-       signal (sig[i], abort_gzip_signal);
-       siginterrupt (sig[i], 1);
+       signal (handled_sig[i], abort_gzip_signal);
+       siginterrupt (handled_sig[i], 1);
       }
 #endif
 }
@@ -1826,8 +1818,10 @@ local void do_exit(exitcode)
 
     if (in_exit) exit(exitcode);
     in_exit = 1;
-    if (env != NULL)  free(env),  env  = NULL;
-    if (args != NULL) free((char*)args), args = NULL;
+    free(env);
+    env  = NULL;
+    free(args);
+    args = NULL;
     FREE(inbuf);
     FREE(outbuf);
     FREE(d_buf);
@@ -1882,7 +1876,7 @@ abort_gzip_signal (sig)
     signal (sig, SIG_IGN);
    remove_output_file ();
    if (sig == exiting_signal)
-     _exit (ERROR);
+     _exit (WARNING);
    signal (sig, SIG_DFL);
    raise (sig);
 }