summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Gruenbacher <agruen@gnu.org>2016-07-19 22:40:40 +0200
committerAndreas Gruenbacher <agruen@gnu.org>2016-07-27 15:47:47 +0200
commit66fdcf0e7c83a1e2eb4db97b9e24f224db656b65 (patch)
treee283ff870ab72a93f3cb05f1205a0ebe0361655c
parent83a3ed012c677df484a892af69dbca8963867cb3 (diff)
downloadpatch-66fdcf0e7c83a1e2eb4db97b9e24f224db656b65.tar.gz
Fix broken git-style patch behavior
When a git-syle patch is applied, all file modifications are done to temporary files which are put in place when the patch ends. When a patch fails, GNU patch was trying to "roll back" to the start. A bug in that code that lead to accidental file deletion was recently discovered by Richard Weinberger <richard@nod.at>. Even worse though, GNU patch should not exhibit this "rollback" behavior in the first place; that's not what people expect. Instead, the files modified so far should be put in place. * src/patch.c (cleanup): Put output files processed successfully in place instead of trying to "roll back" to the start. (forget_output_files): Remove obsolete (and broken) function. * tests/git-cleanup: New broken git-style patch test case that exercises the cleanup path. * tests/Makefile.am (TESTS): Add new test case.
-rw-r--r--src/patch.c18
-rw-r--r--tests/Makefile.am1
-rw-r--r--tests/git-cleanup75
3 files changed, 77 insertions, 17 deletions
diff --git a/src/patch.c b/src/patch.c
index b0ed91a..bf7e5c2 100644
--- a/src/patch.c
+++ b/src/patch.c
@@ -1966,22 +1966,6 @@ output_files (struct stat const *st)
gl_list_clear (files_to_output);
}
-static void
-forget_output_files (void)
-{
- gl_list_iterator_t iter = gl_list_iterator (files_to_output);
- const void *elt;
-
- while (gl_list_iterator_next (&iter, &elt, NULL))
- {
- const struct file_to_output *file_to_output = elt;
-
- safe_unlink (file_to_output->from);
- }
- gl_list_iterator_free (&iter);
- gl_list_clear (files_to_output);
-}
-
/* Fatal exit with cleanup. */
void
@@ -2012,5 +1996,5 @@ cleanup (void)
remove_if_needed (TMPOUTNAME, &TMPOUTNAME_needs_removal);
remove_if_needed (TMPPATNAME, &TMPPATNAME_needs_removal);
remove_if_needed (TMPREJNAME, &TMPREJNAME_needs_removal);
- forget_output_files ();
+ output_files (NULL);
}
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 6d167bd..61a4ab8 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -36,6 +36,7 @@ TESTS = \
file-modes \
filename-choice \
git-binary-diff \
+ git-cleanup \
garbage \
global-reject-files \
inname \
diff --git a/tests/git-cleanup b/tests/git-cleanup
new file mode 100644
index 0000000..a71be97
--- /dev/null
+++ b/tests/git-cleanup
@@ -0,0 +1,75 @@
+# Copyright (C) 2009, 2011-2016 Free Software Foundation, Inc.
+#
+# Copying and distribution of this file, with or without modification,
+# in any medium, are permitted without royalty provided the copyright
+# notice and this notice are preserved.
+
+. $srcdir/test-lib.sh
+
+require cat
+use_local_patch
+use_tmpdir
+
+# ==============================================================
+
+cat > 1.diff <<EOF
+diff --git a/f b/f
+--- f
++++ f
+@@ -1 +1 @@
+-1
++1a
+@@ -5 +5 @@
+-out
++in
+diff --git a/g b/g
+--- g
++++ g
+@@ -1 +1 @@
+-out
++in
+diff --git a/h b/h
+--- h
++++ h
+@@ -1 +1 @@
+BAD PATCH
+EOF
+
+echo 1 > f
+echo -n '' > g
+echo -n '' > h
+
+check 'patch -f -i 1.diff || echo status: $?' <<EOF
+patching file f
+Hunk #2 FAILED at 5.
+1 out of 2 hunks FAILED -- saving rejects to file f.rej
+patching file g
+Hunk #1 FAILED at 1.
+1 out of 1 hunk FAILED -- saving rejects to file g.rej
+patching file h
+/home/agruenba/git/patch/src/patch: **** malformed patch at line 20: BAD PATCH
+
+status: 2
+EOF
+
+check 'cat f' <<EOF
+1a
+EOF
+
+check 'cat f.rej' <<EOF
+--- f
++++ f
+@@ -5 +5 @@
+-out
++in
+EOF
+
+ncheck 'cat g'
+
+check 'cat g.rej' <<EOF
+--- g
++++ g
+@@ -1 +1 @@
+-out
++in
+EOF