From: Junio C Hamano Date: Wed, 12 Jul 2017 22:18:22 +0000 (-0700) Subject: Merge branch 'rs/apply-avoid-over-reading' X-Git-Tag: v2.14.0-rc0~12 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/6fee4ca6255ad5ffe3be98c11e7822166e2d4510?hp=-c Merge branch 'rs/apply-avoid-over-reading' Code cleanup. * rs/apply-avoid-over-reading: apply: use strcmp(3) for comparing strings in gitdiff_verify_name() --- 6fee4ca6255ad5ffe3be98c11e7822166e2d4510 diff --combined apply.c index 4050cebcfa,58ffe1b764..f2d599141d --- a/apply.c +++ b/apply.c @@@ -8,7 -8,6 +8,7 @@@ */ #include "cache.h" +#include "config.h" #include "blob.h" #include "delta.h" #include "diff.h" @@@ -28,7 -27,7 +28,7 @@@ static void git_apply_config(void git_config(git_default_config, NULL); } -int parse_whitespace_option(struct apply_state *state, const char *option) +static int parse_whitespace_option(struct apply_state *state, const char *option) { if (!option) { state->ws_error_action = warn_on_ws_error; @@@ -58,8 -57,8 +58,8 @@@ return error(_("unrecognized whitespace option '%s'"), option); } -int parse_ignorewhitespace_option(struct apply_state *state, - const char *option) +static int parse_ignorewhitespace_option(struct apply_state *state, + const char *option) { if (!option || !strcmp(option, "no") || !strcmp(option, "false") || !strcmp(option, "never") || @@@ -113,29 -112,21 +113,29 @@@ void clear_apply_state(struct apply_sta /* &state->fn_table is cleared at the end of apply_patch() */ } +static void mute_routine(const char *msg, va_list params) +{ + /* do nothing */ +} + int check_apply_state(struct apply_state *state, int force_apply) { int is_not_gitdir = !startup_info->have_repository; if (state->apply_with_reject && state->threeway) - return error("--reject and --3way cannot be used together."); + return error(_("--reject and --3way cannot be used together.")); if (state->cached && state->threeway) - return error("--cached and --3way cannot be used together."); + return error(_("--cached and --3way cannot be used together.")); if (state->threeway) { if (is_not_gitdir) return error(_("--3way outside a repository")); state->check_index = 1; } - if (state->apply_with_reject) - state->apply = state->apply_verbosely = 1; + if (state->apply_with_reject) { + state->apply = 1; + if (state->apply_verbosity == verbosity_normal) + state->apply_verbosity = verbosity_verbose; + } if (!force_apply && (state->diffstat || state->numstat || state->summary || state->check || state->fake_ancestor)) state->apply = 0; if (state->check_index && is_not_gitdir) @@@ -150,13 -141,6 +150,13 @@@ if (!state->lock_file) return error("BUG: state->lock_file should not be NULL"); + if (state->apply_verbosity <= verbosity_silent) { + state->saved_error_routine = get_error_routine(); + state->saved_warn_routine = get_warn_routine(); + set_error_routine(mute_routine); + set_warn_routine(mute_routine); + } + return 0; } @@@ -211,7 -195,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; @@@ -764,6 -747,17 +764,6 @@@ static char *find_name_traditional(stru 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. @@@ -962,13 -956,12 +962,12 @@@ static int gitdiff_verify_name(struct a } 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") : @@@ -1001,27 -994,20 +1000,27 @@@ static int gitdiff_newname(struct apply 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, @@@ -1135,7 -1121,7 +1134,7 @@@ static int gitdiff_index(struct apply_s 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; } @@@ -1319,18 -1305,6 +1318,18 @@@ static char *git_header_name(struct app } } +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, @@@ -1397,8 -1371,6 +1396,8 @@@ 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; @@@ -1596,10 -1568,9 +1595,10 @@@ static int find_header(struct apply_sta patch->old_name = xstrdup(patch->def_name); patch->new_name = xstrdup(patch->def_name); } - if (!patch->is_delete && !patch->new_name) { - error("git diff header lacks filename information " - "(line %d)", state->linenr); + 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; } patch->is_toplevel_relative = 1; @@@ -1647,9 -1618,8 +1646,9 @@@ static void record_ws_error(struct appl return; err = whitespace_error_string(result); - fprintf(stderr, "%s:%d: %s.\n%.*s\n", - state->patch_input_file, linenr, err, len, line); + if (state->apply_verbosity > verbosity_silent) + fprintf(stderr, "%s:%d: %s.\n%.*s\n", + state->patch_input_file, linenr, err, len, line); free(err); } @@@ -1844,7 -1814,7 +1843,7 @@@ static int parse_single_patch(struct ap return error(_("new file %s depends on old contents"), patch->new_name); if (0 < patch->is_delete && newlines) return error(_("deleted file %s still has contents"), patch->old_name); - if (!patch->is_delete && !newlines && context) + if (!patch->is_delete && !newlines && context && state->apply_verbosity > verbosity_silent) fprintf_ln(stderr, _("** warning: " "file %s becomes empty but is not deleted"), @@@ -2058,7 -2028,7 +2057,7 @@@ static void prefix_one(struct apply_sta char *old_name = *name; if (!old_name) return; - *name = xstrdup(prefix_filename(state->prefix, state->prefix_length, *name)); + *name = prefix_filename(state->prefix, *name); free(old_name); } @@@ -2100,7 -2070,7 +2099,7 @@@ static int use_patch(struct apply_stat /* 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); } @@@ -2199,20 -2169,29 +2198,20 @@@ static int parse_chunk(struct apply_sta return offset + hdrsize + patchsize; } -#define swap(a,b) myswap((a),(b),sizeof(a)) - -#define myswap(a, b, size) do { \ - unsigned char mytmp[size]; \ - memcpy(mytmp, &a, size); \ - memcpy(&a, &b, size); \ - memcpy(&b, mytmp, size); \ -} while (0) - static void reverse_patches(struct patch *p) { for (; p; p = p->next) { struct fragment *frag = p->fragments; - swap(p->new_name, p->old_name); - swap(p->new_mode, p->old_mode); - swap(p->is_new, p->is_delete); - swap(p->lines_added, p->lines_deleted); - swap(p->old_sha1_prefix, p->new_sha1_prefix); + SWAP(p->new_name, p->old_name); + SWAP(p->new_mode, p->old_mode); + SWAP(p->is_new, p->is_delete); + SWAP(p->lines_added, p->lines_deleted); + SWAP(p->old_sha1_prefix, p->new_sha1_prefix); for (; frag; frag = frag->next) { - swap(frag->newpos, frag->oldpos); - swap(frag->newlines, frag->oldlines); + SWAP(frag->newpos, frag->oldpos); + SWAP(frag->newlines, frag->oldlines); } } } @@@ -2279,7 -2258,7 +2278,7 @@@ static int read_old_data(struct stat *s 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; @@@ -2930,7 -2909,7 +2929,7 @@@ static int apply_one_fragment(struct ap /* Ignore it, we already handled it */ break; default: - if (state->apply_verbosely) + if (state->apply_verbosity > verbosity_normal) error(_("invalid start of line: '%c'"), first); applied_pos = -1; goto out; @@@ -3045,7 -3024,7 +3044,7 @@@ state->apply = 0; } - if (state->apply_verbosely && applied_pos != pos) { + if (state->apply_verbosity > verbosity_normal && applied_pos != pos) { int offset = applied_pos - pos; if (state->apply_in_reverse) offset = 0 - offset; @@@ -3060,14 -3039,14 +3059,14 @@@ * Warn if it was necessary to reduce the number * of context lines. */ - if ((leading != frag->leading) || - (trailing != frag->trailing)) + if ((leading != frag->leading || + trailing != frag->trailing) && state->apply_verbosity > verbosity_silent) fprintf_ln(stderr, _("Context reduced to (%ld/%ld)" " to apply fragment at %d"), leading, trailing, applied_pos+1); update_image(state, img, applied_pos, &preimage, &postimage); } else { - if (state->apply_verbosely) + if (state->apply_verbosity > verbosity_normal) error(_("while searching for:\n%.*s"), (int)(old - oldlines), oldlines); } @@@ -3098,8 -3077,8 +3097,8 @@@ static int apply_binary_fragment(struc /* Binary patch is irreversible without the optional second hunk */ if (state->apply_in_reverse) { if (!fragment->next) - return error("cannot reverse-apply a binary patch " - "without the reverse hunk to '%s'", + return error(_("cannot reverse-apply a binary patch " + "without the reverse hunk to '%s'"), patch->new_name ? patch->new_name : patch->old_name); fragment = fragment->next; @@@ -3134,7 -3113,7 +3133,7 @@@ static int apply_binary(struct apply_st struct patch *patch) { const char *name = patch->old_name ? patch->old_name : patch->new_name; - unsigned char sha1[20]; + struct object_id oid; /* * For safety, we require patch index line to contain @@@ -3142,46 -3121,46 +3141,46 @@@ */ if (strlen(patch->old_sha1_prefix) != 40 || strlen(patch->new_sha1_prefix) != 40 || - get_sha1_hex(patch->old_sha1_prefix, sha1) || - get_sha1_hex(patch->new_sha1_prefix, sha1)) - return error("cannot apply binary patch to '%s' " - "without full index line", name); + get_oid_hex(patch->old_sha1_prefix, &oid) || + get_oid_hex(patch->new_sha1_prefix, &oid)) + return error(_("cannot apply binary patch to '%s' " + "without full index line"), name); if (patch->old_name) { /* * See if the old one matches what the patch * applies to. */ - hash_sha1_file(img->buf, img->len, blob_type, sha1); - if (strcmp(sha1_to_hex(sha1), patch->old_sha1_prefix)) - return error("the patch applies to '%s' (%s), " - "which does not match the " - "current contents.", - name, sha1_to_hex(sha1)); + hash_sha1_file(img->buf, img->len, blob_type, oid.hash); + if (strcmp(oid_to_hex(&oid), patch->old_sha1_prefix)) + return error(_("the patch applies to '%s' (%s), " + "which does not match the " + "current contents."), + name, oid_to_hex(&oid)); } else { /* Otherwise, the old one must be empty. */ if (img->len) - return error("the patch applies to an empty " - "'%s' but it is not empty", name); + return error(_("the patch applies to an empty " + "'%s' but it is not empty"), name); } - get_sha1_hex(patch->new_sha1_prefix, sha1); - if (is_null_sha1(sha1)) { + get_oid_hex(patch->new_sha1_prefix, &oid); + if (is_null_oid(&oid)) { clear_image(img); return 0; /* deletion patch */ } - if (has_sha1_file(sha1)) { + if (has_sha1_file(oid.hash)) { /* We already have the postimage */ enum object_type type; unsigned long size; char *result; - result = read_sha1_file(sha1, &type, &size); + result = read_sha1_file(oid.hash, &type, &size); if (!result) - return error("the necessary postimage %s for " - "'%s' cannot be read", + return error(_("the necessary postimage %s for " + "'%s' cannot be read"), patch->new_sha1_prefix, name); clear_image(img); img->buf = result; @@@ -3197,10 -3176,10 +3196,10 @@@ name); /* verify that the result matches */ - hash_sha1_file(img->buf, img->len, blob_type, sha1); - if (strcmp(sha1_to_hex(sha1), patch->new_sha1_prefix)) + hash_sha1_file(img->buf, img->len, blob_type, oid.hash); + if (strcmp(oid_to_hex(&oid), patch->new_sha1_prefix)) return error(_("binary patch to '%s' creates incorrect result (expecting %s, got %s)"), - name, patch->new_sha1_prefix, sha1_to_hex(sha1)); + name, patch->new_sha1_prefix, oid_to_hex(&oid)); } return 0; @@@ -3230,17 -3209,17 +3229,17 @@@ static int apply_fragments(struct apply return 0; } -static int read_blob_object(struct strbuf *buf, const unsigned char *sha1, unsigned mode) +static int read_blob_object(struct strbuf *buf, const struct object_id *oid, unsigned mode) { if (S_ISGITLINK(mode)) { strbuf_grow(buf, 100); - strbuf_addf(buf, "Subproject commit %s\n", sha1_to_hex(sha1)); + strbuf_addf(buf, "Subproject commit %s\n", oid_to_hex(oid)); } else { enum object_type type; unsigned long sz; char *result; - result = read_sha1_file(sha1, &type, &sz); + result = read_sha1_file(oid->hash, &type, &sz); if (!result) return -1; /* XXX read_sha1_file NUL-terminates */ @@@ -3253,7 -3232,7 +3252,7 @@@ static int read_file_or_gitlink(const s { if (!ce) return 0; - return read_blob_object(buf, ce->sha1, ce->ce_mode); + return read_blob_object(buf, &ce->oid, ce->ce_mode); } static struct patch *in_fn_table(struct apply_state *state, const char *name) @@@ -3337,8 -3316,10 +3336,8 @@@ static void prepare_fn_table(struct app static int checkout_target(struct index_state *istate, struct cache_entry *ce, struct stat *st) { - struct checkout costate; + struct checkout costate = CHECKOUT_INIT; - memset(&costate, 0, sizeof(costate)); - costate.base_dir = ""; costate.refresh_cache = 1; costate.istate = istate; if (checkout_entry(ce, &costate, NULL) || lstat(ce->name, st)) @@@ -3458,9 -3439,9 +3457,9 @@@ static int load_preimage(struct apply_s static int three_way_merge(struct image *image, char *path, - const unsigned char *base, - const unsigned char *ours, - const unsigned char *theirs) + const struct object_id *base, + const struct object_id *ours, + const struct object_id *theirs) { mmfile_t base_file, our_file, their_file; mmbuffer_t result = { NULL }; @@@ -3514,7 -3495,7 +3513,7 @@@ static int load_current(struct apply_st ce = active_cache[pos]; if (lstat(name, &st)) { if (errno != ENOENT) - return error(_("%s: %s"), name, strerror(errno)); + return error_errno("%s", name); if (checkout_target(&the_index, ce, &st)) return -1; } @@@ -3537,7 -3518,7 +3536,7 @@@ static int try_threeway(struct apply_st struct stat *st, const struct cache_entry *ce) { - unsigned char pre_sha1[20], post_sha1[20], our_sha1[20]; + struct object_id pre_oid, post_oid, our_oid; struct strbuf buf = STRBUF_INIT; size_t len; int status; @@@ -3551,13 -3532,12 +3550,13 @@@ /* Preimage the patch was prepared for */ if (patch->is_new) - write_sha1_file("", 0, blob_type, pre_sha1); - else if (get_sha1(patch->old_sha1_prefix, pre_sha1) || - read_blob_object(&buf, pre_sha1, patch->old_mode)) - return error("repository lacks the necessary blob to fall back on 3-way merge."); + write_sha1_file("", 0, blob_type, pre_oid.hash); + else if (get_sha1(patch->old_sha1_prefix, pre_oid.hash) || + read_blob_object(&buf, &pre_oid, patch->old_mode)) + return error(_("repository lacks the necessary blob to fall back on 3-way merge.")); - fprintf(stderr, "Falling back to three-way merge...\n"); + if (state->apply_verbosity > verbosity_silent) + fprintf(stderr, _("Falling back to three-way merge...\n")); img = strbuf_detach(&buf, &len); prepare_image(&tmp_image, img, len, 1); @@@ -3566,30 -3546,28 +3565,30 @@@ clear_image(&tmp_image); return -1; } - /* post_sha1[] is theirs */ - write_sha1_file(tmp_image.buf, tmp_image.len, blob_type, post_sha1); + /* post_oid is theirs */ + write_sha1_file(tmp_image.buf, tmp_image.len, blob_type, post_oid.hash); clear_image(&tmp_image); - /* our_sha1[] is ours */ + /* our_oid is ours */ if (patch->is_new) { if (load_current(state, &tmp_image, patch)) - return error("cannot read the current contents of '%s'", + return error(_("cannot read the current contents of '%s'"), patch->new_name); } else { if (load_preimage(state, &tmp_image, patch, st, ce)) - return error("cannot read the current contents of '%s'", + return error(_("cannot read the current contents of '%s'"), patch->old_name); } - write_sha1_file(tmp_image.buf, tmp_image.len, blob_type, our_sha1); + write_sha1_file(tmp_image.buf, tmp_image.len, blob_type, our_oid.hash); clear_image(&tmp_image); /* in-core three-way merge between post and our using pre as base */ status = three_way_merge(image, patch->new_name, - pre_sha1, our_sha1, post_sha1); + &pre_oid, &our_oid, &post_oid); if (status < 0) { - fprintf(stderr, "Failed to fall back on three-way merge...\n"); + if (state->apply_verbosity > verbosity_silent) + fprintf(stderr, + _("Failed to fall back on three-way merge...\n")); return status; } @@@ -3598,18 -3576,12 +3597,18 @@@ if (patch->is_new) oidclr(&patch->threeway_stage[0]); else - hashcpy(patch->threeway_stage[0].hash, pre_sha1); - hashcpy(patch->threeway_stage[1].hash, our_sha1); - hashcpy(patch->threeway_stage[2].hash, post_sha1); - fprintf(stderr, "Applied patch to '%s' with conflicts.\n", patch->new_name); + oidcpy(&patch->threeway_stage[0], &pre_oid); + oidcpy(&patch->threeway_stage[1], &our_oid); + oidcpy(&patch->threeway_stage[2], &post_oid); + if (state->apply_verbosity > verbosity_silent) + fprintf(stderr, + _("Applied patch to '%s' with conflicts.\n"), + patch->new_name); } else { - fprintf(stderr, "Applied patch to '%s' cleanly.\n", patch->new_name); + if (state->apply_verbosity > verbosity_silent) + fprintf(stderr, + _("Applied patch to '%s' cleanly.\n"), + patch->new_name); } return 0; } @@@ -3673,7 -3645,7 +3672,7 @@@ static int check_preimage(struct apply_ } else if (!state->cached) { stat_ret = lstat(old_name, st); if (stat_ret && errno != ENOENT) - return error(_("%s: %s"), old_name, strerror(errno)); + return error_errno("%s", old_name); } if (state->check_index && !previous) { @@@ -3695,7 -3667,7 +3694,7 @@@ } else if (stat_ret < 0) { if (patch->is_new < 0) goto is_new; - return error(_("%s: %s"), old_name, strerror(errno)); + return error_errno("%s", old_name); } if (!state->cached && !previous) @@@ -3717,7 -3689,8 +3716,7 @@@ 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; } @@@ -3752,8 -3725,8 +3751,8 @@@ static int check_to_create(struct apply return 0; return EXISTS_IN_WORKTREE; - } else if ((errno != ENOENT) && (errno != ENOTDIR)) { - return error("%s: %s", new_name, strerror(errno)); + } else if (!is_missing_file_error(errno)) { + return error_errno("%s", new_name); } return 0; } @@@ -3981,7 -3954,7 +3980,7 @@@ static int check_patch_list(struct appl prepare_fn_table(state, patch); while (patch) { int res; - if (state->apply_verbosely) + if (state->apply_verbosity > verbosity_normal) say_patch_name(stderr, _("Checking patch %s..."), patch); res = check_patch(state, patch); @@@ -3993,30 -3966,21 +3992,30 @@@ return err; } -/* This function tries to read the sha1 from the current index */ -static int get_current_sha1(const char *path, unsigned char *sha1) +static int read_apply_cache(struct apply_state *state) +{ + if (state->index_file) + return read_cache_from(state->index_file); + else + return read_cache(); +} + +/* This function tries to read the object name from the current index */ +static int get_current_oid(struct apply_state *state, const char *path, + struct object_id *oid) { int pos; - if (read_cache() < 0) + if (read_apply_cache(state) < 0) return -1; pos = cache_name_pos(path, strlen(path)); if (pos < 0) return -1; - hashcpy(sha1, active_cache[pos]->sha1); + oidcpy(oid, &active_cache[pos]->oid); return 0; } -static int preimage_sha1_in_gitlink_patch(struct patch *p, unsigned char sha1[20]) +static int preimage_oid_in_gitlink_patch(struct patch *p, struct object_id *oid) { /* * A usable gitlink patch has only one fragment (hunk) that looks like: @@@ -4040,18 -4004,18 +4039,18 @@@ (preimage = memchr(hunk->patch, '\n', hunk->size)) != NULL && starts_with(++preimage, heading) && /* does it record full SHA-1? */ - !get_sha1_hex(preimage + sizeof(heading) - 1, sha1) && - preimage[sizeof(heading) + 40 - 1] == '\n' && + !get_oid_hex(preimage + sizeof(heading) - 1, oid) && + preimage[sizeof(heading) + GIT_SHA1_HEXSZ - 1] == '\n' && /* does the abbreviated name on the index line agree with it? */ starts_with(preimage + sizeof(heading) - 1, p->old_sha1_prefix)) return 0; /* it all looks fine */ /* we may have full object name on the index line */ - return get_sha1_hex(p->old_sha1_prefix, sha1); + return get_oid_hex(p->old_sha1_prefix, oid); } /* Build an index that contains the just the files needed for a 3way merge */ -static int build_fake_ancestor(struct patch *list, const char *filename) +static int build_fake_ancestor(struct apply_state *state, struct patch *list) { struct patch *patch; struct index_state result = { NULL }; @@@ -4062,7 -4026,7 +4061,7 @@@ * worth showing the new sha1 prefix, but until then... */ for (patch = list; patch; patch = patch->next) { - unsigned char sha1[20]; + struct object_id oid; struct cache_entry *ce; const char *name; @@@ -4071,40 -4035,39 +4070,40 @@@ continue; if (S_ISGITLINK(patch->old_mode)) { - if (!preimage_sha1_in_gitlink_patch(patch, sha1)) + if (!preimage_oid_in_gitlink_patch(patch, &oid)) ; /* ok, the textual part looks sane */ else - return error("sha1 information is lacking or " - "useless for submodule %s", name); - } else if (!get_sha1_blob(patch->old_sha1_prefix, sha1)) { + return error(_("sha1 information is lacking or " + "useless for submodule %s"), name); + } else if (!get_sha1_blob(patch->old_sha1_prefix, oid.hash)) { ; /* ok */ } else if (!patch->lines_added && !patch->lines_deleted) { /* mode-only change: update the current */ - if (get_current_sha1(patch->old_name, sha1)) - return error("mode change for %s, which is not " - "in current HEAD", name); + if (get_current_oid(state, patch->old_name, &oid)) + return error(_("mode change for %s, which is not " + "in current HEAD"), name); } else - return error("sha1 information is lacking or useless " - "(%s).", name); + return error(_("sha1 information is lacking or useless " + "(%s)."), name); - ce = make_cache_entry(patch->old_mode, sha1, name, 0, 0); + ce = make_cache_entry(patch->old_mode, oid.hash, name, 0, 0); if (!ce) return error(_("make_cache_entry failed for path '%s'"), name); if (add_index_entry(&result, ce, ADD_CACHE_OK_TO_ADD)) { free(ce); - return error("Could not add %s to temporary index", + return error(_("could not add %s to temporary index"), name); } } - hold_lock_file_for_update(&lock, filename, LOCK_DIE_ON_ERROR); + hold_lock_file_for_update(&lock, state->fake_ancestor, LOCK_DIE_ON_ERROR); res = write_locked_index(&result, &lock, COMMIT_LOCK); discard_index(&result); if (res) - return error("Could not write temporary index to %s", filename); + return error(_("could not write temporary index to %s"), + state->fake_ancestor); return 0; } @@@ -4274,21 -4237,21 +4273,21 @@@ static int add_index_file(struct apply_ const char *s; if (!skip_prefix(buf, "Subproject commit ", &s) || - get_sha1_hex(s, ce->sha1)) { + get_oid_hex(s, &ce->oid)) { free(ce); - return error(_("corrupt patch for submodule %s"), path); + return error(_("corrupt patch for submodule %s"), path); } } else { if (!state->cached) { if (lstat(path, &st) < 0) { free(ce); - return error(_("unable to stat newly " - "created file '%s': %s"), - path, strerror(errno)); + return error_errno(_("unable to stat newly " + "created file '%s'"), + path); } fill_stat_cache_info(ce, &st); } - if (write_sha1_file(buf, size, blob_type, ce->sha1) < 0) { + if (write_sha1_file(buf, size, blob_type, ce->oid.hash) < 0) { free(ce); return error(_("unable to create backing store " "for newly created file %s"), path); @@@ -4437,7 -4400,7 +4436,7 @@@ static int add_conflicted_stages_file(s ce->ce_mode = create_ce_mode(mode); ce->ce_flags = create_ce_flags(stage); ce->ce_namelen = namelen; - hashcpy(ce->sha1, patch->threeway_stage[stage - 1].hash); + oidcpy(&ce->oid, &patch->threeway_stage[stage - 1]); if (add_cache_entry(ce, ADD_CACHE_OK_TO_ADD) < 0) { free(ce); return error(_("unable to add cache entry for %s"), @@@ -4507,7 -4470,7 +4506,7 @@@ static int write_out_one_reject(struct } if (!cnt) { - if (state->apply_verbosely) + if (state->apply_verbosity > verbosity_normal) say_patch_name(stderr, _("Applied patch %s cleanly."), patch); return 0; @@@ -4524,8 -4487,7 +4523,8 @@@ "Applying patch %%s with %d rejects...", cnt), cnt); - say_patch_name(stderr, sb.buf, patch); + if (state->apply_verbosity > verbosity_silent) + say_patch_name(stderr, sb.buf, patch); strbuf_release(&sb); cnt = strlen(patch->new_name); @@@ -4539,7 -4501,7 +4538,7 @@@ rej = fopen(namebuf, "w"); if (!rej) - return error(_("cannot open %s: %s"), namebuf, strerror(errno)); + return error_errno(_("cannot open %s"), namebuf); /* Normal git tools never deal with .rej, so do not pretend * this is a git patch by saying --git or giving extended @@@ -4552,12 -4514,10 +4551,12 @@@ frag; cnt++, frag = frag->next) { if (!frag->rejected) { - fprintf_ln(stderr, _("Hunk #%d applied cleanly."), cnt); + if (state->apply_verbosity > verbosity_silent) + fprintf_ln(stderr, _("Hunk #%d applied cleanly."), cnt); continue; } - fprintf_ln(stderr, _("Rejected hunk #%d."), cnt); + if (state->apply_verbosity > verbosity_silent) + fprintf_ln(stderr, _("Rejected hunk #%d."), cnt); fprintf(rej, "%.*s", frag->size, frag->patch); if (frag->patch[frag->size-1] != '\n') fputc('\n', rej); @@@ -4606,10 -4566,8 +4605,10 @@@ static int write_out_results(struct app struct string_list_item *item; string_list_sort(&cpath); - for_each_string_list_item(item, &cpath) - fprintf(stderr, "U %s\n", item->string); + if (state->apply_verbosity > verbosity_silent) { + for_each_string_list_item(item, &cpath) + fprintf(stderr, "U %s\n", item->string); + } string_list_clear(&cpath, 0); rerere(0); @@@ -4666,7 -4624,7 +4665,7 @@@ static int apply_patch(struct apply_sta listp = &patch->next; } else { - if (state->apply_verbosely) + if (state->apply_verbosity > verbosity_normal) say_patch_name(stderr, _("Skipped patch '%s'."), patch); free_patch(patch); skipped_patch++; @@@ -4684,16 -4642,10 +4683,16 @@@ state->apply = 0; state->update_index = state->check_index && state->apply; - if (state->update_index && state->newfd < 0) - state->newfd = hold_locked_index(state->lock_file, 1); + if (state->update_index && state->newfd < 0) { + if (state->index_file) + state->newfd = hold_lock_file_for_update(state->lock_file, + state->index_file, + LOCK_DIE_ON_ERROR); + else + state->newfd = hold_locked_index(state->lock_file, LOCK_DIE_ON_ERROR); + } - if (state->check_index && read_cache() < 0) { + if (state->check_index && read_apply_cache(state) < 0) { error(_("unable to read index file")); res = -128; goto end; @@@ -4725,18 -4677,18 +4724,18 @@@ } if (state->fake_ancestor && - build_fake_ancestor(list, state->fake_ancestor)) { + build_fake_ancestor(state, list)) { res = -128; goto end; } - if (state->diffstat) + if (state->diffstat && state->apply_verbosity > verbosity_silent) stat_patch_list(state, list); - if (state->numstat) + if (state->numstat && state->apply_verbosity > verbosity_silent) numstat_patch_list(state, list); - if (state->summary) + if (state->summary && state->apply_verbosity > verbosity_silent) summary_patch_list(list); end: @@@ -4746,16 -4698,16 +4745,16 @@@ return res; } -int apply_option_parse_exclude(const struct option *opt, - const char *arg, int unset) +static int apply_option_parse_exclude(const struct option *opt, + const char *arg, int unset) { struct apply_state *state = opt->value; add_name_limit(state, arg, 1); return 0; } -int apply_option_parse_include(const struct option *opt, - const char *arg, int unset) +static int apply_option_parse_include(const struct option *opt, + const char *arg, int unset) { struct apply_state *state = opt->value; add_name_limit(state, arg, 0); @@@ -4763,9 -4715,9 +4762,9 @@@ return 0; } -int apply_option_parse_p(const struct option *opt, - const char *arg, - int unset) +static int apply_option_parse_p(const struct option *opt, + const char *arg, + int unset) { struct apply_state *state = opt->value; state->p_value = atoi(arg); @@@ -4773,8 -4725,8 +4772,8 @@@ return 0; } -int apply_option_parse_space_change(const struct option *opt, - const char *arg, int unset) +static int apply_option_parse_space_change(const struct option *opt, + const char *arg, int unset) { struct apply_state *state = opt->value; if (unset) @@@ -4784,8 -4736,8 +4783,8 @@@ return 0; } -int apply_option_parse_whitespace(const struct option *opt, - const char *arg, int unset) +static int apply_option_parse_whitespace(const struct option *opt, + const char *arg, int unset) { struct apply_state *state = opt->value; state->whitespace_option = arg; @@@ -4794,8 -4746,8 +4793,8 @@@ return 0; } -int apply_option_parse_directory(const struct option *opt, - const char *arg, int unset) +static int apply_option_parse_directory(const struct option *opt, + const char *arg, int unset) { struct apply_state *state = opt->value; strbuf_reset(&state->root); @@@ -4816,7 -4768,6 +4815,7 @@@ int apply_all_patches(struct apply_stat for (i = 0; i < argc; i++) { const char *arg = argv[i]; + char *to_free = NULL; int fd; if (!strcmp(arg, "-")) { @@@ -4826,21 -4777,21 +4825,21 @@@ errs |= res; read_stdin = 0; continue; - } else if (0 < state->prefix_length) - arg = prefix_filename(state->prefix, - state->prefix_length, - arg); + } else + arg = to_free = prefix_filename(state->prefix, arg); fd = open(arg, O_RDONLY); if (fd < 0) { error(_("can't open patch '%s': %s"), arg, strerror(errno)); res = -128; + free(to_free); goto end; } read_stdin = 0; set_default_whitespace_mode(state); res = apply_patch(state, fd, arg, options); close(fd); + free(to_free); if (res < 0) goto end; errs |= res; @@@ -4872,12 -4823,10 +4871,12 @@@ goto end; } if (state->applied_after_fixing_ws && state->apply) - warning("%d line%s applied after" - " fixing whitespace errors.", - state->applied_after_fixing_ws, - state->applied_after_fixing_ws == 1 ? "" : "s"); + warning(Q_("%d line applied after" + " fixing whitespace errors.", + "%d lines applied after" + " fixing whitespace errors.", + state->applied_after_fixing_ws), + state->applied_after_fixing_ws); else if (state->whitespace_error) warning(Q_("%d line adds whitespace errors.", "%d lines add whitespace errors.", @@@ -4895,7 -4844,7 +4894,7 @@@ state->newfd = -1; } - return !!errs; + res = !!errs; end: if (state->newfd >= 0) { @@@ -4903,89 -4852,5 +4902,89 @@@ state->newfd = -1; } + if (state->apply_verbosity <= verbosity_silent) { + set_error_routine(state->saved_error_routine); + set_warn_routine(state->saved_warn_routine); + } + + if (res > -1) + return res; return (res == -1 ? 1 : 128); } + +int apply_parse_options(int argc, const char **argv, + struct apply_state *state, + int *force_apply, int *options, + const char * const *apply_usage) +{ + struct option builtin_apply_options[] = { + { OPTION_CALLBACK, 0, "exclude", state, N_("path"), + N_("don't apply changes matching the given path"), + 0, apply_option_parse_exclude }, + { OPTION_CALLBACK, 0, "include", state, N_("path"), + N_("apply changes matching the given path"), + 0, apply_option_parse_include }, + { OPTION_CALLBACK, 'p', NULL, state, N_("num"), + N_("remove leading slashes from traditional diff paths"), + 0, apply_option_parse_p }, + OPT_BOOL(0, "no-add", &state->no_add, + N_("ignore additions made by the patch")), + OPT_BOOL(0, "stat", &state->diffstat, + N_("instead of applying the patch, output diffstat for the input")), + OPT_NOOP_NOARG(0, "allow-binary-replacement"), + OPT_NOOP_NOARG(0, "binary"), + OPT_BOOL(0, "numstat", &state->numstat, + N_("show number of added and deleted lines in decimal notation")), + OPT_BOOL(0, "summary", &state->summary, + N_("instead of applying the patch, output a summary for the input")), + OPT_BOOL(0, "check", &state->check, + N_("instead of applying the patch, see if the patch is applicable")), + OPT_BOOL(0, "index", &state->check_index, + N_("make sure the patch is applicable to the current index")), + OPT_BOOL(0, "cached", &state->cached, + N_("apply a patch without touching the working tree")), + OPT_BOOL(0, "unsafe-paths", &state->unsafe_paths, + N_("accept a patch that touches outside the working area")), + OPT_BOOL(0, "apply", force_apply, + N_("also apply the patch (use with --stat/--summary/--check)")), + OPT_BOOL('3', "3way", &state->threeway, + N_( "attempt three-way merge if a patch does not apply")), + OPT_FILENAME(0, "build-fake-ancestor", &state->fake_ancestor, + N_("build a temporary index based on embedded index information")), + /* Think twice before adding "--nul" synonym to this */ + OPT_SET_INT('z', NULL, &state->line_termination, + N_("paths are separated with NUL character"), '\0'), + OPT_INTEGER('C', NULL, &state->p_context, + N_("ensure at least lines of context match")), + { OPTION_CALLBACK, 0, "whitespace", state, N_("action"), + N_("detect new or modified lines that have whitespace errors"), + 0, apply_option_parse_whitespace }, + { OPTION_CALLBACK, 0, "ignore-space-change", state, NULL, + N_("ignore changes in whitespace when finding context"), + PARSE_OPT_NOARG, apply_option_parse_space_change }, + { OPTION_CALLBACK, 0, "ignore-whitespace", state, NULL, + N_("ignore changes in whitespace when finding context"), + PARSE_OPT_NOARG, apply_option_parse_space_change }, + OPT_BOOL('R', "reverse", &state->apply_in_reverse, + N_("apply the patch in reverse")), + OPT_BOOL(0, "unidiff-zero", &state->unidiff_zero, + N_("don't expect at least one line of context")), + OPT_BOOL(0, "reject", &state->apply_with_reject, + N_("leave the rejected hunks in corresponding *.rej files")), + OPT_BOOL(0, "allow-overlap", &state->allow_overlap, + N_("allow overlapping hunks")), + OPT__VERBOSE(&state->apply_verbosity, N_("be verbose")), + OPT_BIT(0, "inaccurate-eof", options, + N_("tolerate incorrectly detected missing new-line at the end of file"), + APPLY_OPT_INACCURATE_EOF), + OPT_BIT(0, "recount", options, + N_("do not trust the line counts in the hunk headers"), + APPLY_OPT_RECOUNT), + { OPTION_CALLBACK, 0, "directory", state, N_("root"), + N_("prepend to all filenames"), + 0, apply_option_parse_directory }, + OPT_END() + }; + + return parse_options(argc, argv, state->prefix, builtin_apply_options, apply_usage, 0); +}