summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Steinhardt <ps@pks.im>2017-09-22 13:39:05 +0200
committerPatrick Steinhardt <ps@pks.im>2017-11-11 20:29:28 +0000
commit80226b5f674e6d04a4064ebc93c09fc667e8fa52 (patch)
tree536922594c92ca3fcbdbbd9e128eb6a268a2471a
parent3892f70d8e6e6c8483d2163763d9c8b98b6fbf0a (diff)
downloadlibgit2-80226b5f674e6d04a4064ebc93c09fc667e8fa52.tar.gz
patch_parse: allow parsing ambiguous patch headers
The git patch format allows for having unquoted paths with whitespaces inside. This format becomes ambiguous to parse, e.g. in the following example: diff --git a/file b/with spaces.txt b/file b/with spaces.txt While we cannot parse this in a correct way, we can instead use the "---" and "+++" lines to retrieve the file names, as the path is not followed by anything here but spans the complete remaining line. Because of this, we can simply bail outwhen parsing the "diff --git" header here without an actual error and then proceed to just take the paths from the other headers.
-rw-r--r--src/patch_parse.c16
-rw-r--r--tests/patch/parse.c6
-rw-r--r--tests/patch/patch_common.h10
3 files changed, 32 insertions, 0 deletions
diff --git a/src/patch_parse.c b/src/patch_parse.c
index 3a242b7a1..9ffe1f91c 100644
--- a/src/patch_parse.c
+++ b/src/patch_parse.c
@@ -321,6 +321,22 @@ static int parse_header_start(git_patch_parsed *patch, git_patch_parse_ctx *ctx)
return git_parse_err("corrupt new path in git diff header at line %"PRIuZ,
ctx->parse_ctx.line_num);
+ /*
+ * We cannot expect to be able to always parse paths correctly at this
+ * point. Due to the possibility of unquoted names, whitespaces in
+ * filenames and custom prefixes we have to allow that, though, and just
+ * proceeed here. We then hope for the "---" and "+++" lines to fix that
+ * for us.
+ */
+ if (!git_parse_ctx_contains(&ctx->parse_ctx, "\n", 1)) {
+ git_parse_advance_chars(&ctx->parse_ctx, ctx->parse_ctx.line_len - 1);
+
+ git__free(patch->header_old_path);
+ patch->header_old_path = NULL;
+ git__free(patch->header_new_path);
+ patch->header_new_path = NULL;
+ }
+
return 0;
}
diff --git a/tests/patch/parse.c b/tests/patch/parse.c
index 8350ac2dd..a40ad7b23 100644
--- a/tests/patch/parse.c
+++ b/tests/patch/parse.c
@@ -102,3 +102,9 @@ void test_patch_parse__invalid_patches_fails(void)
strlen(PATCH_CORRUPT_MISSING_HUNK_HEADER), NULL));
}
+void test_patch_parse__files_with_whitespaces_succeeds(void)
+{
+ git_patch *patch;
+ cl_git_pass(git_patch_from_buffer(&patch, PATCH_NAME_WHITESPACE, strlen(PATCH_NAME_WHITESPACE), NULL));
+ git_patch_free(patch);
+}
diff --git a/tests/patch/patch_common.h b/tests/patch/patch_common.h
index a20ebd617..e838e6089 100644
--- a/tests/patch/patch_common.h
+++ b/tests/patch/patch_common.h
@@ -575,6 +575,16 @@
"+added line with no nl\n" \
"\\ No newline at end of file\n"
+#define PATCH_NAME_WHITESPACE \
+ "diff --git a/file with spaces.txt b/file with spaces.txt\n" \
+ "index 9432026..83759c0 100644\n" \
+ "--- a/file with spaces.txt\n" \
+ "+++ b/file with spaces.txt\n" \
+ "@@ -0,3 +0,2 @@\n" \
+ " and this\n" \
+ "-is additional context\n" \
+ " below it!\n" \
+
#define PATCH_CORRUPT_GIT_HEADER \
"diff --git a/file.txt\n" \
"index 9432026..0f39b9a 100644\n" \