diff options
Diffstat (limited to 'apply.c')
-rw-r--r-- | apply.c | 53 |
1 files changed, 41 insertions, 12 deletions
@@ -80,7 +80,6 @@ int init_apply_state(struct apply_state *state, { memset(state, 0, sizeof(*state)); state->prefix = prefix; - state->prefix_length = state->prefix ? strlen(state->prefix) : 0; state->lock_file = lock_file; state->newfd = -1; state->apply = 1; @@ -220,6 +219,7 @@ struct patch { unsigned int recount:1; unsigned int conflicted_threeway:1; unsigned int direct_to_threeway:1; + unsigned int crlf_in_old:1; struct fragment *fragments; char *result; size_t resultsize; @@ -786,11 +786,11 @@ static int guess_p_value(struct apply_state *state, const char *nameline) * Does it begin with "a/$our-prefix" and such? Then this is * very likely to apply to our directory. */ - if (!strncmp(name, state->prefix, state->prefix_length)) + if (starts_with(name, state->prefix)) val = count_slashes(state->prefix); else { cp++; - if (!strncmp(cp, state->prefix, state->prefix_length)) + if (starts_with(cp, state->prefix)) val = count_slashes(state->prefix) + 1; } } @@ -1663,6 +1663,19 @@ static void check_whitespace(struct apply_state *state, } /* + * Check if the patch has context lines with CRLF or + * the patch wants to remove lines with CRLF. + */ +static void check_old_for_crlf(struct patch *patch, const char *line, int len) +{ + if (len >= 2 && line[len-1] == '\n' && line[len-2] == '\r') { + patch->ws_rule |= WS_CR_AT_EOL; + patch->crlf_in_old = 1; + } +} + + +/* * Parse a unified diff. Note that this really needs to parse each * fragment separately, since the only way to know the difference * between a "---" that is part of a patch, and a "---" that starts @@ -1712,11 +1725,14 @@ static int parse_fragment(struct apply_state *state, if (!deleted && !added) leading++; trailing++; + check_old_for_crlf(patch, line, len); if (!state->apply_in_reverse && state->ws_error_action == correct_ws_error) check_whitespace(state, line, len, patch->ws_rule); break; case '-': + if (!state->apply_in_reverse) + check_old_for_crlf(patch, line, len); if (state->apply_in_reverse && state->ws_error_action != nowarn_ws_error) check_whitespace(state, line, len, patch->ws_rule); @@ -1725,6 +1741,8 @@ static int parse_fragment(struct apply_state *state, trailing = 0; break; case '+': + if (state->apply_in_reverse) + check_old_for_crlf(patch, line, len); if (!state->apply_in_reverse && state->ws_error_action != nowarn_ws_error) check_whitespace(state, line, len, patch->ws_rule); @@ -2089,10 +2107,9 @@ static int use_patch(struct apply_state *state, struct patch *p) int i; /* Paths outside are not touched regardless of "--include" */ - if (0 < state->prefix_length) { - int pathlen = strlen(pathname); - if (pathlen <= state->prefix_length || - memcmp(state->prefix, pathname, state->prefix_length)) + if (state->prefix && *state->prefix) { + const char *rest; + if (!skip_prefix(pathname, state->prefix, &rest) || !*rest) return 0; } @@ -2268,8 +2285,11 @@ static void show_stats(struct apply_state *state, struct patch *patch) add, pluses, del, minuses); } -static int read_old_data(struct stat *st, const char *path, struct strbuf *buf) +static int read_old_data(struct stat *st, struct patch *patch, + const char *path, struct strbuf *buf) { + enum safe_crlf safe_crlf = patch->crlf_in_old ? + SAFE_CRLF_KEEP_CRLF : SAFE_CRLF_RENORMALIZE; switch (st->st_mode & S_IFMT) { case S_IFLNK: if (strbuf_readlink(buf, path, st->st_size) < 0) @@ -2278,7 +2298,15 @@ 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(&the_index, path, buf->buf, buf->len, buf, 0); + /* + * "git apply" without "--index/--cached" should never look + * at the index; the target file may not have been added to + * the index yet, and we may not even be in any Git repository. + * Pass NULL to convert_to_git() to stress this; the function + * should never look at the index when explicit crlf option + * is given. + */ + convert_to_git(NULL, path, buf->buf, buf->len, buf, safe_crlf); return 0; default: return -1; @@ -3381,6 +3409,7 @@ static int load_patch_target(struct apply_state *state, struct strbuf *buf, const struct cache_entry *ce, struct stat *st, + struct patch *patch, const char *name, unsigned expected_mode) { @@ -3396,7 +3425,7 @@ static int load_patch_target(struct apply_state *state, } else if (has_symlink_leading_path(name, strlen(name))) { return error(_("reading from '%s' beyond a symbolic link"), name); } else { - if (read_old_data(st, name, buf)) + if (read_old_data(st, patch, name, buf)) return error(_("failed to read %s"), name); } } @@ -3429,7 +3458,7 @@ static int load_preimage(struct apply_state *state, /* We have a patched copy in memory; use that. */ strbuf_add(&buf, previous->result, previous->resultsize); } else { - status = load_patch_target(state, &buf, ce, st, + status = load_patch_target(state, &buf, ce, st, patch, patch->old_name, patch->old_mode); if (status < 0) return status; @@ -3517,7 +3546,7 @@ static int load_current(struct apply_state *state, if (verify_index_match(ce, &st)) return error(_("%s: does not match index"), name); - status = load_patch_target(state, &buf, ce, &st, name, mode); + status = load_patch_target(state, &buf, ce, &st, patch, name, mode); if (status < 0) return status; else if (status) |