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) */
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[] =
{
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. */
{"-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 */
{"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 }
};
#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",
recursive = 1;
#endif
break;
+
+ case RSYNCABLE_OPTION:
+ case RSYNCABLE_OPTION + ENV_OPTION:
+ rsync = 1;
+ break;
case 'S':
#ifdef NO_MULTIPLE_DOTS
if (*optarg == '.') optarg++;
z_len = strlen(optarg);
z_suffix = optarg;
break;
+ case SYNCHRONOUS_OPTION:
+ synchronous = true;
+ break;
case 't':
test = decompress = to_stdout = 1;
break;
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 */
}
{
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)
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 ("??? ?? ??:?? ");