Skip to content

Commit 80226b5

Browse files
committed
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.
1 parent 3892f70 commit 80226b5

File tree

3 files changed

+32
-0
lines changed

3 files changed

+32
-0
lines changed

src/patch_parse.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,22 @@ static int parse_header_start(git_patch_parsed *patch, git_patch_parse_ctx *ctx)
321321
return git_parse_err("corrupt new path in git diff header at line %"PRIuZ,
322322
ctx->parse_ctx.line_num);
323323

324+
/*
325+
* We cannot expect to be able to always parse paths correctly at this
326+
* point. Due to the possibility of unquoted names, whitespaces in
327+
* filenames and custom prefixes we have to allow that, though, and just
328+
* proceeed here. We then hope for the "---" and "+++" lines to fix that
329+
* for us.
330+
*/
331+
if (!git_parse_ctx_contains(&ctx->parse_ctx, "\n", 1)) {
332+
git_parse_advance_chars(&ctx->parse_ctx, ctx->parse_ctx.line_len - 1);
333+
334+
git__free(patch->header_old_path);
335+
patch->header_old_path = NULL;
336+
git__free(patch->header_new_path);
337+
patch->header_new_path = NULL;
338+
}
339+
324340
return 0;
325341
}
326342

tests/patch/parse.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,3 +102,9 @@ void test_patch_parse__invalid_patches_fails(void)
102102
strlen(PATCH_CORRUPT_MISSING_HUNK_HEADER), NULL));
103103
}
104104

105+
void test_patch_parse__files_with_whitespaces_succeeds(void)
106+
{
107+
git_patch *patch;
108+
cl_git_pass(git_patch_from_buffer(&patch, PATCH_NAME_WHITESPACE, strlen(PATCH_NAME_WHITESPACE), NULL));
109+
git_patch_free(patch);
110+
}

tests/patch/patch_common.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -575,6 +575,16 @@
575575
"+added line with no nl\n" \
576576
"\\ No newline at end of file\n"
577577

578+
#define PATCH_NAME_WHITESPACE \
579+
"diff --git a/file with spaces.txt b/file with spaces.txt\n" \
580+
"index 9432026..83759c0 100644\n" \
581+
"--- a/file with spaces.txt\n" \
582+
"+++ b/file with spaces.txt\n" \
583+
"@@ -0,3 +0,2 @@\n" \
584+
" and this\n" \
585+
"-is additional context\n" \
586+
" below it!\n" \
587+
578588
#define PATCH_CORRUPT_GIT_HEADER \
579589
"diff --git a/file.txt\n" \
580590
"index 9432026..0f39b9a 100644\n" \

0 commit comments

Comments
 (0)