This is a backport of the fix itself. From 768901548e280726f160a1da4434f3fde8f9921a Mon Sep 17 00:00:00 2001 From: Jim Meyering Date: Sat, 9 May 2015 19:47:08 -0700 Subject: [PATCH 84/92] sed -i: don't leave behind a temporary sedXXXXXX file For example, running a command like "sed -i s//b/ F" would fail to remove a temporary file named sedXXXXXX (for random XXXXXX) in the directory alongside F. * sed/sed.c (G_file_to_unlink): New global. (register_cleanup_file, cancel_cleanup, cleanup): New functions. (main): Call atexit. * sed/execute.c (open_next_file): Register for unlink. (closedown): Call cancel_cleanup right after the rename. * sed/sed.h: Declare two of the new functions. * NEWS (Bug fixes): Mention it. * testsuite/temp-file-cleanup.sh: New file. Test for this. * testsuite/Makefile.am (T): Add it. Reported by David Jones in http://bugs.gnu.org/20002. --- NEWS | 4 ++++ sed/execute.c | 2 ++ sed/sed.c | 35 ++++++++++++++++++++++++++++++++++- sed/sed.h | 2 ++ testsuite/Makefile.am | 3 ++- testsuite/temp-file-cleanup.sh | 38 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 82 insertions(+), 2 deletions(-) create mode 100755 testsuite/temp-file-cleanup.sh Index: sed-4.2.2/sed/execute.c =================================================================== --- sed-4.2.2.orig/sed/execute.c +++ sed-4.2.2/sed/execute.c @@ -656,6 +656,7 @@ open_next_file(name, input) output_file.fp = ck_mkstemp (&input->out_file_name, tmpdir, "sed", write_mode); + register_cleanup_file (input->out_file_name); output_file.missing_newline = false; free (tmpdir); @@ -713,6 +714,7 @@ closedown(input) } ck_rename (input->out_file_name, target_name, input->out_file_name); + cancel_cleanup (); free (input->out_file_name); } else Index: sed-4.2.2/sed/sed.c =================================================================== --- sed-4.2.2.orig/sed/sed.c +++ sed-4.2.2/sed/sed.c @@ -69,6 +69,35 @@ countT lcmd_out_line_len = 70; /* The complete compiled SED program that we are going to run: */ static struct vector *the_program = NULL; +/* When we've created a temporary for an in-place update, + we may have to exit before the rename. This is the name + of the temporary that we'll have to unlink via an atexit- + registered cleanup function. */ +static char const *G_file_to_unlink; + +/* When exiting between temporary file creation and the rename + associated with a sed -i invocation, remove that file. */ +static void +cleanup (void) +{ + if (G_file_to_unlink) + unlink (G_file_to_unlink); +} + +/* Note that FILE must be removed upon exit. */ +void +register_cleanup_file (char const *file) +{ + G_file_to_unlink = file; +} + +/* Clear the global file-to-unlink global. */ +void +cancel_cleanup (void) +{ + G_file_to_unlink = NULL; +} + static void usage (int); static void contact(errmsg) @@ -200,6 +229,10 @@ main(argc, argv) #endif initialize_mbcs (); + /* Arrange to remove any un-renamed temporary file, + upon premature exit. */ + atexit (cleanup); + #if ENABLE_NLS /* Tell program which translations to use and where to find. */ Index: sed-4.2.2/sed/sed.h =================================================================== --- sed-4.2.2.orig/sed/sed.h +++ sed-4.2.2/sed/sed.h @@ -262,4 +262,6 @@ extern bool is_utf8; extern int brlen (int ch, mbstate_t *ps); extern void initialize_mbcs (void); +extern void register_cleanup_file (char const *file); +extern void cancel_cleanup (void);