From 46979f567bde4c299fa18fdc72180361511b0057 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 23 May 2005 14:38:49 -0700 Subject: git-apply: improve error detection and messages In particular, give line numbers when detecting corrupt patches. This makes the tool a lot more friendly (indeed, much more so than regular "patch", I think). --- apply.c | 116 +++++++++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 74 insertions(+), 42 deletions(-) (limited to 'apply.c') diff --git a/apply.c b/apply.c index 536b068292..05f921a311 100644 --- a/apply.c +++ b/apply.c @@ -21,6 +21,8 @@ static int merge_patch = 1; static const char apply_usage[] = "git-apply "; +static int linenr = 1; + #define CHUNKSIZE (8192) static void *read_patch_file(int fd, unsigned long *sizep) @@ -77,7 +79,7 @@ static int parse_git_header(char *line, unsigned int size) { unsigned long offset, len; - for (offset = 0 ; size > 0 ; offset += len, size -= len, line += len) { + for (offset = 0 ; size > 0 ; offset += len, size -= len, line += len, linenr++) { len = linelen(line, size); if (!len) break; @@ -104,11 +106,60 @@ static int parse_git_header(char *line, unsigned int size) return offset ? :-1; } +static int parse_num(const char *line, int len, int offset, const char *expect, unsigned long *p) +{ + char *ptr; + int digits, ex; + + if (offset < 0 || offset >= len) + return -1; + line += offset; + len -= offset; + + if (!isdigit(*line)) + return -1; + *p = strtoul(line, &ptr, 10); + + digits = ptr - line; + + offset += digits; + line += digits; + len -= digits; + + ex = strlen(expect); + if (ex > len) + return -1; + if (memcmp(line, expect, ex)) + return -1; + + return offset + ex; +} + +/* + * Parse a unified diff fragment header of the + * form "@@ -a,b +c,d @@" + */ +static int parse_fragment_header(char *line, int len, unsigned long *pos) +{ + int offset; + + if (!len || line[len-1] != '\n') + return -1; + + /* Figure out the number of lines in a fragment */ + offset = parse_num(line, len, 4, ",", pos); + offset = parse_num(line, len, offset, " +", pos+1); + offset = parse_num(line, len, offset, ",", pos+2); + offset = parse_num(line, len, offset, " @@", pos+3); + + return offset; +} + static int find_header(char *line, unsigned long size, int *hdrsize) { unsigned long offset, len; - for (offset = 0; size > 0; offset += len, size -= len, line += len) { + for (offset = 0; size > 0; offset += len, size -= len, line += len, linenr++) { unsigned long nextlen; len = linelen(line, size); @@ -118,6 +169,19 @@ static int find_header(char *line, unsigned long size, int *hdrsize) /* Testing this early allows us to take a few shortcuts.. */ if (len < 6) continue; + + /* + * Make sure we don't find any unconnected patch fragmants. + * That's a sign that we didn't find a header, and that a + * patch has become corrupted/broken up. + */ + if (!memcmp("@@ -", line, 4)) { + unsigned long pos[4]; + if (parse_fragment_header(line, len, pos) < 0) + continue; + error("patch fragment without header at line %d: %.*s", linenr, len-1, line); + } + if (size < len + 6) break; @@ -149,40 +213,12 @@ static int find_header(char *line, unsigned long size, int *hdrsize) /* Ok, we'll consider it a patch */ *hdrsize = len + nextlen; + linenr += 2; return offset; } return -1; } -static int parse_num(const char *line, int len, int offset, const char *expect, unsigned long *p) -{ - char *ptr; - int digits, ex; - - if (offset < 0 || offset >= len) - return -1; - line += offset; - len -= offset; - - if (!isdigit(*line)) - return -1; - *p = strtoul(line, &ptr, 10); - - digits = ptr - line; - - offset += digits; - line += digits; - len -= digits; - - ex = strlen(expect); - if (ex > len) - return -1; - if (memcmp(line, expect, ex)) - return -1; - - return offset + ex; -} - /* * Parse a unified diff. Note that this really needs * to parse each fragment separately, since the only @@ -193,23 +229,19 @@ static int parse_num(const char *line, int len, int offset, const char *expect, static int apply_fragment(char *line, unsigned long size) { int len = linelen(line, size), offset; - unsigned long oldpos, oldlines, newpos, newlines; + unsigned long pos[4], oldlines, newlines; - if (!len || line[len-1] != '\n') - return -1; - - /* Figure out the number of lines in a fragment */ - offset = parse_num(line, len, 4, ",", &oldpos); - offset = parse_num(line, len, offset, " +", &oldlines); - offset = parse_num(line, len, offset, ",", &newpos); - offset = parse_num(line, len, offset, " @@", &newlines); + offset = parse_fragment_header(line, len, pos); if (offset < 0) return -1; + oldlines = pos[1]; + newlines = pos[3]; /* Parse the thing.. */ line += len; size -= len; - for (offset = len; size > 0; offset += len, size -= len, line += len) { + linenr++; + for (offset = len; size > 0; offset += len, size -= len, line += len, linenr++) { if (!oldlines && !newlines) break; len = linelen(line, size); @@ -240,7 +272,7 @@ static int apply_single_patch(char *line, unsigned long size) while (size > 4 && !memcmp(line, "@@ -", 4)) { int len = apply_fragment(line, size); if (len <= 0) - die("corrupt patch"); + die("corrupt patch at line %d", linenr); printf("applying fragment:\n%.*s\n\n", len, line); -- cgit v1.2.3