gzip: new option --synchronous
authorPaul Eggert <eggert@cs.ucla.edu>
Sun, 28 Feb 2016 07:58:54 +0000 (23:58 -0800)
committerPaul Eggert <eggert@cs.ucla.edu>
Sun, 28 Feb 2016 08:02:57 +0000 (00:02 -0800)
This follows up on the earlier patch to avoid data loss near the
system crashes.  It makes the new behavior optional, with the
default off.  See: http://bugs.gnu.org/22768
* NEWS, doc/gzip.texi (Sample, Invoking gzip), gunzip.in (usage):
* gzip.1, zcat.in (usage):
Document this.
* gzip.c (synchronous): New static var.
(SYNCHRONOUS_OPTION): New constant.
(longopts, help, main, treat_file): Add support for --synchronous.

NEWS
doc/gzip.texi
gunzip.in
gzip.1
gzip.c
zcat.in

diff --git a/NEWS b/NEWS
index 31472cc65da920c5e741d3d4630ac76bd94f41a7..a3989afa6e81ad8e83571169e99556751a6010f4 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -4,14 +4,18 @@ GNU gzip NEWS                                    -*- outline -*-
 
 ** Changes in behavior
 
-  When acting in-place, gzip now fsyncs the output before closing it.
-  This is slower, but on many file systems it is safer if the system
-  is about to crash.
-
   The GZIP environment variable is now obsolescent; gzip now warns if
   it is used, and rejects attempts to use dangerous options or operands.
   You can use an alias or script instead.
 
+** New features
+
+  gzip now accepts the --synchronous option, which causes it to use
+  fsync and similar primitives to transfer output data to the output
+  file's storage device when the file system supports this.  Although
+  this option makes gzip safer in the presence of system crashes, it
+  can make gzip considerably slower.
+
 ** Bug fixes
 
   gzip -k -v no longer reports that files are replaced.
index 978b9198da00a93a03124a9a628162a35d8895f8..fa94b84ae53fd0336b85b367ca4f11f99123dadc 100644 (file)
@@ -204,6 +204,7 @@ Mandatory arguments to long options are mandatory for short options too.
   -q, --quiet       suppress all warnings
   -r, --recursive   operate recursively on directories
   -S, --suffix=SUF  use suffix SUF on compressed files
+      --synchronous synchronous output (safer if system crashes, but slower)
   -t, --test        test compressed file integrity
   -v, --verbose     verbose mode
   -V, --version     display version number
@@ -374,6 +375,16 @@ gunzip -S "" *        (*.* for MSDOS)
 Previous versions of gzip used the @samp{.z} suffix.  This was changed to
 avoid a conflict with @command{pack}.
 
+@item --synchronous
+Use synchronous output, by transferring output data to the output
+file's storage device when the file system supports this.  Because
+file system data can be cached, without this option if the system
+crashes around the time a command like @samp{gzip FOO} is run the user
+might lose both @file{FOO} and @file{FOO.gz}; this is the default with
+@command{gzip}, just as it is the default with most applications that
+move data.  When this option is used, @command{gzip} is safer but can
+be considerably slower.
+
 @item --test
 @itemx -t
 Test.  Check the compressed file integrity.
index 12968340ceeb7e8a01c11bd9833aefd86a7e0241..d0efd2d86306cb424aa88c3d1d4ad3c0b5ad4fbe 100644 (file)
--- a/gunzip.in
+++ b/gunzip.in
@@ -45,6 +45,7 @@ Mandatory arguments to long options are mandatory for short options too.
   -q, --quiet       suppress all warnings
   -r, --recursive   operate recursively on directories
   -S, --suffix=SUF  use suffix SUF on compressed files
+      --synchronous synchronous output (safer if system crashes, but slower)
   -t, --test        test compressed file integrity
   -v, --verbose     verbose mode
       --help        display this help and exit
diff --git a/gzip.1 b/gzip.1
index 07995ea99366a1ae049e1e79168804b099734a62..3262a8788507450cb484bf2be9aeff73576cb2e1 100644 (file)
--- a/gzip.1
+++ b/gzip.1
@@ -296,6 +296,12 @@ are transferred to other systems.
 When decompressing, add .suf to the beginning of the list of
 suffixes to try, when deriving an output file name from an input file name.
 .TP
+.B --synchronous
+Use synchronous output.  With this option,
+.I gzip
+is less likely to lose data during a system crash, but it can be
+considerably slower.
+.TP
 .B \-t --test
 Test. Check the compressed file integrity.
 .TP
diff --git a/gzip.c b/gzip.c
index 6cfc561c3f1fb04562fb132867dc394d7579464b..d9cdfaa5ac51df572db2d3c06e261355fde66e39 100644 (file)
--- a/gzip.c
+++ b/gzip.c
@@ -159,6 +159,14 @@ DECLARE(uch, window, 2L*WSIZE);
    is deliberately not documented, and only for testing.  */
 static bool presume_input_tty;
 
+/* If true, transfer output data to the output file's storage device
+   when supported.  Otherwise, if the system crashes around the time
+   gzip is run, the user might lose both input and output data.  See:
+   Pillai TS et al.  All file systems are not created equal: on the
+   complexity of crafting crash-consistent applications. OSDI'14. 2014:433-48.
+   https://www.usenix.org/conference/osdi14/technical-sessions/presentation/pillai */
+static bool synchronous;
+
 static int ascii = 0;        /* convert end-of-lines to local OS conventions */
        int to_stdout = 0;    /* output to stdout (-c) */
 static int decompress = 0;   /* decompress (-d) */
@@ -240,6 +248,7 @@ static int handled_sig[] =
 enum
 {
   PRESUME_INPUT_TTY_OPTION = CHAR_MAX + 1,
+  SYNCHRONOUS_OPTION,
 
   /* A value greater than all valid long options, used as a flag to
      distinguish options derived from the GZIP environment variable.  */
@@ -268,6 +277,7 @@ static const struct option longopts[] =
     {"-presume-input-tty", no_argument, NULL, PRESUME_INPUT_TTY_OPTION},
     {"quiet",      0, 0, 'q'}, /* quiet mode */
     {"silent",     0, 0, 'q'}, /* quiet mode */
+    {"synchronous",0, 0, SYNCHRONOUS_OPTION},
     {"recursive",  0, 0, 'r'}, /* recurse through directories */
     {"suffix",     1, 0, 'S'}, /* use given suffix instead of .gz */
     {"test",       0, 0, 't'}, /* test compressed file integrity */
@@ -353,6 +363,7 @@ local void help()
  "  -r, --recursive   operate recursively on directories",
 #endif
  "  -S, --suffix=SUF  use suffix SUF on compressed files",
+ "      --synchronous synchronous output (safer if system crashes, but slower)",
  "  -t, --test        test compressed file integrity",
  "  -v, --verbose     verbose mode",
  "  -V, --version     display version number",
@@ -551,6 +562,9 @@ int main (int argc, char **argv)
             z_len = strlen(optarg);
             z_suffix = optarg;
             break;
+        case SYNCHRONOUS_OPTION:
+            synchronous = true;
+            break;
         case 't':
             test = decompress = to_stdout = 1;
             break;
@@ -645,6 +659,12 @@ int main (int argc, char **argv)
     if (list && !quiet && file_count > 1) {
         do_list(-1, -1); /* print totals */
     }
+    if (to_stdout
+        && ((synchronous
+             && (fdatasync (STDOUT_FILENO) != 0 && errno != EINVAL))
+            || close (STDOUT_FILENO) != 0)
+        && errno != EBADF)
+      write_error ();
     do_exit(exit_code);
     return exit_code; /* just to avoid lint warning */
 }
@@ -972,13 +992,7 @@ local void treat_file(iname)
       {
         copy_stat (&istat);
 
-        /* If KEEP, transfer output data to the output file's storage device.
-           Otherwise, if the system crashed now the user might lose
-           both input and output data.  See: Pillai TS et al.  All
-           file systems are not created equal: on the complexity of
-           crafting crash-consistent applications. OSDI'14. 2014:433-48.
-           https://www.usenix.org/conference/osdi14/technical-sessions/presentation/pillai  */
-        if ((!keep
+        if ((synchronous
              && ((0 <= dfd && fdatasync (dfd) != 0 && errno != EINVAL)
                  || (fsync (ofd) != 0 && errno != EINVAL)))
             || close (ofd) != 0)
diff --git a/zcat.in b/zcat.in
index be6577f5c9c5fc8676cd4759f5d0581296b2a3e8..75660e504b35c69025400b181ea42a3cdfb22013 100644 (file)
--- a/zcat.in
+++ b/zcat.in
@@ -39,6 +39,7 @@ Uncompress FILEs to standard output.
   -q, --quiet       suppress all warnings
   -r, --recursive   operate recursively on directories
   -S, --suffix=SUF  use suffix SUF on compressed files
+      --synchronous synchronous output (safer if system crashes, but slower)
   -t, --test        test compressed file integrity
   -v, --verbose     verbose mode
       --help        display this help and exit