diff options
Diffstat (limited to 'apply.c')
-rw-r--r-- | apply.c | 57 |
1 files changed, 34 insertions, 23 deletions
@@ -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. @@ -985,8 +976,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 +1001,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 +1135,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 +1319,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 +1397,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 +1596,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; @@ -2267,7 +2279,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 +3717,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 +3752,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; |