Skip to content

Commit

Permalink
git-apply: improve error detection and messages
Browse files Browse the repository at this point in the history
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).
  • Loading branch information
Linus Torvalds committed May 23, 2005
1 parent 5e224a2 commit 46979f5
Showing 1 changed file with 74 additions and 42 deletions.
116 changes: 74 additions & 42 deletions apply.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
static int merge_patch = 1;
static const char apply_usage[] = "git-apply <patch>";

static int linenr = 1;

#define CHUNKSIZE (8192)

static void *read_patch_file(int fd, unsigned long *sizep)
Expand Down Expand Up @@ -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;
Expand All @@ -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);
Expand All @@ -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;

Expand Down Expand Up @@ -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
Expand All @@ -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);
Expand Down Expand Up @@ -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);

Expand Down

0 comments on commit 46979f5

Please sign in to comment.