From c8367d7660239b1aedce7850c766c0c0f8938d1c Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Mon, 22 Feb 2016 23:21:49 -0800 Subject: [PATCH] fsync output file before closing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem reported by Yanyan Jiang 蒋炎岩 in: http://bugs.gnu.org/22768 * NEWS: Document this. * bootstrap.conf (gnulib_modules): Add fsync. * gzip.c (treat_file): Call fsync just before closing the output. * lib/.gitignore, m4/.gitignore: Add fsync-related gnulib files. --- NEWS | 4 ++++ bootstrap.conf | 1 + gzip.c | 11 ++++++++++- lib/.gitignore | 1 + m4/.gitignore | 1 + 5 files changed, 17 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index a1c668f..31472cc 100644 --- a/NEWS +++ b/NEWS @@ -4,6 +4,10 @@ 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. diff --git a/bootstrap.conf b/bootstrap.conf index 13a485d..b15caa3 100644 --- a/bootstrap.conf +++ b/bootstrap.conf @@ -31,6 +31,7 @@ fcntl-safer fdl fdopendir fprintf-posix +fsync getopt-gnu git-version-gen gitlog-to-changelog diff --git a/gzip.c b/gzip.c index a013540..b872383 100644 --- a/gzip.c +++ b/gzip.c @@ -926,8 +926,17 @@ local void treat_file(iname) if (!to_stdout) { - copy_stat (&istat); + + /* 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 && fsync (ofd) != 0 && errno != EINVAL) + write_error (); + if (close (ofd) != 0) write_error (); diff --git a/lib/.gitignore b/lib/.gitignore index 81d94ff..a368a26 100644 --- a/lib/.gitignore +++ b/lib/.gitignore @@ -225,3 +225,4 @@ /xsize.h /yesno.c /yesno.h +/fsync.c diff --git a/m4/.gitignore b/m4/.gitignore index 660b926..32f5566 100644 --- a/m4/.gitignore +++ b/m4/.gitignore @@ -150,3 +150,4 @@ /xalloc.m4 /xsize.m4 /yesno.m4 +/fsync.m4 -- 2.5.0