diff options
Diffstat (limited to 'apply.c')
-rw-r--r-- | apply.c | 475 |
1 files changed, 310 insertions, 165 deletions
@@ -27,7 +27,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; @@ -57,8 +57,8 @@ int parse_whitespace_option(struct apply_state *state, const char *option) 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") || @@ -112,21 +112,29 @@ void clear_apply_state(struct apply_state *state) /* &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) @@ -141,6 +149,13 @@ int check_apply_state(struct apply_state *state, int force_apply) 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; } @@ -195,6 +210,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; @@ -994,20 +1010,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, @@ -1121,7 +1144,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; } @@ -1305,6 +1328,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, @@ -1371,6 +1406,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; @@ -1568,9 +1605,10 @@ 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) { - 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; @@ -1618,8 +1656,9 @@ static void record_ws_error(struct apply_state *state, 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); } @@ -1814,7 +1853,7 @@ static int parse_single_patch(struct apply_state *state, 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"), @@ -2028,7 +2067,7 @@ static void prefix_one(struct apply_state *state, char **name) 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); } @@ -2169,29 +2208,20 @@ static int parse_chunk(struct apply_state *state, char *buffer, unsigned long si 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); } } } @@ -2909,7 +2939,7 @@ static int apply_one_fragment(struct apply_state *state, /* 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; @@ -3024,7 +3054,7 @@ static int apply_one_fragment(struct apply_state *state, 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; @@ -3039,14 +3069,14 @@ static int apply_one_fragment(struct apply_state *state, * 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); } @@ -3077,8 +3107,8 @@ static int apply_binary_fragment(struct apply_state *state, /* 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; @@ -3113,7 +3143,7 @@ static int apply_binary(struct apply_state *state, 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 @@ -3121,46 +3151,46 @@ static int apply_binary(struct apply_state *state, */ 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; @@ -3176,10 +3206,10 @@ static int apply_binary(struct apply_state *state, 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; @@ -3209,17 +3239,17 @@ static int apply_fragments(struct apply_state *state, struct image *img, struct 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 */ @@ -3232,7 +3262,7 @@ static int read_file_or_gitlink(const struct cache_entry *ce, struct strbuf *buf { 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) @@ -3316,10 +3346,8 @@ static void prepare_fn_table(struct apply_state *state, struct patch *patch) 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)) @@ -3439,9 +3467,9 @@ static int load_preimage(struct apply_state *state, 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 }; @@ -3495,7 +3523,7 @@ static int load_current(struct apply_state *state, 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; } @@ -3518,7 +3546,7 @@ static int try_threeway(struct apply_state *state, 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; @@ -3532,12 +3560,13 @@ static int try_threeway(struct apply_state *state, /* 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); @@ -3546,28 +3575,30 @@ static int try_threeway(struct apply_state *state, 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; } @@ -3576,12 +3607,18 @@ static int try_threeway(struct apply_state *state, 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; } @@ -3645,7 +3682,7 @@ static int check_preimage(struct apply_state *state, } 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) { @@ -3667,7 +3704,7 @@ static int check_preimage(struct apply_state *state, } 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) @@ -3726,7 +3763,7 @@ static int check_to_create(struct apply_state *state, return EXISTS_IN_WORKTREE; } else if ((errno != ENOENT) && (errno != ENOTDIR)) { - return error("%s: %s", new_name, strerror(errno)); + return error_errno("%s", new_name); } return 0; } @@ -3954,7 +3991,7 @@ static int check_patch_list(struct apply_state *state, struct patch *patch) 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); @@ -3966,21 +4003,30 @@ static int check_patch_list(struct apply_state *state, struct patch *patch) 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: @@ -4004,18 +4050,18 @@ static int preimage_sha1_in_gitlink_patch(struct patch *p, unsigned char sha1[20 (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 }; @@ -4026,7 +4072,7 @@ static int build_fake_ancestor(struct patch *list, const char *filename) * 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; @@ -4035,39 +4081,40 @@ static int build_fake_ancestor(struct patch *list, const char *filename) 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; } @@ -4237,21 +4284,21 @@ static int add_index_file(struct apply_state *state, 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); @@ -4400,7 +4447,7 @@ static int add_conflicted_stages_file(struct apply_state *state, 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"), @@ -4470,7 +4517,7 @@ static int write_out_one_reject(struct apply_state *state, struct patch *patch) } if (!cnt) { - if (state->apply_verbosely) + if (state->apply_verbosity > verbosity_normal) say_patch_name(stderr, _("Applied patch %s cleanly."), patch); return 0; @@ -4487,7 +4534,8 @@ static int write_out_one_reject(struct apply_state *state, struct patch *patch) "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); @@ -4501,7 +4549,7 @@ static int write_out_one_reject(struct apply_state *state, struct patch *patch) 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 @@ -4514,10 +4562,12 @@ static int write_out_one_reject(struct apply_state *state, struct patch *patch) 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); @@ -4566,8 +4616,10 @@ static int write_out_results(struct apply_state *state, struct patch *list) 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); @@ -4624,7 +4676,7 @@ static int apply_patch(struct apply_state *state, 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++; @@ -4642,10 +4694,16 @@ static int apply_patch(struct apply_state *state, 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; @@ -4677,18 +4735,18 @@ static int apply_patch(struct apply_state *state, } 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: @@ -4698,16 +4756,16 @@ end: 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); @@ -4715,9 +4773,9 @@ int apply_option_parse_include(const struct option *opt, 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); @@ -4725,8 +4783,8 @@ int apply_option_parse_p(const struct option *opt, 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) @@ -4736,8 +4794,8 @@ int apply_option_parse_space_change(const struct option *opt, 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; @@ -4746,8 +4804,8 @@ int apply_option_parse_whitespace(const struct option *opt, 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); @@ -4768,6 +4826,7 @@ int apply_all_patches(struct apply_state *state, for (i = 0; i < argc; i++) { const char *arg = argv[i]; + char *to_free = NULL; int fd; if (!strcmp(arg, "-")) { @@ -4777,21 +4836,21 @@ int apply_all_patches(struct apply_state *state, 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; @@ -4823,10 +4882,12 @@ int apply_all_patches(struct apply_state *state, 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.", @@ -4844,7 +4905,7 @@ int apply_all_patches(struct apply_state *state, state->newfd = -1; } - return !!errs; + res = !!errs; end: if (state->newfd >= 0) { @@ -4852,5 +4913,89 @@ end: 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 <num> 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 <n> 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 <root> to all filenames"), + 0, apply_option_parse_directory }, + OPT_END() + }; + + return parse_options(argc, argv, state->prefix, builtin_apply_options, apply_usage, 0); +} |