Merge branch 'rs/strbuf-getwholeline-fix' into next
[gitweb.git] / sha1_name.c
index 26ceec1d799afad6c6831cba00ca4d0ffab7979f..862b6f1308e7031317ab6eb6d181652a6fc644ad 100644 (file)
@@ -1,4 +1,5 @@
 #include "cache.h"
+#include "config.h"
 #include "tag.h"
 #include "commit.h"
 #include "tree.h"
 #include "dir.h"
 #include "sha1-array.h"
 
-static int get_sha1_oneline(const char *, unsigned char *, struct commit_list *);
+static int get_oid_oneline(const char *, struct object_id *, struct commit_list *);
 
-typedef int (*disambiguate_hint_fn)(const unsigned char *, void *);
+typedef int (*disambiguate_hint_fn)(const struct object_id *, void *);
 
 struct disambiguate_state {
        int len; /* length of prefix in hex chars */
-       char hex_pfx[GIT_SHA1_HEXSZ + 1];
-       unsigned char bin_pfx[GIT_SHA1_RAWSZ];
+       char hex_pfx[GIT_MAX_HEXSZ + 1];
+       struct object_id bin_pfx;
 
        disambiguate_hint_fn fn;
        void *cb_data;
-       unsigned char candidate[GIT_SHA1_RAWSZ];
+       struct object_id candidate;
        unsigned candidate_exists:1;
        unsigned candidate_checked:1;
        unsigned candidate_ok:1;
@@ -29,7 +30,7 @@ struct disambiguate_state {
        unsigned always_call_fn:1;
 };
 
-static void update_candidates(struct disambiguate_state *ds, const unsigned char *current)
+static void update_candidates(struct disambiguate_state *ds, const struct object_id *current)
 {
        if (ds->always_call_fn) {
                ds->ambiguous = ds->fn(current, ds->cb_data) ? 1 : 0;
@@ -37,10 +38,10 @@ static void update_candidates(struct disambiguate_state *ds, const unsigned char
        }
        if (!ds->candidate_exists) {
                /* this is the first candidate */
-               hashcpy(ds->candidate, current);
+               oidcpy(&ds->candidate, current);
                ds->candidate_exists = 1;
                return;
-       } else if (!hashcmp(ds->candidate, current)) {
+       } else if (!oidcmp(&ds->candidate, current)) {
                /* the same as what we already have seen */
                return;
        }
@@ -52,14 +53,14 @@ static void update_candidates(struct disambiguate_state *ds, const unsigned char
        }
 
        if (!ds->candidate_checked) {
-               ds->candidate_ok = ds->fn(ds->candidate, ds->cb_data);
+               ds->candidate_ok = ds->fn(&ds->candidate, ds->cb_data);
                ds->disambiguate_fn_used = 1;
                ds->candidate_checked = 1;
        }
 
        if (!ds->candidate_ok) {
                /* discard the candidate; we know it does not satisfy fn */
-               hashcpy(ds->candidate, current);
+               oidcpy(&ds->candidate, current);
                ds->candidate_checked = 0;
                return;
        }
@@ -77,10 +78,19 @@ static void update_candidates(struct disambiguate_state *ds, const unsigned char
        /* otherwise, current can be discarded and candidate is still good */
 }
 
+static int append_loose_object(const struct object_id *oid, const char *path,
+                              void *data)
+{
+       oid_array_append(data, oid);
+       return 0;
+}
+
+static int match_sha(unsigned, const unsigned char *, const unsigned char *);
+
 static void find_short_object_filename(struct disambiguate_state *ds)
 {
+       int subdir_nr = ds->bin_pfx.hash[0];
        struct alternate_object_database *alt;
-       char hex[GIT_SHA1_HEXSZ];
        static struct alternate_object_database *fakeent;
 
        if (!fakeent) {
@@ -95,29 +105,29 @@ static void find_short_object_filename(struct disambiguate_state *ds)
        }
        fakeent->next = alt_odb_list;
 
-       xsnprintf(hex, sizeof(hex), "%.2s", ds->hex_pfx);
        for (alt = fakeent; alt && !ds->ambiguous; alt = alt->next) {
-               struct strbuf *buf = alt_scratch_buf(alt);
-               struct dirent *de;
-               DIR *dir;
-
-               strbuf_addf(buf, "%.2s/", ds->hex_pfx);
-               dir = opendir(buf->buf);
-               if (!dir)
-                       continue;
+               int pos;
 
-               while (!ds->ambiguous && (de = readdir(dir)) != NULL) {
-                       unsigned char sha1[20];
+               if (!alt->loose_objects_subdir_seen[subdir_nr]) {
+                       struct strbuf *buf = alt_scratch_buf(alt);
+                       for_each_file_in_obj_subdir(subdir_nr, buf,
+                                                   append_loose_object,
+                                                   NULL, NULL,
+                                                   &alt->loose_objects_cache);
+                       alt->loose_objects_subdir_seen[subdir_nr] = 1;
+               }
 
-                       if (strlen(de->d_name) != 38)
-                               continue;
-                       if (memcmp(de->d_name, ds->hex_pfx + 2, ds->len - 2))
-                               continue;
-                       memcpy(hex + 2, de->d_name, 38);
-                       if (!get_sha1_hex(hex, sha1))
-                               update_candidates(ds, sha1);
+               pos = oid_array_lookup(&alt->loose_objects_cache, &ds->bin_pfx);
+               if (pos < 0)
+                       pos = -1 - pos;
+               while (!ds->ambiguous && pos < alt->loose_objects_cache.nr) {
+                       const struct object_id *oid;
+                       oid = alt->loose_objects_cache.oid + pos;
+                       if (!match_sha(ds->len, ds->bin_pfx.hash, oid->hash))
+                               break;
+                       update_candidates(ds, oid);
+                       pos++;
                }
-               closedir(dir);
        }
 }
 
@@ -140,7 +150,7 @@ static void unique_in_pack(struct packed_git *p,
                           struct disambiguate_state *ds)
 {
        uint32_t num, last, i, first = 0;
-       const unsigned char *current = NULL;
+       const struct object_id *current = NULL;
 
        open_pack_index(p);
        num = p->num_objects;
@@ -151,7 +161,7 @@ static void unique_in_pack(struct packed_git *p,
                int cmp;
 
                current = nth_packed_object_sha1(p, mid);
-               cmp = hashcmp(ds->bin_pfx, current);
+               cmp = hashcmp(ds->bin_pfx.hash, current);
                if (!cmp) {
                        first = mid;
                        break;
@@ -169,8 +179,9 @@ static void unique_in_pack(struct packed_git *p,
         * 0, 1 or more objects that actually match(es).
         */
        for (i = first; i < num && !ds->ambiguous; i++) {
-               current = nth_packed_object_sha1(p, i);
-               if (!match_sha(ds->len, ds->bin_pfx, current))
+               struct object_id oid;
+               current = nth_packed_object_oid(&oid, p, i);
+               if (!match_sha(ds->len, ds->bin_pfx.hash, current->hash))
                        break;
                update_candidates(ds, current);
        }
@@ -189,7 +200,7 @@ static void find_short_packed_object(struct disambiguate_state *ds)
 #define SHORT_NAME_AMBIGUOUS (-2)
 
 static int finish_object_disambiguation(struct disambiguate_state *ds,
-                                       unsigned char *sha1)
+                                       struct object_id *oid)
 {
        if (ds->ambiguous)
                return SHORT_NAME_AMBIGUOUS;
@@ -213,66 +224,66 @@ static int finish_object_disambiguation(struct disambiguate_state *ds,
                 * same repository!
                 */
                ds->candidate_ok = (!ds->disambiguate_fn_used ||
-                                   ds->fn(ds->candidate, ds->cb_data));
+                                   ds->fn(&ds->candidate, ds->cb_data));
 
        if (!ds->candidate_ok)
                return SHORT_NAME_AMBIGUOUS;
 
-       hashcpy(sha1, ds->candidate);
+       oidcpy(oid, &ds->candidate);
        return 0;
 }
 
-static int disambiguate_commit_only(const unsigned char *sha1, void *cb_data_unused)
+static int disambiguate_commit_only(const struct object_id *oid, void *cb_data_unused)
 {
-       int kind = sha1_object_info(sha1, NULL);
+       int kind = sha1_object_info(oid->hash, NULL);
        return kind == OBJ_COMMIT;
 }
 
-static int disambiguate_committish_only(const unsigned char *sha1, void *cb_data_unused)
+static int disambiguate_committish_only(const struct object_id *oid, void *cb_data_unused)
 {
        struct object *obj;
        int kind;
 
-       kind = sha1_object_info(sha1, NULL);
+       kind = sha1_object_info(oid->hash, NULL);
        if (kind == OBJ_COMMIT)
                return 1;
        if (kind != OBJ_TAG)
                return 0;
 
        /* We need to do this the hard way... */
-       obj = deref_tag(parse_object(sha1), NULL, 0);
+       obj = deref_tag(parse_object(oid), NULL, 0);
        if (obj && obj->type == OBJ_COMMIT)
                return 1;
        return 0;
 }
 
-static int disambiguate_tree_only(const unsigned char *sha1, void *cb_data_unused)
+static int disambiguate_tree_only(const struct object_id *oid, void *cb_data_unused)
 {
-       int kind = sha1_object_info(sha1, NULL);
+       int kind = sha1_object_info(oid->hash, NULL);
        return kind == OBJ_TREE;
 }
 
-static int disambiguate_treeish_only(const unsigned char *sha1, void *cb_data_unused)
+static int disambiguate_treeish_only(const struct object_id *oid, void *cb_data_unused)
 {
        struct object *obj;
        int kind;
 
-       kind = sha1_object_info(sha1, NULL);
+       kind = sha1_object_info(oid->hash, NULL);
        if (kind == OBJ_TREE || kind == OBJ_COMMIT)
                return 1;
        if (kind != OBJ_TAG)
                return 0;
 
        /* We need to do this the hard way... */
-       obj = deref_tag(parse_object(sha1), NULL, 0);
+       obj = deref_tag(parse_object(oid), NULL, 0);
        if (obj && (obj->type == OBJ_TREE || obj->type == OBJ_COMMIT))
                return 1;
        return 0;
 }
 
-static int disambiguate_blob_only(const unsigned char *sha1, void *cb_data_unused)
+static int disambiguate_blob_only(const struct object_id *oid, void *cb_data_unused)
 {
-       int kind = sha1_object_info(sha1, NULL);
+       int kind = sha1_object_info(oid->hash, NULL);
        return kind == OBJ_BLOB;
 }
 
@@ -332,7 +343,7 @@ static int init_object_disambiguation(const char *name, int len,
                ds->hex_pfx[i] = c;
                if (!(i & 1))
                        val <<= 4;
-               ds->bin_pfx[i >> 1] |= val;
+               ds->bin_pfx.hash[i >> 1] |= val;
        }
 
        ds->len = len;
@@ -341,31 +352,32 @@ static int init_object_disambiguation(const char *name, int len,
        return 0;
 }
 
-static int show_ambiguous_object(const unsigned char *sha1, void *data)
+static int show_ambiguous_object(const struct object_id *oid, void *data)
 {
        const struct disambiguate_state *ds = data;
        struct strbuf desc = STRBUF_INIT;
        int type;
 
-       if (ds->fn && !ds->fn(sha1, ds->cb_data))
+
+       if (ds->fn && !ds->fn(oid, ds->cb_data))
                return 0;
 
-       type = sha1_object_info(sha1, NULL);
+       type = sha1_object_info(oid->hash, NULL);
        if (type == OBJ_COMMIT) {
-               struct commit *commit = lookup_commit(sha1);
+               struct commit *commit = lookup_commit(oid);
                if (commit) {
                        struct pretty_print_context pp = {0};
                        pp.date_mode.type = DATE_SHORT;
                        format_commit_message(commit, " %ad - %s", &desc, &pp);
                }
        } else if (type == OBJ_TAG) {
-               struct tag *tag = lookup_tag(sha1);
+               struct tag *tag = lookup_tag(oid);
                if (!parse_tag(tag) && tag->tag)
                        strbuf_addf(&desc, " %s", tag->tag);
        }
 
        advise("  %s %s%s",
-              find_unique_abbrev(sha1, DEFAULT_ABBREV),
+              find_unique_abbrev(oid->hash, DEFAULT_ABBREV),
               typename(type) ? typename(type) : "unknown type",
               desc.buf);
 
@@ -373,35 +385,35 @@ static int show_ambiguous_object(const unsigned char *sha1, void *data)
        return 0;
 }
 
-static int get_short_sha1(const char *name, int len, unsigned char *sha1,
+static int get_short_oid(const char *name, int len, struct object_id *oid,
                          unsigned flags)
 {
        int status;
        struct disambiguate_state ds;
-       int quietly = !!(flags & GET_SHA1_QUIETLY);
+       int quietly = !!(flags & GET_OID_QUIETLY);
 
        if (init_object_disambiguation(name, len, &ds) < 0)
                return -1;
 
-       if (HAS_MULTI_BITS(flags & GET_SHA1_DISAMBIGUATORS))
-               die("BUG: multiple get_short_sha1 disambiguator flags");
+       if (HAS_MULTI_BITS(flags & GET_OID_DISAMBIGUATORS))
+               die("BUG: multiple get_short_oid disambiguator flags");
 
-       if (flags & GET_SHA1_COMMIT)
+       if (flags & GET_OID_COMMIT)
                ds.fn = disambiguate_commit_only;
-       else if (flags & GET_SHA1_COMMITTISH)
+       else if (flags & GET_OID_COMMITTISH)
                ds.fn = disambiguate_committish_only;
-       else if (flags & GET_SHA1_TREE)
+       else if (flags & GET_OID_TREE)
                ds.fn = disambiguate_tree_only;
-       else if (flags & GET_SHA1_TREEISH)
+       else if (flags & GET_OID_TREEISH)
                ds.fn = disambiguate_treeish_only;
-       else if (flags & GET_SHA1_BLOB)
+       else if (flags & GET_OID_BLOB)
                ds.fn = disambiguate_blob_only;
        else
                ds.fn = default_disambiguate_hint;
 
        find_short_object_filename(&ds);
        find_short_packed_object(&ds);
-       status = finish_object_disambiguation(&ds, sha1);
+       status = finish_object_disambiguation(&ds, oid);
 
        if (!quietly && (status == SHORT_NAME_AMBIGUOUS)) {
                error(_("short SHA1 %s is ambiguous"), ds.hex_pfx);
@@ -422,15 +434,15 @@ static int get_short_sha1(const char *name, int len, unsigned char *sha1,
        return status;
 }
 
-static int collect_ambiguous(const unsigned char *sha1, void *data)
+static int collect_ambiguous(const struct object_id *oid, void *data)
 {
-       sha1_array_append(data, sha1);
+       oid_array_append(data, oid);
        return 0;
 }
 
 int for_each_abbrev(const char *prefix, each_abbrev_fn fn, void *cb_data)
 {
-       struct sha1_array collect = SHA1_ARRAY_INIT;
+       struct oid_array collect = OID_ARRAY_INIT;
        struct disambiguate_state ds;
        int ret;
 
@@ -443,8 +455,8 @@ int for_each_abbrev(const char *prefix, each_abbrev_fn fn, void *cb_data)
        find_short_object_filename(&ds);
        find_short_packed_object(&ds);
 
-       ret = sha1_array_for_each_unique(&collect, fn, cb_data);
-       sha1_array_clear(&collect);
+       ret = oid_array_for_each_unique(&collect, fn, cb_data);
+       oid_array_clear(&collect);
        return ret;
 }
 
@@ -477,10 +489,9 @@ int find_unique_abbrev_r(char *hex, const unsigned char *sha1, int len)
                 * We now know we have on the order of 2^len objects, which
                 * expects a collision at 2^(len/2). But we also care about hex
                 * chars, not bits, and there are 4 bits per hex. So all
-                * together we need to divide by 2; but we also want to round
-                * odd numbers up, hence adding one before dividing.
+                * together we need to divide by 2 and round up.
                 */
-               len = (len + 1) / 2;
+               len = DIV_ROUND_UP(len, 2);
                /*
                 * For very small repos, we stick with our regular fallback.
                 */
@@ -489,12 +500,12 @@ int find_unique_abbrev_r(char *hex, const unsigned char *sha1, int len)
        }
 
        sha1_to_hex_r(hex, sha1);
-       if (len == 40 || !len)
-               return 40;
+       if (len == GIT_SHA1_HEXSZ || !len)
+               return GIT_SHA1_HEXSZ;
        exists = has_sha1_file(sha1);
-       while (len < 40) {
-               unsigned char sha1_ret[20];
-               status = get_short_sha1(hex, len, sha1_ret, GET_SHA1_QUIETLY);
+       while (len < GIT_SHA1_HEXSZ) {
+               struct object_id oid_ret;
+               status = get_short_oid(hex, len, &oid_ret, GET_OID_QUIETLY);
                if (exists
                    ? !status
                    : status == SHORT_NAME_NOT_FOUND) {
@@ -509,7 +520,7 @@ int find_unique_abbrev_r(char *hex, const unsigned char *sha1, int len)
 const char *find_unique_abbrev(const unsigned char *sha1, int len)
 {
        static int bufno;
-       static char hexbuffer[4][GIT_SHA1_HEXSZ + 1];
+       static char hexbuffer[4][GIT_MAX_HEXSZ + 1];
        char *hex = hexbuffer[bufno];
        bufno = (bufno + 1) % ARRAY_SIZE(hexbuffer);
        find_unique_abbrev_r(hex, sha1, len);
@@ -549,7 +560,7 @@ static inline int at_mark(const char *string, int len,
        for (i = 0; i < nr; i++) {
                int suffix_len = strlen(suffix[i]);
                if (suffix_len <= len
-                   && !memcmp(string, suffix[i], suffix_len))
+                   && !strncasecmp(string, suffix[i], suffix_len))
                        return suffix_len;
        }
        return 0;
@@ -567,10 +578,10 @@ static inline int push_mark(const char *string, int len)
        return at_mark(string, len, suffix, ARRAY_SIZE(suffix));
 }
 
-static int get_sha1_1(const char *name, int len, unsigned char *sha1, unsigned lookup_flags);
+static int get_oid_1(const char *name, int len, struct object_id *oid, unsigned lookup_flags);
 static int interpret_nth_prior_checkout(const char *name, int namelen, struct strbuf *buf);
 
-static int get_sha1_basic(const char *str, int len, unsigned char *sha1,
+static int get_oid_basic(const char *str, int len, struct object_id *oid,
                          unsigned int flags)
 {
        static const char *warn_msg = "refname '%.*s' is ambiguous.";
@@ -584,14 +595,14 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1,
        "where \"$br\" is somehow empty and a 40-hex ref is created. Please\n"
        "examine these refs and maybe delete them. Turn this message off by\n"
        "running \"git config advice.objectNameWarning false\"");
-       unsigned char tmp_sha1[20];
+       struct object_id tmp_oid;
        char *real_ref = NULL;
        int refs_found = 0;
        int at, reflog_len, nth_prior = 0;
 
-       if (len == 40 && !get_sha1_hex(str, sha1)) {
+       if (len == GIT_SHA1_HEXSZ && !get_oid_hex(str, oid)) {
                if (warn_ambiguous_refs && warn_on_object_refname_ambiguity) {
-                       refs_found = dwim_ref(str, len, tmp_sha1, &real_ref);
+                       refs_found = dwim_ref(str, len, tmp_oid.hash, &real_ref);
                        if (refs_found > 0) {
                                warning(warn_msg, len, str);
                                if (advice_object_name_warning)
@@ -633,7 +644,7 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1,
                int detached;
 
                if (interpret_nth_prior_checkout(str, len, &buf) > 0) {
-                       detached = (buf.len == 40 && !get_sha1_hex(buf.buf, sha1));
+                       detached = (buf.len == GIT_SHA1_HEXSZ && !get_oid_hex(buf.buf, oid));
                        strbuf_release(&buf);
                        if (detached)
                                return 0;
@@ -642,24 +653,24 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1,
 
        if (!len && reflog_len)
                /* allow "@{...}" to mean the current branch reflog */
-               refs_found = dwim_ref("HEAD", 4, sha1, &real_ref);
+               refs_found = dwim_ref("HEAD", 4, oid->hash, &real_ref);
        else if (reflog_len)
-               refs_found = dwim_log(str, len, sha1, &real_ref);
+               refs_found = dwim_log(str, len, oid->hash, &real_ref);
        else
-               refs_found = dwim_ref(str, len, sha1, &real_ref);
+               refs_found = dwim_ref(str, len, oid->hash, &real_ref);
 
        if (!refs_found)
                return -1;
 
-       if (warn_ambiguous_refs && !(flags & GET_SHA1_QUIETLY) &&
+       if (warn_ambiguous_refs && !(flags & GET_OID_QUIETLY) &&
            (refs_found > 1 ||
-            !get_short_sha1(str, len, tmp_sha1, GET_SHA1_QUIETLY)))
+            !get_short_oid(str, len, &tmp_oid, GET_OID_QUIETLY)))
                warning(warn_msg, len, str);
 
        if (reflog_len) {
                int nth, i;
-               unsigned long at_time;
-               unsigned long co_time;
+               timestamp_t at_time;
+               timestamp_t co_time;
                int co_tz, co_cnt;
 
                /* Is it asking for N-th entry, or approxidate? */
@@ -685,7 +696,7 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1,
                                return -1;
                        }
                }
-               if (read_ref_at(real_ref, flags, at_time, nth, sha1, NULL,
+               if (read_ref_at(real_ref, flags, at_time, nth, oid->hash, NULL,
                                &co_time, &co_tz, &co_cnt)) {
                        if (!len) {
                                if (starts_with(real_ref, "refs/heads/")) {
@@ -698,13 +709,13 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1,
                                }
                        }
                        if (at_time) {
-                               if (!(flags & GET_SHA1_QUIETLY)) {
+                               if (!(flags & GET_OID_QUIETLY)) {
                                        warning("Log for '%.*s' only goes "
                                                "back to %s.", len, str,
                                                show_date(co_time, co_tz, DATE_MODE(RFC2822)));
                                }
                        } else {
-                               if (flags & GET_SHA1_QUIETLY) {
+                               if (flags & GET_OID_QUIETLY) {
                                        exit(128);
                                }
                                die("Log for '%.*s' only has %d entries.",
@@ -718,26 +729,26 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1,
 }
 
 static int get_parent(const char *name, int len,
-                     unsigned char *result, int idx)
+                     struct object_id *result, int idx)
 {
-       unsigned char sha1[20];
-       int ret = get_sha1_1(name, len, sha1, GET_SHA1_COMMITTISH);
+       struct object_id oid;
+       int ret = get_oid_1(name, len, &oid, GET_OID_COMMITTISH);
        struct commit *commit;
        struct commit_list *p;
 
        if (ret)
                return ret;
-       commit = lookup_commit_reference(sha1);
+       commit = lookup_commit_reference(&oid);
        if (parse_commit(commit))
                return -1;
        if (!idx) {
-               hashcpy(result, commit->object.oid.hash);
+               oidcpy(result, &commit->object.oid);
                return 0;
        }
        p = commit->parents;
        while (p) {
                if (!--idx) {
-                       hashcpy(result, p->item->object.oid.hash);
+                       oidcpy(result, &p->item->object.oid);
                        return 0;
                }
                p = p->next;
@@ -746,16 +757,16 @@ static int get_parent(const char *name, int len,
 }
 
 static int get_nth_ancestor(const char *name, int len,
-                           unsigned char *result, int generation)
+                           struct object_id *result, int generation)
 {
-       unsigned char sha1[20];
+       struct object_id oid;
        struct commit *commit;
        int ret;
 
-       ret = get_sha1_1(name, len, sha1, GET_SHA1_COMMITTISH);
+       ret = get_oid_1(name, len, &oid, GET_OID_COMMITTISH);
        if (ret)
                return ret;
-       commit = lookup_commit_reference(sha1);
+       commit = lookup_commit_reference(&oid);
        if (!commit)
                return -1;
 
@@ -764,7 +775,7 @@ static int get_nth_ancestor(const char *name, int len,
                        return -1;
                commit = commit->parents->item;
        }
-       hashcpy(result, commit->object.oid.hash);
+       oidcpy(result, &commit->object.oid);
        return 0;
 }
 
@@ -774,7 +785,7 @@ struct object *peel_to_type(const char *name, int namelen,
        if (name && !namelen)
                namelen = strlen(name);
        while (1) {
-               if (!o || (!o->parsed && !parse_object(o->oid.hash)))
+               if (!o || (!o->parsed && !parse_object(&o->oid)))
                        return NULL;
                if (expected_type == OBJ_ANY || o->type == expected_type)
                        return o;
@@ -793,10 +804,10 @@ struct object *peel_to_type(const char *name, int namelen,
        }
 }
 
-static int peel_onion(const char *name, int len, unsigned char *sha1,
+static int peel_onion(const char *name, int len, struct object_id *oid,
                      unsigned lookup_flags)
 {
-       unsigned char outer[20];
+       struct object_id outer;
        const char *sp;
        unsigned int expected_type = 0;
        struct object *o;
@@ -838,23 +849,23 @@ static int peel_onion(const char *name, int len, unsigned char *sha1,
        else
                return -1;
 
-       lookup_flags &= ~GET_SHA1_DISAMBIGUATORS;
+       lookup_flags &= ~GET_OID_DISAMBIGUATORS;
        if (expected_type == OBJ_COMMIT)
-               lookup_flags |= GET_SHA1_COMMITTISH;
+               lookup_flags |= GET_OID_COMMITTISH;
        else if (expected_type == OBJ_TREE)
-               lookup_flags |= GET_SHA1_TREEISH;
+               lookup_flags |= GET_OID_TREEISH;
 
-       if (get_sha1_1(name, sp - name - 2, outer, lookup_flags))
+       if (get_oid_1(name, sp - name - 2, &outer, lookup_flags))
                return -1;
 
-       o = parse_object(outer);
+       o = parse_object(&outer);
        if (!o)
                return -1;
        if (!expected_type) {
                o = deref_tag(o, name, sp - name - 2);
-               if (!o || (!o->parsed && !parse_object(o->oid.hash)))
+               if (!o || (!o->parsed && !parse_object(&o->oid)))
                        return -1;
-               hashcpy(sha1, o->oid.hash);
+               oidcpy(oid, &o->oid);
                return 0;
        }
 
@@ -867,7 +878,7 @@ static int peel_onion(const char *name, int len, unsigned char *sha1,
        if (!o)
                return -1;
 
-       hashcpy(sha1, o->oid.hash);
+       oidcpy(oid, &o->oid);
        if (sp[0] == '/') {
                /* "$commit^{/foo}" */
                char *prefix;
@@ -883,17 +894,17 @@ static int peel_onion(const char *name, int len, unsigned char *sha1,
 
                prefix = xstrndup(sp + 1, name + len - 1 - (sp + 1));
                commit_list_insert((struct commit *)o, &list);
-               ret = get_sha1_oneline(prefix, sha1, list);
+               ret = get_oid_oneline(prefix, oid, list);
                free(prefix);
                return ret;
        }
        return 0;
 }
 
-static int get_describe_name(const char *name, int len, unsigned char *sha1)
+static int get_describe_name(const char *name, int len, struct object_id *oid)
 {
        const char *cp;
-       unsigned flags = GET_SHA1_QUIETLY | GET_SHA1_COMMIT;
+       unsigned flags = GET_OID_QUIETLY | GET_OID_COMMIT;
 
        for (cp = name + len - 1; name + 2 <= cp; cp--) {
                char ch = *cp;
@@ -904,14 +915,14 @@ static int get_describe_name(const char *name, int len, unsigned char *sha1)
                        if (ch == 'g' && cp[-1] == '-') {
                                cp++;
                                len -= cp - name;
-                               return get_short_sha1(cp, len, sha1, flags);
+                               return get_short_oid(cp, len, oid, flags);
                        }
                }
        }
        return -1;
 }
 
-static int get_sha1_1(const char *name, int len, unsigned char *sha1, unsigned lookup_flags)
+static int get_oid_1(const char *name, int len, struct object_id *oid, unsigned lookup_flags)
 {
        int ret, has_suffix;
        const char *cp;
@@ -938,25 +949,25 @@ static int get_sha1_1(const char *name, int len, unsigned char *sha1, unsigned l
                if (!num && len1 == len - 1)
                        num = 1;
                if (has_suffix == '^')
-                       return get_parent(name, len1, sha1, num);
+                       return get_parent(name, len1, oid, num);
                /* else if (has_suffix == '~') -- goes without saying */
-               return get_nth_ancestor(name, len1, sha1, num);
+               return get_nth_ancestor(name, len1, oid, num);
        }
 
-       ret = peel_onion(name, len, sha1, lookup_flags);
+       ret = peel_onion(name, len, oid, lookup_flags);
        if (!ret)
                return 0;
 
-       ret = get_sha1_basic(name, len, sha1, lookup_flags);
+       ret = get_oid_basic(name, len, oid, lookup_flags);
        if (!ret)
                return 0;
 
        /* It could be describe output that is "SOMETHING-gXXXX" */
-       ret = get_describe_name(name, len, sha1);
+       ret = get_describe_name(name, len, oid);
        if (!ret)
                return 0;
 
-       return get_short_sha1(name, len, sha1, lookup_flags);
+       return get_short_oid(name, len, oid, lookup_flags);
 }
 
 /*
@@ -979,7 +990,7 @@ static int handle_one_ref(const char *path, const struct object_id *oid,
                          int flag, void *cb_data)
 {
        struct commit_list **list = cb_data;
-       struct object *object = parse_object(oid->hash);
+       struct object *object = parse_object(oid);
        if (!object)
                return 0;
        if (object->type == OBJ_TAG) {
@@ -993,7 +1004,7 @@ static int handle_one_ref(const char *path, const struct object_id *oid,
        return 0;
 }
 
-static int get_sha1_oneline(const char *prefix, unsigned char *sha1,
+static int get_oid_oneline(const char *prefix, struct object_id *oid,
                            struct commit_list *list)
 {
        struct commit_list *backup = NULL, *l;
@@ -1025,7 +1036,7 @@ static int get_sha1_oneline(const char *prefix, unsigned char *sha1,
                int matches;
 
                commit = pop_most_recent_commit(&list, ONELINE_SEEN);
-               if (!parse_object(commit->object.oid.hash))
+               if (!parse_object(&commit->object.oid))
                        continue;
                buf = get_commit_buffer(commit, NULL);
                p = strstr(buf, "\n\n");
@@ -1033,7 +1044,7 @@ static int get_sha1_oneline(const char *prefix, unsigned char *sha1,
                unuse_commit_buffer(commit, buf);
 
                if (matches) {
-                       hashcpy(sha1, commit->object.oid.hash);
+                       oidcpy(oid, &commit->object.oid);
                        found = 1;
                        break;
                }
@@ -1051,8 +1062,8 @@ struct grab_nth_branch_switch_cbdata {
        struct strbuf buf;
 };
 
-static int grab_nth_branch_switch(unsigned char *osha1, unsigned char *nsha1,
-                                 const char *email, unsigned long timestamp, int tz,
+static int grab_nth_branch_switch(struct object_id *ooid, struct object_id *noid,
+                                 const char *email, timestamp_t timestamp, int tz,
                                  const char *message, void *cb_data)
 {
        struct grab_nth_branch_switch_cbdata *cb = cb_data;
@@ -1129,18 +1140,18 @@ int get_oid_mb(const char *name, struct object_id *oid)
                struct strbuf sb;
                strbuf_init(&sb, dots - name);
                strbuf_add(&sb, name, dots - name);
-               st = get_sha1_committish(sb.buf, oid_tmp.hash);
+               st = get_oid_committish(sb.buf, &oid_tmp);
                strbuf_release(&sb);
        }
        if (st)
                return st;
-       one = lookup_commit_reference_gently(oid_tmp.hash, 0);
+       one = lookup_commit_reference_gently(&oid_tmp, 0);
        if (!one)
                return -1;
 
-       if (get_sha1_committish(dots[3] ? (dots + 3) : "HEAD", oid_tmp.hash))
+       if (get_oid_committish(dots[3] ? (dots + 3) : "HEAD", &oid_tmp))
                return -1;
-       two = lookup_commit_reference_gently(oid_tmp.hash, 0);
+       two = lookup_commit_reference_gently(&oid_tmp, 0);
        if (!two)
                return -1;
        mbs = get_merge_bases(one, two);
@@ -1327,21 +1338,13 @@ int strbuf_check_branch_ref(struct strbuf *sb, const char *name)
 }
 
 /*
- * This is like "get_sha1_basic()", except it allows "sha1 expressions",
+ * This is like "get_oid_basic()", except it allows "object ID expressions",
  * notably "xyz^" for "parent of xyz"
  */
-int get_sha1(const char *name, unsigned char *sha1)
-{
-       struct object_context unused;
-       return get_sha1_with_context(name, 0, sha1, &unused);
-}
-
-/*
- * This is like "get_sha1()", but for struct object_id.
- */
 int get_oid(const char *name, struct object_id *oid)
 {
-       return get_sha1(name, oid->hash);
+       struct object_context unused;
+       return get_oid_with_context(name, 0, oid, &unused);
 }
 
 
@@ -1355,49 +1358,49 @@ int get_oid(const char *name, struct object_id *oid)
  * commit-ish. It is merely to give a hint to the disambiguation
  * machinery.
  */
-int get_sha1_committish(const char *name, unsigned char *sha1)
+int get_oid_committish(const char *name, struct object_id *oid)
 {
        struct object_context unused;
-       return get_sha1_with_context(name, GET_SHA1_COMMITTISH,
-                                    sha1, &unused);
+       return get_oid_with_context(name, GET_OID_COMMITTISH,
+                                   oid, &unused);
 }
 
-int get_sha1_treeish(const char *name, unsigned char *sha1)
+int get_oid_treeish(const char *name, struct object_id *oid)
 {
        struct object_context unused;
-       return get_sha1_with_context(name, GET_SHA1_TREEISH,
-                                    sha1, &unused);
+       return get_oid_with_context(name, GET_OID_TREEISH,
+                                   oid, &unused);
 }
 
-int get_sha1_commit(const char *name, unsigned char *sha1)
+int get_oid_commit(const char *name, struct object_id *oid)
 {
        struct object_context unused;
-       return get_sha1_with_context(name, GET_SHA1_COMMIT,
-                                    sha1, &unused);
+       return get_oid_with_context(name, GET_OID_COMMIT,
+                                   oid, &unused);
 }
 
-int get_sha1_tree(const char *name, unsigned char *sha1)
+int get_oid_tree(const char *name, struct object_id *oid)
 {
        struct object_context unused;
-       return get_sha1_with_context(name, GET_SHA1_TREE,
-                                    sha1, &unused);
+       return get_oid_with_context(name, GET_OID_TREE,
+                                   oid, &unused);
 }
 
-int get_sha1_blob(const char *name, unsigned char *sha1)
+int get_oid_blob(const char *name, struct object_id *oid)
 {
        struct object_context unused;
-       return get_sha1_with_context(name, GET_SHA1_BLOB,
-                                    sha1, &unused);
+       return get_oid_with_context(name, GET_OID_BLOB,
+                                   oid, &unused);
 }
 
 /* Must be called only when object_name:filename doesn't exist. */
-static void diagnose_invalid_sha1_path(const char *prefix,
-                                      const char *filename,
-                                      const unsigned char *tree_sha1,
-                                      const char *object_name,
-                                      int object_name_len)
+static void diagnose_invalid_oid_path(const char *prefix,
+                                     const char *filename,
+                                     const struct object_id *tree_oid,
+                                     const char *object_name,
+                                     int object_name_len)
 {
-       unsigned char sha1[20];
+       struct object_id oid;
        unsigned mode;
 
        if (!prefix)
@@ -1406,11 +1409,11 @@ static void diagnose_invalid_sha1_path(const char *prefix,
        if (file_exists(filename))
                die("Path '%s' exists on disk, but not in '%.*s'.",
                    filename, object_name_len, object_name);
-       if (errno == ENOENT || errno == ENOTDIR) {
+       if (is_missing_file_error(errno)) {
                char *fullname = xstrfmt("%s%s", prefix, filename);
 
-               if (!get_tree_entry(tree_sha1, fullname,
-                                   sha1, &mode)) {
+               if (!get_tree_entry(tree_oid->hash, fullname,
+                                   oid.hash, &mode)) {
                        die("Path '%s' exists, but not '%s'.\n"
                            "Did you mean '%.*s:%s' aka '%.*s:./%s'?",
                            fullname,
@@ -1471,7 +1474,7 @@ static void diagnose_invalid_index_path(int stage,
 
        if (file_exists(filename))
                die("Path '%s' exists on disk, but not in the index.", filename);
-       if (errno == ENOENT || errno == ENOTDIR)
+       if (is_missing_file_error(errno))
                die("Path '%s' does not exist (neither on disk nor in the index).",
                    filename);
 
@@ -1493,23 +1496,24 @@ static char *resolve_relative_path(const char *rel)
                           rel);
 }
 
-static int get_sha1_with_context_1(const char *name,
-                                  unsigned flags,
-                                  const char *prefix,
-                                  unsigned char *sha1,
-                                  struct object_context *oc)
+static int get_oid_with_context_1(const char *name,
+                                 unsigned flags,
+                                 const char *prefix,
+                                 struct object_id *oid,
+                                 struct object_context *oc)
 {
        int ret, bracket_depth;
        int namelen = strlen(name);
        const char *cp;
-       int only_to_die = flags & GET_SHA1_ONLY_TO_DIE;
+       int only_to_die = flags & GET_OID_ONLY_TO_DIE;
 
        if (only_to_die)
-               flags |= GET_SHA1_QUIETLY;
+               flags |= GET_OID_QUIETLY;
 
        memset(oc, 0, sizeof(*oc));
        oc->mode = S_IFINVALID;
-       ret = get_sha1_1(name, namelen, sha1, flags);
+       strbuf_init(&oc->symlink_path, 0);
+       ret = get_oid_1(name, namelen, oid, flags);
        if (!ret)
                return ret;
        /*
@@ -1529,7 +1533,7 @@ static int get_sha1_with_context_1(const char *name,
 
                        for_each_ref(handle_one_ref, &list);
                        commit_list_sort_by_date(&list);
-                       return get_sha1_oneline(name + 2, sha1, list);
+                       return get_oid_oneline(name + 2, oid, list);
                }
                if (namelen < 3 ||
                    name[2] != ':' ||
@@ -1547,7 +1551,8 @@ static int get_sha1_with_context_1(const char *name,
                        namelen = strlen(cp);
                }
 
-               strlcpy(oc->path, cp, sizeof(oc->path));
+               if (flags & GET_OID_RECORD_PATH)
+                       oc->path = xstrdup(cp);
 
                if (!active_cache)
                        read_cache();
@@ -1560,7 +1565,7 @@ static int get_sha1_with_context_1(const char *name,
                            memcmp(ce->name, cp, namelen))
                                break;
                        if (ce_stage(ce) == stage) {
-                               hashcpy(sha1, ce->oid.hash);
+                               oidcpy(oid, &ce->oid);
                                oc->mode = ce->ce_mode;
                                free(new_path);
                                return 0;
@@ -1581,36 +1586,37 @@ static int get_sha1_with_context_1(const char *name,
                        break;
        }
        if (*cp == ':') {
-               unsigned char tree_sha1[20];
+               struct object_id tree_oid;
                int len = cp - name;
                unsigned sub_flags = flags;
 
-               sub_flags &= ~GET_SHA1_DISAMBIGUATORS;
-               sub_flags |= GET_SHA1_TREEISH;
+               sub_flags &= ~GET_OID_DISAMBIGUATORS;
+               sub_flags |= GET_OID_TREEISH;
 
-               if (!get_sha1_1(name, len, tree_sha1, sub_flags)) {
+               if (!get_oid_1(name, len, &tree_oid, sub_flags)) {
                        const char *filename = cp+1;
                        char *new_filename = NULL;
 
                        new_filename = resolve_relative_path(filename);
                        if (new_filename)
                                filename = new_filename;
-                       if (flags & GET_SHA1_FOLLOW_SYMLINKS) {
-                               ret = get_tree_entry_follow_symlinks(tree_sha1,
-                                       filename, sha1, &oc->symlink_path,
+                       if (flags & GET_OID_FOLLOW_SYMLINKS) {
+                               ret = get_tree_entry_follow_symlinks(tree_oid.hash,
+                                       filename, oid->hash, &oc->symlink_path,
                                        &oc->mode);
                        } else {
-                               ret = get_tree_entry(tree_sha1, filename,
-                                                    sha1, &oc->mode);
+                               ret = get_tree_entry(tree_oid.hash, filename,
+                                                    oid->hash, &oc->mode);
                                if (ret && only_to_die) {
-                                       diagnose_invalid_sha1_path(prefix,
+                                       diagnose_invalid_oid_path(prefix,
                                                                   filename,
-                                                                  tree_sha1,
+                                                                  &tree_oid,
                                                                   name, len);
                                }
                        }
-                       hashcpy(oc->tree, tree_sha1);
-                       strlcpy(oc->path, filename, sizeof(oc->path));
+                       hashcpy(oc->tree, tree_oid.hash);
+                       if (flags & GET_OID_RECORD_PATH)
+                               oc->path = xstrdup(filename);
 
                        free(new_filename);
                        return ret;
@@ -1632,13 +1638,13 @@ static int get_sha1_with_context_1(const char *name,
 void maybe_die_on_misspelt_object_name(const char *name, const char *prefix)
 {
        struct object_context oc;
-       unsigned char sha1[20];
-       get_sha1_with_context_1(name, GET_SHA1_ONLY_TO_DIE, prefix, sha1, &oc);
+       struct object_id oid;
+       get_oid_with_context_1(name, GET_OID_ONLY_TO_DIE, prefix, &oid, &oc);
 }
 
-int get_sha1_with_context(const char *str, unsigned flags, unsigned char *sha1, struct object_context *orc)
+int get_oid_with_context(const char *str, unsigned flags, struct object_id *oid, struct object_context *oc)
 {
-       if (flags & GET_SHA1_FOLLOW_SYMLINKS && flags & GET_SHA1_ONLY_TO_DIE)
+       if (flags & GET_OID_FOLLOW_SYMLINKS && flags & GET_OID_ONLY_TO_DIE)
                die("BUG: incompatible flags for get_sha1_with_context");
-       return get_sha1_with_context_1(str, flags, NULL, sha1, orc);
+       return get_oid_with_context_1(str, flags, NULL, oid, oc);
 }