]> git.ipfire.org Git - thirdparty/git.git/blobdiff - apply.c
sha1_name: convert get_sha1* to get_oid*
[thirdparty/git.git] / apply.c
diff --git a/apply.c b/apply.c
index 4024e70c54408dee28b0f9f41d11115476925ba1..9889b47d6a51c42f00a4da712d99683d904405e6 100644 (file)
--- 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"
@@ -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;
@@ -57,8 +58,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 +113,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 +150,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 +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;
@@ -747,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.
@@ -956,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") :
@@ -995,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,
@@ -1122,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;
 }
 
@@ -1306,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,
@@ -1372,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;
@@ -1569,9 +1595,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;
@@ -1619,8 +1646,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);
 }
 
@@ -1815,7 +1843,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"),
@@ -2029,7 +2057,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);
 }
 
@@ -2071,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);
        }
 
@@ -2170,29 +2198,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);
                }
        }
 }
@@ -2259,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;
@@ -2910,7 +2929,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;
@@ -3025,7 +3044,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;
@@ -3040,14 +3059,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);
        }
@@ -3078,8 +3097,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;
@@ -3114,7 +3133,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
@@ -3122,46 +3141,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;
@@ -3177,10 +3196,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;
@@ -3210,17 +3229,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 */
@@ -3233,7 +3252,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)
@@ -3317,10 +3336,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))
@@ -3440,9 +3457,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 };
@@ -3496,7 +3513,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;
        }
@@ -3519,7 +3536,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;
@@ -3533,12 +3550,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_oid(patch->old_sha1_prefix, &pre_oid) ||
+                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);
@@ -3547,28 +3565,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;
        }
 
@@ -3577,12 +3597,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;
 }
@@ -3646,7 +3672,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) {
@@ -3668,7 +3694,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)
@@ -3690,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;
 }
 
@@ -3726,8 +3751,8 @@ static int check_to_create(struct apply_state *state,
                        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;
 }
@@ -3955,7 +3980,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);
@@ -3967,21 +3992,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:
@@ -4005,18 +4039,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 };
@@ -4027,7 +4061,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;
 
@@ -4036,39 +4070,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_oid_blob(patch->old_sha1_prefix, &oid)) {
                        ; /* 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;
 }
@@ -4238,21 +4273,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);
@@ -4401,7 +4436,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"),
@@ -4471,7 +4506,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;
@@ -4488,7 +4523,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);
@@ -4502,7 +4538,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
@@ -4515,10 +4551,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);
@@ -4567,8 +4605,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);
@@ -4625,7 +4665,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++;
@@ -4643,10 +4683,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;
@@ -4678,18 +4724,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:
@@ -4699,16 +4745,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);
@@ -4716,9 +4762,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);
@@ -4726,8 +4772,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)
@@ -4737,8 +4783,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;
@@ -4747,8 +4793,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);
@@ -4769,6 +4815,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, "-")) {
@@ -4778,21 +4825,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;
@@ -4824,10 +4871,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.",
@@ -4845,7 +4894,7 @@ int apply_all_patches(struct apply_state *state,
                state->newfd = -1;
        }
 
-       return !!errs;
+       res = !!errs;
 
 end:
        if (state->newfd >= 0) {
@@ -4853,5 +4902,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);
+}