Port to Oracle Solaris Studio 12.4
[debian/gzip] / gzip.c
diff --git a/gzip.c b/gzip.c
index 15bcf78f2da9258b4560fbf1d9d470fbda0ff4a1..d66530a70bdce1d19a2687658e9ef0b9f19a1e18 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) */
@@ -212,6 +220,7 @@ static int dfd = -1;       /* output directory 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[] =
   {
@@ -240,6 +249,8 @@ static int handled_sig[] =
 enum
 {
   PRESUME_INPUT_TTY_OPTION = CHAR_MAX + 1,
+  RSYNCABLE_OPTION,
+  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 +279,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 */
@@ -278,7 +290,7 @@ static const 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, RSYNCABLE_OPTION}, /* make rsync-friendly archive */
     { 0, 0, 0, 0 }
 };
 
@@ -352,7 +364,9 @@ local void help()
 #if ! NO_DIR
  "  -r, --recursive   operate recursively on directories",
 #endif
+ "      --rsyncable   make rsync-friendly archive",
  "  -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",
@@ -544,6 +558,11 @@ int main (int argc, char **argv)
             recursive = 1;
 #endif
             break;
+
+        case RSYNCABLE_OPTION:
+        case RSYNCABLE_OPTION + ENV_OPTION:
+            rsync = 1;
+            break;
         case 'S':
 #ifdef NO_MULTIPLE_DOTS
             if (*optarg == '.') optarg++;
@@ -551,6 +570,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;
@@ -634,7 +656,7 @@ int main (int argc, char **argv)
     /* And get to work */
     if (file_count != 0) {
         if (to_stdout && !test && !list && (!decompress || !ascii)) {
-            SET_BINARY_MODE(fileno(stdout));
+            SET_BINARY_MODE (STDOUT_FILENO);
         }
         while (optind < argc) {
             treat_file(argv[optind++]);
@@ -645,6 +667,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 */
 }
@@ -675,7 +703,7 @@ local void treat_stdin()
 {
     if (!force && !list
         && (presume_input_tty
-            || isatty(fileno((FILE *)(decompress ? stdin : stdout))))) {
+            || isatty (decompress ? STDIN_FILENO : STDOUT_FILENO))) {
         /* Do not send compressed data to the terminal or read it from
          * the terminal. We get here when user invoked the program
          * without parameters, so be helpful. According to the GNU standards:
@@ -701,16 +729,16 @@ local void treat_stdin()
     }
 
     if (decompress || !ascii) {
-        SET_BINARY_MODE(fileno(stdin));
+      SET_BINARY_MODE (STDIN_FILENO);
     }
     if (!test && !list && (!decompress || !ascii)) {
-        SET_BINARY_MODE(fileno(stdout));
+      SET_BINARY_MODE (STDOUT_FILENO);
     }
     strcpy(ifname, "stdin");
     strcpy(ofname, "stdout");
 
     /* Get the file's time stamp and size.  */
-    if (fstat (fileno (stdin), &istat) != 0)
+    if (fstat (STDIN_FILENO, &istat) != 0)
       {
         progerror ("standard input");
         do_exit (ERROR);
@@ -728,7 +756,7 @@ local void treat_stdin()
     clear_bufs(); /* clear input and output buffers */
     to_stdout = 1;
     part_nb = 0;
-    ifd = fileno(stdin);
+    ifd = STDIN_FILENO;
 
     if (decompress) {
         method = get_method(ifd);
@@ -744,7 +772,8 @@ local void treat_stdin()
     /* Actually do the compression/decompression. Loop over zipped members.
      */
     for (;;) {
-        if ((*work)(fileno(stdin), fileno(stdout)) != OK) return;
+        if (work (STDIN_FILENO, STDOUT_FILENO) != OK)
+          return;
 
         if (input_eof ())
           break;
@@ -931,7 +960,7 @@ local void treat_file(iname)
      * a new ofname and save the original name in the compressed file.
      */
     if (to_stdout) {
-        ofd = fileno(stdout);
+        ofd = STDOUT_FILENO;
         /* Keep remove_ofname_fd negative.  */
     } else {
         if (create_outfile() != OK) return;
@@ -971,13 +1000,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)
@@ -1630,7 +1653,7 @@ local int get_method(in)
             inptr--;
         last_member = 1;
         if (imagic0 != EOF) {
-            write_buf(fileno(stdout), magic, 1);
+            write_buf (STDOUT_FILENO, magic, 1);
             bytes_out++;
         }
     }
@@ -1740,12 +1763,13 @@ local void do_list(ifd, method)
 
     if (verbose)
       {
+        static char const month_abbr[][4]
+          = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+              "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
         struct tm *tm = localtime (&time_stamp.tv_sec);
         printf ("%5s %08lx ", methods[method], crc);
         if (tm)
-          printf ("%s%3d %02d:%02d ",
-                  ("Jan\0Feb\0Mar\0Apr\0May\0Jun\0Jul\0Aug\0Sep\0Oct\0Nov\0Dec"
-                   + 4 * tm->tm_mon),
+          printf ("%s%3d %02d:%02d ", month_abbr[tm->tm_mon],
                   tm->tm_mday, tm->tm_hour, tm->tm_min);
         else
           printf ("??? ?? ??:?? ");
@@ -1844,7 +1868,7 @@ local int check_ofname()
     if (!force) {
         int ok = 0;
         fprintf (stderr, "%s: %s already exists;", program_name, ofname);
-        if (foreground && (presume_input_tty || isatty(fileno(stdin)))) {
+        if (foreground && (presume_input_tty || isatty (STDIN_FILENO))) {
             fprintf(stderr, " do you wish to overwrite (y or n)? ");
             fflush(stderr);
             ok = yesno();