]> git.cworth.org Git - gzip/blobdiff - gzip.c
Imported Debian patch 1.3.5-10sarge1
[gzip] / gzip.c
diff --git a/gzip.c b/gzip.c
index b18a0a9103a90c2813fa3261a930ef9b2d7c2f83..2f692b5658327d6e33ee21abcfe0ce53709a9647 100644 (file)
--- a/gzip.c
+++ b/gzip.c
@@ -1,5 +1,5 @@
 /* gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
- * Copyright (C) 1999, 2001 Free Software Foundation, Inc.
+ * Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
  * Copyright (C) 1992-1993 Jean-loup Gailly
  * The unzip code was written and put in the public domain by Mark Adler.
  * Portions of the lzw code are derived from the public domain 'compress'
@@ -11,7 +11,7 @@
  */
 
 static char  *license_msg[] = {
-"Copyright 2001 Free Software Foundation",
+"Copyright 2002 Free Software Foundation",
 "Copyright 1992-1993 Jean-loup Gailly",
 "This program comes with ABSOLUTELY NO WARRANTY.",
 "You may redistribute copies of this program",
@@ -103,6 +103,9 @@ static char rcsid[] = "$Id: gzip.c,v 0.24 1993/06/24 10:52:07 jloup Exp $";
 #    define DIR_OPT "NO_DIR"
 #  endif
 #endif
+#ifndef NO_DIR
+# define NO_DIR 0
+#endif
 
 #ifdef CLOSEDIR_VOID
 # define CLOSEDIR(d) (closedir(d), 0)
@@ -110,6 +113,10 @@ static char rcsid[] = "$Id: gzip.c,v 0.24 1993/06/24 10:52:07 jloup Exp $";
 # define CLOSEDIR(d) closedir(d)
 #endif
 
+#if !defined(HAVE_LSTAT) && !defined(lstat)
+# define lstat(name, buf) stat(name, buf)
+#endif
+
 #ifdef HAVE_UTIME
 #  ifdef HAVE_UTIME_H
 #    include <utime.h>
@@ -234,7 +241,7 @@ 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) */
-int  z_len;           /* strlen(z_suffix) */
+size_t z_len;         /* strlen(z_suffix) */
 
 off_t bytes_in;             /* number of input bytes */
 off_t bytes_out;            /* number of output bytes */
@@ -249,6 +256,7 @@ 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 */
 
 struct option longopts[] =
 {
@@ -278,6 +286,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 }
 };
 
@@ -306,7 +315,7 @@ local void do_exit      OF((int exitcode));
       int main          OF((int argc, char **argv));
 int (*work) OF((int infile, int outfile)) = zip; /* function to call */
 
-#ifndef NO_DIR
+#if ! NO_DIR
 local void treat_dir    OF((char *dir));
 #endif
 #ifdef HAVE_UTIME
@@ -320,17 +329,7 @@ local void usage()
 {
     printf ("usage: %s [-%scdfhlLnN%stvV19] [-S suffix] [file ...]\n",
            progname,
-#if O_BINARY
-           "a",
-#else
-           "",
-#endif
-#ifdef NO_DIR
-           ""
-#else
-           "r"
-#endif
-           );
+           O_BINARY ? "a" : "", NO_DIR ? "" : "r");
 }
 
 /* ======================================================================== */
@@ -355,7 +354,7 @@ local void help()
  " -n --no-name     do not save or restore the original name and time stamp",
  " -N --name        save or restore the original name and time stamp",
  " -q --quiet       suppress all warnings",
-#ifndef NO_DIR
+#if ! NO_DIR
  " -r --recursive   operate recursively on directories",
 #endif
  " -S .suf  --suffix .suf     use suffix .suf on compressed files",
@@ -368,6 +367,7 @@ local void help()
  " -Z --lzw         produce output compatible with old compress",
  " -b --bits maxbits   max number of bits per code (implies -Z)",
 #endif
+ "    --rsyncable   Make rsync-friendly archive",
  " file...          files to (de)compress. If none given, use standard input.",
  "Report bugs to <bug-gzip@gnu.org>.",
   0};
@@ -467,16 +467,16 @@ int main (argc, argv)
 
     foreground = signal(SIGINT, SIG_IGN) != SIG_IGN;
     if (foreground) {
-       (void) signal (SIGINT, (sig_type)abort_gzip);
+       (void) signal (SIGINT, (sig_type)abort_gzip_signal);
     }
 #ifdef SIGTERM
     if (signal(SIGTERM, SIG_IGN) != SIG_IGN) {
-       (void) signal(SIGTERM, (sig_type)abort_gzip);
+       (void) signal(SIGTERM, (sig_type)abort_gzip_signal);
     }
 #endif
 #ifdef SIGHUP
     if (signal(SIGHUP, SIG_IGN) != SIG_IGN) {
-       (void) signal(SIGHUP,  (sig_type)abort_gzip);
+       (void) signal(SIGHUP,  (sig_type)abort_gzip_signal);
     }
 #endif
 
@@ -539,13 +539,16 @@ int main (argc, argv)
        case 'q':
            quiet = 1; verbose = 0; break;
        case 'r':
-#ifdef NO_DIR
+#if NO_DIR
            fprintf(stderr, "%s: -r not supported on this system\n", progname);
            usage();
            do_exit(ERROR); break;
 #else
            recursive = 1; break;
 #endif
+       case 'R':
+           rsync = 1; break;
+
        case 'S':
 #ifdef NO_MULTIPLE_DOTS
             if (*optarg == '.') optarg++;
@@ -583,7 +586,7 @@ int main (argc, argv)
 #ifdef SIGPIPE
     /* Ignore "Broken Pipe" message with --quiet */
     if (quiet && signal (SIGPIPE, SIG_IGN) != SIG_IGN)
-      signal (SIGPIPE, (sig_type) abort_gzip);
+      signal (SIGPIPE, (sig_type) abort_gzip_signal);
 #endif
 
     /* By default, save name and timestamp on compression but do not
@@ -603,7 +606,7 @@ int main (argc, argv)
 #endif
     if ((z_len == 0 && !decompress) || z_len > MAX_SUFFIX) {
         fprintf(stderr, "%s: incorrect suffix '%s'\n",
-                progname, optarg);
+                progname, z_suffix);
         do_exit(ERROR);
     }
     if (do_lzw && !decompress) work = lzw;
@@ -773,7 +776,7 @@ local void treat_file(iname)
 
     /* If the input name is that of a directory, recurse or ignore: */
     if (S_ISDIR(istat.st_mode)) {
-#ifndef NO_DIR
+#if ! NO_DIR
        if (recursive) {
            struct stat st;
            st = istat;
@@ -878,8 +881,11 @@ local void treat_file(iname)
     }
 
     close(ifd);
-    if (!to_stdout && close(ofd)) {
-       write_error();
+    if (!to_stdout) {
+         /* Copy modes, times, ownership, and remove the input file */
+         copy_stat(&istat);
+         if (close(ofd))
+            write_error();
     }
     if (method == -1) {
        if (!to_stdout) xunlink (ofname);
@@ -899,10 +905,6 @@ local void treat_file(iname)
        }
        fprintf(stderr, "\n");
     }
-    /* Copy modes, times, ownership, and remove the input file */
-    if (!to_stdout) {
-       copy_stat(&istat);
-    }
 }
 
 /* ========================================================================
@@ -976,11 +978,9 @@ local int do_stat(name, sbuf)
     struct stat *sbuf;
 {
     errno = 0;
-#ifdef HAVE_LSTAT
     if (!to_stdout && !force) {
        return lstat(name, sbuf);
     }
-#endif
     return stat(name, sbuf);
 }
 
@@ -1322,6 +1322,7 @@ local int get_method(in)
                /* Copy the base name. Keep a directory prefix intact. */
                 char *p = base_name (ofname);
                 char *base = p;
+               char *base2;
                for (;;) {
                    *p = (char)get_char();
                    if (*p++ == '\0') break;
@@ -1329,6 +1330,8 @@ local int get_method(in)
                        error("corrupted input -- file name too large");
                    }
                }
+               base2 = base_name (base);
+               strcpy(base, base2);
                 /* If necessary, adapt the name to local OS conventions: */
                 if (!list) {
                    MAKE_LEGAL_NAME(base);
@@ -1543,7 +1546,7 @@ local int name_too_long(name, statb)
 
     tstat = *statb;      /* Just in case OS does not fill all fields */
     name[s-1] = '\0';
-    res = stat(name, &tstat) == 0 && same_file(statb, &tstat);
+    res = lstat(name, &tstat) == 0 && same_file(statb, &tstat);
     name[s-1] = c;
     Trace((stderr, " too_long(%s) => %d\n", name, res));
     return res;
@@ -1633,12 +1636,12 @@ local int check_ofname()
      * instead of silently truncating filenames).
      */
     errno = 0;
-    while (stat(ofname, &ostat) != 0) {
+    while (lstat(ofname, &ostat) != 0) {
         if (errno != ENAMETOOLONG) return 0; /* ofname does not exist */
        shorten_name(ofname);
     }
 #else
-    if (stat(ofname, &ostat) != 0) return 0;
+    if (lstat(ofname, &ostat) != 0) return 0;
 #endif
     /* Check for name truncation on existing file. Do this even on systems
      * defining ENAMETOOLONG, because on most systems the strict Posix
@@ -1646,7 +1649,7 @@ local int check_ofname()
      */
     if (!decompress && name_too_long(ofname, &ostat)) {
        shorten_name(ofname);
-       if (stat(ofname, &ostat) != 0) return 0;
+       if (lstat(ofname, &ostat) != 0) return 0;
     }
 
     /* Check that the input and output files are different (could be
@@ -1730,7 +1733,7 @@ local void copy_stat(ifstat)
     reset_times(ofname, ifstat);
 #endif
     /* Copy the protection modes */
-    if (chmod(ofname, ifstat->st_mode & 07777)) {
+    if (fchmod(ofd, ifstat->st_mode & 07777)) {
        int e = errno;
        WARN((stderr, "%s: ", progname));
        if (!quiet) {
@@ -1739,7 +1742,7 @@ local void copy_stat(ifstat)
        }
     }
 #ifndef NO_CHOWN
-    chown(ofname, ifstat->st_uid, ifstat->st_gid);  /* Copy ownership */
+    fchown(ofd, ifstat->st_uid, ifstat->st_gid);  /* Copy ownership */
 #endif
     remove_ofname = 0;
     /* It's now safe to remove the input file: */
@@ -1753,7 +1756,7 @@ local void copy_stat(ifstat)
     }
 }
 
-#ifndef NO_DIR
+#if ! NO_DIR
 
 /* ========================================================================
  * Recurse through the given directory. This code is taken from ncompress.
@@ -1819,7 +1822,7 @@ local void treat_dir(dir)
     if (CLOSEDIR(dirp) != 0)
        progerror(dir);
 }
-#endif /* ? NO_DIR */
+#endif /* ! NO_DIR */
 
 /* ========================================================================
  * Free all dynamically allocated variables and exit with the given code.
@@ -1847,13 +1850,31 @@ local void do_exit(exitcode)
 }
 
 /* ========================================================================
- * Signal and error handler.
+ * Close and unlink the output file if appropriate.  This routine must be
+ * async-signal-safe.
  */
-RETSIGTYPE abort_gzip()
-{
+local void do_remove() {
    if (remove_ofname) {
        close(ofd);
        xunlink (ofname);
    }
-   do_exit(ERROR);
 }
+
+/* ========================================================================
+ * Error handler.
+ */
+RETSIGTYPE abort_gzip()
+{
+       do_remove();
+       do_exit(ERROR);
+}
+
+/* ========================================================================
+ * Signal handler.
+ */
+RETSIGTYPE abort_gzip_signal()
+{
+       do_remove();
+       _exit(ERROR);
+}
+