summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Steinhardt <ps@pks.im>2019-07-05 11:06:33 +0200
committerPatrick Steinhardt <ps@pks.im>2020-03-26 16:20:11 +0100
commitfe012c6018ed1f3ca41b998e2c0aa9a1a8d77c42 (patch)
tree0415ba0f3be7f60305a1b49d4c7aa278d044584f
parentb8339912db0a02091f630c083dc1f4c2cd02cb11 (diff)
downloadlibgit2-fe012c6018ed1f3ca41b998e2c0aa9a1a8d77c42.tar.gz
patch_parse: handle missing newline indicator in old file
When either the old or new file contents have no newline at the end of the file, then git-diff(1) will print out a "\ No newline at end of file" indicator. While we do correctly handle this in the case where the new file has this indcator, we fail to parse patches where the old file is missing a newline at EOF. Fix this bug by handling and missing newline indicators in the old file. Add tests to verify that we can parse such files.
-rw-r--r--src/patch_parse.c13
-rw-r--r--tests/patch/parse.c14
-rw-r--r--tests/patch/patch_common.h10
3 files changed, 36 insertions, 1 deletions
diff --git a/src/patch_parse.c b/src/patch_parse.c
index 25d9c2630..fdd1b9aeb 100644
--- a/src/patch_parse.c
+++ b/src/patch_parse.c
@@ -578,6 +578,16 @@ static int parse_hunk_body(
old_lineno = -1;
break;
+ case '\\':
+ /*
+ * If there are no oldlines left, then this is probably
+ * the "\ No newline at end of file" marker. Do not
+ * verify its format, as it may be localized.
+ */
+ if (!oldlines)
+ continue;
+ /* fall through */
+
default:
error = git_parse_err("invalid patch hunk at line %"PRIuZ, ctx->parse_ctx.line_num);
goto done;
@@ -606,7 +616,8 @@ static int parse_hunk_body(
goto done;
}
- /* Handle "\ No newline at end of file". Only expect the leading
+ /*
+ * Handle "\ No newline at end of file". Only expect the leading
* backslash, though, because the rest of the string could be
* localized. Because `diff` optimizes for the case where you
* want to apply the patch by hand.
diff --git a/tests/patch/parse.c b/tests/patch/parse.c
index 7eb987920..92f63b861 100644
--- a/tests/patch/parse.c
+++ b/tests/patch/parse.c
@@ -102,6 +102,20 @@ void test_patch_parse__invalid_patches_fails(void)
strlen(PATCH_CORRUPT_MISSING_HUNK_HEADER), NULL));
}
+void test_patch_parse__no_newline_at_end_of_new_file(void)
+{
+ git_patch *patch;
+ cl_git_pass(git_patch_from_buffer(&patch, PATCH_APPEND_NO_NL, strlen(PATCH_APPEND_NO_NL), NULL));
+ git_patch_free(patch);
+}
+
+void test_patch_parse__no_newline_at_end_of_old_file(void)
+{
+ git_patch *patch;
+ cl_git_pass(git_patch_from_buffer(&patch, PATCH_APPEND_NO_NL_IN_OLD_FILE, strlen(PATCH_APPEND_NO_NL_IN_OLD_FILE), NULL));
+ git_patch_free(patch);
+}
+
void test_patch_parse__files_with_whitespaces_succeeds(void)
{
git_patch *patch;
diff --git a/tests/patch/patch_common.h b/tests/patch/patch_common.h
index 291ece9eb..2db8d933f 100644
--- a/tests/patch/patch_common.h
+++ b/tests/patch/patch_common.h
@@ -681,6 +681,16 @@
"+added line with no nl\n" \
"\\ No newline at end of file\n"
+#define PATCH_APPEND_NO_NL_IN_OLD_FILE \
+ "diff --git a/file.txt b/file.txt\n" \
+ "index 9432026..83759c0 100644\n" \
+ "--- a/file.txt\n" \
+ "+++ b/file.txt\n" \
+ "@@ -1,1 +1,1 @@\n" \
+ "-foo\n" \
+ "\\ No newline at end of file\n" \
+ "+foo\n"
+
#define PATCH_NAME_WHITESPACE \
"diff --git a/file with spaces.txt b/file with spaces.txt\n" \
"index 9432026..83759c0 100644\n" \