summaryrefslogtreecommitdiff
path: root/apply.c
diff options
context:
space:
mode:
Diffstat (limited to 'apply.c')
-rw-r--r--apply.c62
1 files changed, 36 insertions, 26 deletions
diff --git a/apply.c b/apply.c
index c49cef0637..f2d599141d 100644
--- a/apply.c
+++ b/apply.c
@@ -8,6 +8,7 @@
*/
#include "cache.h"
+#include "config.h"
#include "blob.h"
#include "delta.h"
#include "diff.h"
@@ -210,6 +211,7 @@ struct patch {
unsigned ws_rule;
int lines_added, lines_deleted;
int score;
+ int extension_linenr; /* first line specifying delete/new/rename/copy */
unsigned int is_toplevel_relative:1;
unsigned int inaccurate_eof:1;
unsigned int is_binary:1;
@@ -762,17 +764,6 @@ static char *find_name_traditional(struct apply_state *state,
return find_name_common(state, line, def, p_value, line + len, 0);
}
-static int count_slashes(const char *cp)
-{
- int cnt = 0;
- char ch;
-
- while ((ch = *cp++))
- if (ch == '/')
- cnt++;
- return cnt;
-}
-
/*
* Given the string after "--- " or "+++ ", guess the appropriate
* p_value for the given patch.
@@ -971,13 +962,12 @@ static int gitdiff_verify_name(struct apply_state *state,
}
if (*name) {
- int len = strlen(*name);
char *another;
if (isnull)
return error(_("git apply: bad git-diff - expected /dev/null, got %s on line %d"),
*name, state->linenr);
another = find_name(state, line, NULL, state->p_value, TERM_TAB);
- if (!another || memcmp(another, *name, len + 1)) {
+ if (!another || strcmp(another, *name)) {
free(another);
return error((side == DIFF_NEW_NAME) ?
_("git apply: bad git-diff - inconsistent new filename on line %d") :
@@ -985,8 +975,7 @@ static int gitdiff_verify_name(struct apply_state *state,
}
free(another);
} else {
- /* expect "/dev/null" */
- if (memcmp("/dev/null", line, 9) || line[9] != '\n')
+ if (!starts_with(line, "/dev/null\n"))
return error(_("git apply: bad git-diff - expected /dev/null on line %d"), state->linenr);
}
@@ -1011,20 +1000,27 @@ static int gitdiff_newname(struct apply_state *state,
DIFF_NEW_NAME);
}
+static int parse_mode_line(const char *line, int linenr, unsigned int *mode)
+{
+ char *end;
+ *mode = strtoul(line, &end, 8);
+ if (end == line || !isspace(*end))
+ return error(_("invalid mode on line %d: %s"), linenr, line);
+ return 0;
+}
+
static int gitdiff_oldmode(struct apply_state *state,
const char *line,
struct patch *patch)
{
- patch->old_mode = strtoul(line, NULL, 8);
- return 0;
+ return parse_mode_line(line, state->linenr, &patch->old_mode);
}
static int gitdiff_newmode(struct apply_state *state,
const char *line,
struct patch *patch)
{
- patch->new_mode = strtoul(line, NULL, 8);
- return 0;
+ return parse_mode_line(line, state->linenr, &patch->new_mode);
}
static int gitdiff_delete(struct apply_state *state,
@@ -1138,7 +1134,7 @@ static int gitdiff_index(struct apply_state *state,
memcpy(patch->new_sha1_prefix, line, len);
patch->new_sha1_prefix[len] = 0;
if (*ptr == ' ')
- patch->old_mode = strtoul(ptr+1, NULL, 8);
+ return gitdiff_oldmode(state, ptr + 1, patch);
return 0;
}
@@ -1322,6 +1318,18 @@ static char *git_header_name(struct apply_state *state,
}
}
+static int check_header_line(struct apply_state *state, struct patch *patch)
+{
+ int extensions = (patch->is_delete == 1) + (patch->is_new == 1) +
+ (patch->is_rename == 1) + (patch->is_copy == 1);
+ if (extensions > 1)
+ return error(_("inconsistent header lines %d and %d"),
+ patch->extension_linenr, state->linenr);
+ if (extensions && !patch->extension_linenr)
+ patch->extension_linenr = state->linenr;
+ return 0;
+}
+
/* Verify that we recognize the lines following a git header */
static int parse_git_header(struct apply_state *state,
const char *line,
@@ -1388,6 +1396,8 @@ static int parse_git_header(struct apply_state *state,
res = p->fn(state, line + oplen, patch);
if (res < 0)
return -1;
+ if (check_header_line(state, patch))
+ return -1;
if (res > 0)
return offset;
break;
@@ -1585,7 +1595,8 @@ static int find_header(struct apply_state *state,
patch->old_name = xstrdup(patch->def_name);
patch->new_name = xstrdup(patch->def_name);
}
- if (!patch->is_delete && !patch->new_name) {
+ if ((!patch->new_name && !patch->is_delete) ||
+ (!patch->old_name && !patch->is_new)) {
error(_("git diff header lacks filename information "
"(line %d)"), state->linenr);
return -128;
@@ -2088,7 +2099,7 @@ static int use_patch(struct apply_state *state, struct patch *p)
/* See if it matches any of exclude/include rule */
for (i = 0; i < state->limit_by_name.nr; i++) {
struct string_list_item *it = &state->limit_by_name.items[i];
- if (!wildmatch(it->string, pathname, 0, NULL))
+ if (!wildmatch(it->string, pathname, 0))
return (it->util != NULL);
}
@@ -2267,7 +2278,7 @@ static int read_old_data(struct stat *st, const char *path, struct strbuf *buf)
case S_IFREG:
if (strbuf_read_file(buf, path, st->st_size) != st->st_size)
return error(_("unable to open or read %s"), path);
- convert_to_git(path, buf->buf, buf->len, buf, 0);
+ convert_to_git(&the_index, path, buf->buf, buf->len, buf, 0);
return 0;
default:
return -1;
@@ -3705,8 +3716,7 @@ static int check_preimage(struct apply_state *state,
is_new:
patch->is_new = 1;
patch->is_delete = 0;
- free(patch->old_name);
- patch->old_name = NULL;
+ FREE_AND_NULL(patch->old_name);
return 0;
}
@@ -3741,7 +3751,7 @@ static int check_to_create(struct apply_state *state,
return 0;
return EXISTS_IN_WORKTREE;
- } else if ((errno != ENOENT) && (errno != ENOTDIR)) {
+ } else if (!is_missing_file_error(errno)) {
return error_errno("%s", new_name);
}
return 0;