From 60b82b59a729d2a4322c3305d7207ce027831e23 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Mon, 13 Sep 2010 15:55:34 -0400 Subject: [PATCH] sponge: Guarantee that output file is always updated atomically, by renaming a temp file into place. Closes: #592144 --- debian/changelog | 2 ++ sponge.c | 27 +++++---------------------- sponge.docbook | 3 ++- 3 files changed, 9 insertions(+), 23 deletions(-) diff --git a/debian/changelog b/debian/changelog index 1d6c0e5..ae71b8c 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,6 +1,8 @@ moreutils (0.42) UNRELEASED; urgency=low * Typo. Closes: #596032 + * sponge: Guarantee that output file is always updated atomically, + by renaming a temp file into place. Closes: #592144 -- Joey Hess Wed, 08 Sep 2010 02:09:29 -0400 diff --git a/sponge.c b/sponge.c index 242298d..ea343d0 100644 --- a/sponge.c +++ b/sponge.c @@ -262,6 +262,7 @@ int main (int argc, char **argv) { FILE *outfile, *tmpfile = 0; ssize_t i = 0; size_t mem_available = default_sponge_size(); + struct stat statbuf; if (argc > 2 || (argc == 2 && strcmp(argv[1], "-h") == 0)) { usage(); @@ -269,7 +270,8 @@ int main (int argc, char **argv) { if (argc == 2) { outname = argv[1]; } - + + tmpfile = open_tmpfile(); bufstart = buf = malloc(bufsize); if (!buf) { perror("failed to allocate memory"); @@ -279,9 +281,6 @@ int main (int argc, char **argv) { bufused = bufused+i; if (bufused == bufsize) { if ((bufsize*2) >= mem_available) { - if (!tmpfile) { - tmpfile=open_tmpfile(); - } write_buff_tmp(bufstart, bufused, tmpfile); bufused = 0; } @@ -300,8 +299,6 @@ int main (int argc, char **argv) { perror("failed to read from stdin"); exit(1); } - if (tmpfile) { - struct stat statbuf; /* write whatever we have in memory to tmpfile */ if (bufused) @@ -319,6 +316,7 @@ int main (int argc, char **argv) { ! S_ISLNK(statbuf.st_mode) ) || errno == ENOENT) && rename(tmpname, outname) == 0) { + tmpname=NULL; /* Fix renamed file mode to match either * the old file mode, or the default file * mode for a newly created file. */ @@ -345,26 +343,11 @@ int main (int argc, char **argv) { exit(1); } copy_tmpfile(tmpfile, outfile, bufstart, bufsize); + fclose(outfile); } else { copy_tmpfile(tmpfile, stdout, bufstart, bufsize); } - } - else { - if (outname) { - outfile = fopen(outname, "w"); - if (!outfile) { - perror("error opening output file"); - exit(1); - } - } - else { - outfile = stdout; - } - if (bufused) - write_buff_out(bufstart, bufused, outfile); - fclose(outfile); - } return 0; } diff --git a/sponge.docbook b/sponge.docbook index 24c432a..ab2c42d 100644 --- a/sponge.docbook +++ b/sponge.docbook @@ -58,7 +58,8 @@ USA redirect, sponge soaks up all its input before opening the output file. This allows constricting pipelines that read from and write to - the same file. + the same file. It also creates the output file + atomically by renaming a temp file into place. If no output file is specified, sponge outputs to stdout. -- 2.39.5