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;
/* 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++]);
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 */
}
{
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:
}
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);
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);
/* 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;
* 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;
{
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)
inptr--;
last_member = 1;
if (imagic0 != EOF) {
- write_buf(fileno(stdout), magic, 1);
+ write_buf (STDOUT_FILENO, magic, 1);
bytes_out++;
}
}
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 ("??? ?? ??:?? ");
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();