Imported Upstream version 2.30.0
[platform/upstream/git.git] / sha1-file.c
index 97b7423..c3c49d2 100644 (file)
@@ -30,8 +30,8 @@
 #include "mergesort.h"
 #include "quote.h"
 #include "packfile.h"
-#include "fetch-object.h"
 #include "object-store.h"
+#include "promisor-remote.h"
 
 /* The maximum size for an object header. */
 #define MAX_HEADER_LEN 32
 #define EMPTY_TREE_SHA1_BIN_LITERAL \
         "\x4b\x82\x5d\xc6\x42\xcb\x6e\xb9\xa0\x60" \
         "\xe5\x4b\xf8\xd6\x92\x88\xfb\xee\x49\x04"
+#define EMPTY_TREE_SHA256_BIN_LITERAL \
+       "\x6e\xf1\x9b\x41\x22\x5c\x53\x69\xf1\xc1" \
+       "\x04\xd4\x5d\x8d\x85\xef\xa9\xb0\x57\xb5" \
+       "\x3b\x14\xb4\xb9\xb9\x39\xdd\x74\xde\xcc" \
+       "\x53\x21"
 
 #define EMPTY_BLOB_SHA1_BIN_LITERAL \
        "\xe6\x9d\xe2\x9b\xb2\xd1\xd6\x43\x4b\x8b" \
        "\x29\xae\x77\x5a\xd8\xc2\xe4\x8c\x53\x91"
+#define EMPTY_BLOB_SHA256_BIN_LITERAL \
+       "\x47\x3a\x0f\x4c\x3b\xe8\xa9\x36\x81\xa2" \
+       "\x67\xe3\xb1\xe9\xa7\xdc\xda\x11\x85\x43" \
+       "\x6f\xe1\x41\xf7\x74\x91\x20\xa3\x03\x72" \
+       "\x18\x13"
 
-const unsigned char null_sha1[GIT_MAX_RAWSZ];
 const struct object_id null_oid;
 static const struct object_id empty_tree_oid = {
        EMPTY_TREE_SHA1_BIN_LITERAL
@@ -53,12 +62,23 @@ static const struct object_id empty_tree_oid = {
 static const struct object_id empty_blob_oid = {
        EMPTY_BLOB_SHA1_BIN_LITERAL
 };
+static const struct object_id empty_tree_oid_sha256 = {
+       EMPTY_TREE_SHA256_BIN_LITERAL
+};
+static const struct object_id empty_blob_oid_sha256 = {
+       EMPTY_BLOB_SHA256_BIN_LITERAL
+};
 
 static void git_hash_sha1_init(git_hash_ctx *ctx)
 {
        git_SHA1_Init(&ctx->sha1);
 }
 
+static void git_hash_sha1_clone(git_hash_ctx *dst, const git_hash_ctx *src)
+{
+       git_SHA1_Clone(&dst->sha1, &src->sha1);
+}
+
 static void git_hash_sha1_update(git_hash_ctx *ctx, const void *data, size_t len)
 {
        git_SHA1_Update(&ctx->sha1, data, len);
@@ -69,11 +89,37 @@ static void git_hash_sha1_final(unsigned char *hash, git_hash_ctx *ctx)
        git_SHA1_Final(hash, &ctx->sha1);
 }
 
+
+static void git_hash_sha256_init(git_hash_ctx *ctx)
+{
+       git_SHA256_Init(&ctx->sha256);
+}
+
+static void git_hash_sha256_clone(git_hash_ctx *dst, const git_hash_ctx *src)
+{
+       git_SHA256_Clone(&dst->sha256, &src->sha256);
+}
+
+static void git_hash_sha256_update(git_hash_ctx *ctx, const void *data, size_t len)
+{
+       git_SHA256_Update(&ctx->sha256, data, len);
+}
+
+static void git_hash_sha256_final(unsigned char *hash, git_hash_ctx *ctx)
+{
+       git_SHA256_Final(hash, &ctx->sha256);
+}
+
 static void git_hash_unknown_init(git_hash_ctx *ctx)
 {
        BUG("trying to init unknown hash");
 }
 
+static void git_hash_unknown_clone(git_hash_ctx *dst, const git_hash_ctx *src)
+{
+       BUG("trying to clone unknown hash");
+}
+
 static void git_hash_unknown_update(git_hash_ctx *ctx, const void *data, size_t len)
 {
        BUG("trying to update unknown hash");
@@ -90,24 +136,42 @@ const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = {
                0x00000000,
                0,
                0,
+               0,
                git_hash_unknown_init,
+               git_hash_unknown_clone,
                git_hash_unknown_update,
                git_hash_unknown_final,
                NULL,
                NULL,
        },
        {
-               "sha-1",
+               "sha1",
                /* "sha1", big-endian */
                0x73686131,
                GIT_SHA1_RAWSZ,
                GIT_SHA1_HEXSZ,
+               GIT_SHA1_BLKSZ,
                git_hash_sha1_init,
+               git_hash_sha1_clone,
                git_hash_sha1_update,
                git_hash_sha1_final,
                &empty_tree_oid,
                &empty_blob_oid,
        },
+       {
+               "sha256",
+               /* "s256", big-endian */
+               0x73323536,
+               GIT_SHA256_RAWSZ,
+               GIT_SHA256_HEXSZ,
+               GIT_SHA256_BLKSZ,
+               git_hash_sha256_init,
+               git_hash_sha256_clone,
+               git_hash_sha256_update,
+               git_hash_sha256_final,
+               &empty_tree_oid_sha256,
+               &empty_blob_oid_sha256,
+       }
 };
 
 const char *empty_tree_oid_hex(void)
@@ -122,9 +186,38 @@ const char *empty_blob_oid_hex(void)
        return oid_to_hex_r(buf, the_hash_algo->empty_blob);
 }
 
+int hash_algo_by_name(const char *name)
+{
+       int i;
+       if (!name)
+               return GIT_HASH_UNKNOWN;
+       for (i = 1; i < GIT_HASH_NALGOS; i++)
+               if (!strcmp(name, hash_algos[i].name))
+                       return i;
+       return GIT_HASH_UNKNOWN;
+}
+
+int hash_algo_by_id(uint32_t format_id)
+{
+       int i;
+       for (i = 1; i < GIT_HASH_NALGOS; i++)
+               if (format_id == hash_algos[i].format_id)
+                       return i;
+       return GIT_HASH_UNKNOWN;
+}
+
+int hash_algo_by_length(int len)
+{
+       int i;
+       for (i = 1; i < GIT_HASH_NALGOS; i++)
+               if (len == hash_algos[i].rawsz)
+                       return i;
+       return GIT_HASH_UNKNOWN;
+}
+
 /*
  * This is meant to hold a *small* number of objects that you would
- * want read_sha1_file() to be able to return, but yet you do not want
+ * want read_object_file() to be able to return, but yet you do not want
  * to write them into the object store (e.g. a browse-only
  * application).
  */
@@ -149,10 +242,10 @@ static struct cached_object *find_cached_object(const struct object_id *oid)
        struct cached_object *co = cached_objects;
 
        for (i = 0; i < cached_object_nr; i++, co++) {
-               if (!oidcmp(&co->oid, oid))
+               if (oideq(&co->oid, oid))
                        return co;
        }
-       if (!oidcmp(oid, the_hash_algo->empty_tree))
+       if (oideq(oid, the_hash_algo->empty_tree))
                return &empty_tree;
        return NULL;
 }
@@ -198,7 +291,7 @@ int mkdir_in_gitdir(const char *path)
        return adjust_shared_perm(path);
 }
 
-enum scld_error safe_create_leading_directories(char *path)
+static enum scld_error safe_create_leading_directories_1(char *path, int share)
 {
        char *next_component = path + offset_1st_component(path);
        enum scld_error ret = SCLD_OK;
@@ -244,7 +337,7 @@ enum scld_error safe_create_leading_directories(char *path)
                                ret = SCLD_VANISHED;
                        else
                                ret = SCLD_FAILED;
-               } else if (adjust_shared_perm(path)) {
+               } else if (share && adjust_shared_perm(path)) {
                        ret = SCLD_PERMS;
                }
                *slash = slash_character;
@@ -252,6 +345,16 @@ enum scld_error safe_create_leading_directories(char *path)
        return ret;
 }
 
+enum scld_error safe_create_leading_directories(char *path)
+{
+       return safe_create_leading_directories_1(path, 1);
+}
+
+enum scld_error safe_create_leading_directories_no_share(char *path)
+{
+       return safe_create_leading_directories_1(path, 0);
+}
+
 enum scld_error safe_create_leading_directories_const(const char *path)
 {
        int save_errno;
@@ -333,12 +436,12 @@ out:
        return ret;
 }
 
-static void fill_sha1_path(struct strbuf *buf, const unsigned char *sha1)
+static void fill_loose_path(struct strbuf *buf, const struct object_id *oid)
 {
        int i;
        for (i = 0; i < the_hash_algo->rawsz; i++) {
                static char hex[] = "0123456789abcdef";
-               unsigned int val = sha1[i];
+               unsigned int val = oid->hash[i];
                strbuf_addch(buf, hex[val >> 4]);
                strbuf_addch(buf, hex[val & 0xf]);
                if (!i)
@@ -346,25 +449,21 @@ static void fill_sha1_path(struct strbuf *buf, const unsigned char *sha1)
        }
 }
 
-void sha1_file_name(struct repository *r, struct strbuf *buf, const unsigned char *sha1)
+static const char *odb_loose_path(struct object_directory *odb,
+                                 struct strbuf *buf,
+                                 const struct object_id *oid)
 {
-       strbuf_addstr(buf, r->objects->objectdir);
+       strbuf_reset(buf);
+       strbuf_addstr(buf, odb->path);
        strbuf_addch(buf, '/');
-       fill_sha1_path(buf, sha1);
-}
-
-struct strbuf *alt_scratch_buf(struct alternate_object_database *alt)
-{
-       strbuf_setlen(&alt->scratch, alt->base_len);
-       return &alt->scratch;
+       fill_loose_path(buf, oid);
+       return buf->buf;
 }
 
-static const char *alt_sha1_path(struct alternate_object_database *alt,
-                                const unsigned char *sha1)
+const char *loose_object_path(struct repository *r, struct strbuf *buf,
+                             const struct object_id *oid)
 {
-       struct strbuf *buf = alt_scratch_buf(alt);
-       fill_sha1_path(buf, sha1);
-       return buf->buf;
+       return odb_loose_path(r->objects->odb, buf, oid);
 }
 
 /*
@@ -374,7 +473,7 @@ static int alt_odb_usable(struct raw_object_store *o,
                          struct strbuf *path,
                          const char *normalized_objdir)
 {
-       struct alternate_object_database *alt;
+       struct object_directory *odb;
 
        /* Detect cases where alternate disappeared */
        if (!is_directory(path->buf)) {
@@ -388,8 +487,8 @@ static int alt_odb_usable(struct raw_object_store *o,
         * Prevent the common mistake of listing the same
         * thing twice, or object directory itself.
         */
-       for (alt = o->alt_odb_list; alt; alt = alt->next) {
-               if (!fspathcmp(path->buf, alt->path))
+       for (odb = o->odb; odb; odb = odb->next) {
+               if (!fspathcmp(path->buf, odb->path))
                        return 0;
        }
        if (!fspathcmp(path->buf, normalized_objdir))
@@ -402,7 +501,7 @@ static int alt_odb_usable(struct raw_object_store *o,
  * Prepare alternate object database registry.
  *
  * The variable alt_odb_list points at the list of struct
- * alternate_object_database.  The elements on this list come from
+ * object_directory.  The elements on this list come from
  * non-empty elements from colon separated ALTERNATE_DB_ENVIRONMENT
  * environment variable, and $GIT_OBJECT_DIRECTORY/info/alternates,
  * whose contents is similar to that environment variable but can be
@@ -419,7 +518,7 @@ static void read_info_alternates(struct repository *r,
 static int link_alt_odb_entry(struct repository *r, const char *entry,
        const char *relative_base, int depth, const char *normalized_objdir)
 {
-       struct alternate_object_database *ent;
+       struct object_directory *ent;
        struct strbuf pathbuf = STRBUF_INIT;
 
        if (!is_absolute_path(entry) && relative_base) {
@@ -447,11 +546,12 @@ static int link_alt_odb_entry(struct repository *r, const char *entry,
                return -1;
        }
 
-       ent = alloc_alt_odb(pathbuf.buf);
+       ent = xcalloc(1, sizeof(*ent));
+       ent->path = xstrdup(pathbuf.buf);
 
        /* add the alternate entry */
-       *r->objects->alt_odb_tail = ent;
-       r->objects->alt_odb_tail = &(ent->next);
+       *r->objects->odb_tail = ent;
+       r->objects->odb_tail = &(ent->next);
        ent->next = NULL;
 
        /* recursively add alternates */
@@ -505,7 +605,7 @@ static void link_alt_odb_entries(struct repository *r, const char *alt,
                return;
        }
 
-       strbuf_add_absolute_path(&objdirbuf, r->objects->objectdir);
+       strbuf_add_absolute_path(&objdirbuf, r->objects->odb->path);
        if (strbuf_normalize_path(&objdirbuf) < 0)
                die(_("unable to normalize object directory: %s"),
                    objdirbuf.buf);
@@ -540,18 +640,6 @@ static void read_info_alternates(struct repository *r,
        free(path);
 }
 
-struct alternate_object_database *alloc_alt_odb(const char *dir)
-{
-       struct alternate_object_database *ent;
-
-       FLEX_ALLOC_STR(ent, path, dir);
-       strbuf_init(&ent->scratch, 0);
-       strbuf_addf(&ent->scratch, "%s/", dir);
-       ent->base_len = ent->scratch.len;
-
-       return ent;
-}
-
 void add_to_alternates_file(const char *reference)
 {
        struct lock_file lock = LOCK_INIT;
@@ -588,7 +676,7 @@ void add_to_alternates_file(const char *reference)
                fprintf_or_die(out, "%s\n", reference);
                if (commit_lock_file(&lock))
                        die_errno(_("unable to move new alternates file into place"));
-               if (the_repository->objects->alt_odb_tail)
+               if (the_repository->objects->loaded_alternates)
                        link_alt_odb_entries(the_repository, reference,
                                             '\n', NULL, 0);
        }
@@ -616,20 +704,15 @@ void add_to_alternates_memory(const char *reference)
 char *compute_alternate_path(const char *path, struct strbuf *err)
 {
        char *ref_git = NULL;
-       const char *repo, *ref_git_s;
+       const char *repo;
        int seen_error = 0;
 
-       ref_git_s = real_path_if_valid(path);
-       if (!ref_git_s) {
+       ref_git = real_pathdup(path, 0);
+       if (!ref_git) {
                seen_error = 1;
                strbuf_addf(err, _("path '%s' does not exist"), path);
                goto out;
-       } else
-               /*
-                * Beware: read_gitfile(), real_path() and mkpath()
-                * return static buffer
-                */
-               ref_git = xstrdup(ref_git_s);
+       }
 
        repo = read_gitfile(ref_git);
        if (!repo)
@@ -682,13 +765,111 @@ out:
        return ref_git;
 }
 
+static void fill_alternate_refs_command(struct child_process *cmd,
+                                       const char *repo_path)
+{
+       const char *value;
+
+       if (!git_config_get_value("core.alternateRefsCommand", &value)) {
+               cmd->use_shell = 1;
+
+               strvec_push(&cmd->args, value);
+               strvec_push(&cmd->args, repo_path);
+       } else {
+               cmd->git_cmd = 1;
+
+               strvec_pushf(&cmd->args, "--git-dir=%s", repo_path);
+               strvec_push(&cmd->args, "for-each-ref");
+               strvec_push(&cmd->args, "--format=%(objectname)");
+
+               if (!git_config_get_value("core.alternateRefsPrefixes", &value)) {
+                       strvec_push(&cmd->args, "--");
+                       strvec_split(&cmd->args, value);
+               }
+       }
+
+       cmd->env = local_repo_env;
+       cmd->out = -1;
+}
+
+static void read_alternate_refs(const char *path,
+                               alternate_ref_fn *cb,
+                               void *data)
+{
+       struct child_process cmd = CHILD_PROCESS_INIT;
+       struct strbuf line = STRBUF_INIT;
+       FILE *fh;
+
+       fill_alternate_refs_command(&cmd, path);
+
+       if (start_command(&cmd))
+               return;
+
+       fh = xfdopen(cmd.out, "r");
+       while (strbuf_getline_lf(&line, fh) != EOF) {
+               struct object_id oid;
+               const char *p;
+
+               if (parse_oid_hex(line.buf, &oid, &p) || *p) {
+                       warning(_("invalid line while parsing alternate refs: %s"),
+                               line.buf);
+                       break;
+               }
+
+               cb(&oid, data);
+       }
+
+       fclose(fh);
+       finish_command(&cmd);
+       strbuf_release(&line);
+}
+
+struct alternate_refs_data {
+       alternate_ref_fn *fn;
+       void *data;
+};
+
+static int refs_from_alternate_cb(struct object_directory *e,
+                                 void *data)
+{
+       struct strbuf path = STRBUF_INIT;
+       size_t base_len;
+       struct alternate_refs_data *cb = data;
+
+       if (!strbuf_realpath(&path, e->path, 0))
+               goto out;
+       if (!strbuf_strip_suffix(&path, "/objects"))
+               goto out;
+       base_len = path.len;
+
+       /* Is this a git repository with refs? */
+       strbuf_addstr(&path, "/refs");
+       if (!is_directory(path.buf))
+               goto out;
+       strbuf_setlen(&path, base_len);
+
+       read_alternate_refs(path.buf, cb->fn, cb->data);
+
+out:
+       strbuf_release(&path);
+       return 0;
+}
+
+void for_each_alternate_ref(alternate_ref_fn fn, void *data)
+{
+       struct alternate_refs_data cb;
+       cb.fn = fn;
+       cb.data = data;
+       foreach_alt_odb(refs_from_alternate_cb, &cb);
+}
+
 int foreach_alt_odb(alt_odb_fn fn, void *cb)
 {
-       struct alternate_object_database *ent;
+       struct object_directory *ent;
        int r = 0;
 
        prepare_alt_odb(the_repository);
-       for (ent = the_repository->objects->alt_odb_list; ent; ent = ent->next) {
+       for (ent = the_repository->objects->odb->next; ent; ent = ent->next) {
                r = fn(ent, cb);
                if (r)
                        break;
@@ -698,21 +879,19 @@ int foreach_alt_odb(alt_odb_fn fn, void *cb)
 
 void prepare_alt_odb(struct repository *r)
 {
-       if (r->objects->alt_odb_tail)
+       if (r->objects->loaded_alternates)
                return;
 
-       r->objects->alt_odb_tail = &r->objects->alt_odb_list;
        link_alt_odb_entries(r, r->objects->alternate_db, PATH_SEP, NULL, 0);
 
-       read_info_alternates(r, r->objects->objectdir, 0);
+       read_info_alternates(r, r->objects->odb->path, 0);
+       r->objects->loaded_alternates = 1;
 }
 
 /* Returns 1 if we have successfully freshened the file, 0 otherwise. */
 static int freshen_file(const char *fn)
 {
-       struct utimbuf t;
-       t.actime = t.modtime = time(NULL);
-       return !utime(fn, &t);
+       return !utime(fn, NULL);
 }
 
 /*
@@ -731,23 +910,27 @@ int check_and_freshen_file(const char *fn, int freshen)
        return 1;
 }
 
-static int check_and_freshen_local(const struct object_id *oid, int freshen)
+static int check_and_freshen_odb(struct object_directory *odb,
+                                const struct object_id *oid,
+                                int freshen)
 {
-       static struct strbuf buf = STRBUF_INIT;
-
-       strbuf_reset(&buf);
-       sha1_file_name(the_repository, &buf, oid->hash);
+       static struct strbuf path = STRBUF_INIT;
+       odb_loose_path(odb, &path, oid);
+       return check_and_freshen_file(path.buf, freshen);
+}
 
-       return check_and_freshen_file(buf.buf, freshen);
+static int check_and_freshen_local(const struct object_id *oid, int freshen)
+{
+       return check_and_freshen_odb(the_repository->objects->odb, oid, freshen);
 }
 
 static int check_and_freshen_nonlocal(const struct object_id *oid, int freshen)
 {
-       struct alternate_object_database *alt;
+       struct object_directory *odb;
+
        prepare_alt_odb(the_repository);
-       for (alt = the_repository->objects->alt_odb_list; alt; alt = alt->next) {
-               const char *path = alt_sha1_path(alt, oid->hash);
-               if (check_and_freshen_file(path, freshen))
+       for (odb = the_repository->objects->odb->next; odb; odb = odb->next) {
+               if (check_and_freshen_odb(odb, oid, freshen))
                        return 1;
        }
        return 0;
@@ -789,12 +972,8 @@ void *xmmap_gently(void *start, size_t length,
 
        mmap_limit_check(length);
        ret = mmap(start, length, prot, flags, fd, offset);
-       if (ret == MAP_FAILED) {
-               if (!length)
-                       return NULL;
-               release_pack_memory(length);
-               ret = mmap(start, length, prot, flags, fd, offset);
-       }
+       if (ret == MAP_FAILED && !length)
+               ret = NULL;
        return ret;
 }
 
@@ -809,12 +988,12 @@ void *xmmap(void *start, size_t length,
 
 /*
  * With an in-core object data in "map", rehash it to make sure the
- * object name actually matches "sha1" to detect object corruption.
- * With "map" == NULL, try reading the object named with "sha1" using
+ * object name actually matches "oid" to detect object corruption.
+ * With "map" == NULL, try reading the object named with "oid" using
  * the streaming interface and rehash it to do the same.
  */
-int check_object_signature(const struct object_id *oid, void *map,
-                          unsigned long size, const char *type)
+int check_object_signature(struct repository *r, const struct object_id *oid,
+                          void *map, unsigned long size, const char *type)
 {
        struct object_id real_oid;
        enum object_type obj_type;
@@ -824,20 +1003,20 @@ int check_object_signature(const struct object_id *oid, void *map,
        int hdrlen;
 
        if (map) {
-               hash_object_file(map, size, type, &real_oid);
-               return oidcmp(oid, &real_oid) ? -1 : 0;
+               hash_object_file(r->hash_algo, map, size, type, &real_oid);
+               return !oideq(oid, &real_oid) ? -1 : 0;
        }
 
-       st = open_istream(oid, &obj_type, &size, NULL);
+       st = open_istream(r, oid, &obj_type, &size, NULL);
        if (!st)
                return -1;
 
        /* Generate the header */
-       hdrlen = xsnprintf(hdr, sizeof(hdr), "%s %lu", type_name(obj_type), size) + 1;
+       hdrlen = xsnprintf(hdr, sizeof(hdr), "%s %"PRIuMAX , type_name(obj_type), (uintmax_t)size) + 1;
 
        /* Sha1.. */
-       the_hash_algo->init_fn(&c);
-       the_hash_algo->update_fn(&c, hdr, hdrlen);
+       r->hash_algo->init_fn(&c);
+       r->hash_algo->update_fn(&c, hdr, hdrlen);
        for (;;) {
                char buf[1024 * 16];
                ssize_t readlen = read_istream(st, buf, sizeof(buf));
@@ -848,11 +1027,11 @@ int check_object_signature(const struct object_id *oid, void *map,
                }
                if (!readlen)
                        break;
-               the_hash_algo->update_fn(&c, buf, readlen);
+               r->hash_algo->update_fn(&c, buf, readlen);
        }
-       the_hash_algo->final_fn(real_oid.hash, &c);
+       r->hash_algo->final_fn(real_oid.hash, &c);
        close_istream(st);
-       return oidcmp(oid, &real_oid) ? -1 : 0;
+       return !oideq(oid, &real_oid) ? -1 : 0;
 }
 
 int git_open_cloexec(const char *name, int flags)
@@ -883,30 +1062,22 @@ int git_open_cloexec(const char *name, int flags)
 }
 
 /*
- * Find "sha1" as a loose object in the local repository or in an alternate.
+ * Find "oid" as a loose object in the local repository or in an alternate.
  * Returns 0 on success, negative on failure.
  *
  * The "path" out-parameter will give the path of the object we found (if any).
  * Note that it may point to static storage and is only valid until another
- * call to sha1_file_name(), etc.
+ * call to stat_loose_object().
  */
-static int stat_sha1_file(struct repository *r, const unsigned char *sha1,
-                         struct stat *st, const char **path)
+static int stat_loose_object(struct repository *r, const struct object_id *oid,
+                            struct stat *st, const char **path)
 {
-       struct alternate_object_database *alt;
+       struct object_directory *odb;
        static struct strbuf buf = STRBUF_INIT;
 
-       strbuf_reset(&buf);
-       sha1_file_name(r, &buf, sha1);
-       *path = buf.buf;
-
-       if (!lstat(*path, st))
-               return 0;
-
        prepare_alt_odb(r);
-       errno = ENOENT;
-       for (alt = r->objects->alt_odb_list; alt; alt = alt->next) {
-               *path = alt_sha1_path(alt, sha1);
+       for (odb = r->objects->odb; odb; odb = odb->next) {
+               *path = odb_loose_path(odb, &buf, oid);
                if (!lstat(*path, st))
                        return 0;
        }
@@ -915,32 +1086,24 @@ static int stat_sha1_file(struct repository *r, const unsigned char *sha1,
 }
 
 /*
- * Like stat_sha1_file(), but actually open the object and return the
+ * Like stat_loose_object(), but actually open the object and return the
  * descriptor. See the caveats on the "path" parameter above.
  */
-static int open_sha1_file(struct repository *r,
-                         const unsigned char *sha1, const char **path)
+static int open_loose_object(struct repository *r,
+                            const struct object_id *oid, const char **path)
 {
        int fd;
-       struct alternate_object_database *alt;
-       int most_interesting_errno;
+       struct object_directory *odb;
+       int most_interesting_errno = ENOENT;
        static struct strbuf buf = STRBUF_INIT;
 
-       strbuf_reset(&buf);
-       sha1_file_name(r, &buf, sha1);
-       *path = buf.buf;
-
-       fd = git_open(*path);
-       if (fd >= 0)
-               return fd;
-       most_interesting_errno = errno;
-
        prepare_alt_odb(r);
-       for (alt = r->objects->alt_odb_list; alt; alt = alt->next) {
-               *path = alt_sha1_path(alt, sha1);
+       for (odb = r->objects->odb; odb; odb = odb->next) {
+               *path = odb_loose_path(odb, &buf, oid);
                fd = git_open(*path);
                if (fd >= 0)
                        return fd;
+
                if (most_interesting_errno == ENOENT)
                        most_interesting_errno = errno;
        }
@@ -948,12 +1111,25 @@ static int open_sha1_file(struct repository *r,
        return -1;
 }
 
+static int quick_has_loose(struct repository *r,
+                          const struct object_id *oid)
+{
+       struct object_directory *odb;
+
+       prepare_alt_odb(r);
+       for (odb = r->objects->odb; odb; odb = odb->next) {
+               if (oid_array_lookup(odb_loose_cache(odb, oid), oid) >= 0)
+                       return 1;
+       }
+       return 0;
+}
+
 /*
  * Map the loose object at "path" if it is not NULL, or the path found by
- * searching for a loose object named "sha1".
+ * searching for a loose object named "oid".
  */
-static void *map_sha1_file_1(struct repository *r, const char *path,
-                            const unsigned char *sha1, unsigned long *size)
+static void *map_loose_object_1(struct repository *r, const char *path,
+                            const struct object_id *oid, unsigned long *size)
 {
        void *map;
        int fd;
@@ -961,7 +1137,7 @@ static void *map_sha1_file_1(struct repository *r, const char *path,
        if (path)
                fd = git_open(path);
        else
-               fd = open_sha1_file(r, sha1, &path);
+               fd = open_loose_object(r, oid, &path);
        map = NULL;
        if (fd >= 0) {
                struct stat st;
@@ -971,6 +1147,7 @@ static void *map_sha1_file_1(struct repository *r, const char *path,
                        if (!*size) {
                                /* mmap() is forbidden on empty files */
                                error(_("object file %s is empty"), path);
+                               close(fd);
                                return NULL;
                        }
                        map = xmmap(NULL, *size, PROT_READ, MAP_PRIVATE, fd, 0);
@@ -980,16 +1157,19 @@ static void *map_sha1_file_1(struct repository *r, const char *path,
        return map;
 }
 
-void *map_sha1_file(struct repository *r,
-                   const unsigned char *sha1, unsigned long *size)
+void *map_loose_object(struct repository *r,
+                      const struct object_id *oid,
+                      unsigned long *size)
 {
-       return map_sha1_file_1(r, NULL, sha1, size);
+       return map_loose_object_1(r, NULL, oid, size);
 }
 
-static int unpack_sha1_short_header(git_zstream *stream,
-                                   unsigned char *map, unsigned long mapsize,
-                                   void *buffer, unsigned long bufsiz)
+static int unpack_loose_short_header(git_zstream *stream,
+                                    unsigned char *map, unsigned long mapsize,
+                                    void *buffer, unsigned long bufsiz)
 {
+       int ret;
+
        /* Get the data stream */
        memset(stream, 0, sizeof(*stream));
        stream->next_in = map;
@@ -998,15 +1178,19 @@ static int unpack_sha1_short_header(git_zstream *stream,
        stream->avail_out = bufsiz;
 
        git_inflate_init(stream);
-       return git_inflate(stream, 0);
+       obj_read_unlock();
+       ret = git_inflate(stream, 0);
+       obj_read_lock();
+
+       return ret;
 }
 
-int unpack_sha1_header(git_zstream *stream,
-                      unsigned char *map, unsigned long mapsize,
-                      void *buffer, unsigned long bufsiz)
+int unpack_loose_header(git_zstream *stream,
+                       unsigned char *map, unsigned long mapsize,
+                       void *buffer, unsigned long bufsiz)
 {
-       int status = unpack_sha1_short_header(stream, map, mapsize,
-                                             buffer, bufsiz);
+       int status = unpack_loose_short_header(stream, map, mapsize,
+                                              buffer, bufsiz);
 
        if (status < Z_OK)
                return status;
@@ -1017,13 +1201,13 @@ int unpack_sha1_header(git_zstream *stream,
        return 0;
 }
 
-static int unpack_sha1_header_to_strbuf(git_zstream *stream, unsigned char *map,
-                                       unsigned long mapsize, void *buffer,
-                                       unsigned long bufsiz, struct strbuf *header)
+static int unpack_loose_header_to_strbuf(git_zstream *stream, unsigned char *map,
+                                        unsigned long mapsize, void *buffer,
+                                        unsigned long bufsiz, struct strbuf *header)
 {
        int status;
 
-       status = unpack_sha1_short_header(stream, map, mapsize, buffer, bufsiz);
+       status = unpack_loose_short_header(stream, map, mapsize, buffer, bufsiz);
        if (status < Z_OK)
                return -1;
 
@@ -1043,7 +1227,9 @@ static int unpack_sha1_header_to_strbuf(git_zstream *stream, unsigned char *map,
        stream->avail_out = bufsiz;
 
        do {
+               obj_read_unlock();
                status = git_inflate(stream, 0);
+               obj_read_lock();
                strbuf_add(header, buffer, stream->next_out - (unsigned char *)buffer);
                if (memchr(buffer, '\0', stream->next_out - (unsigned char *)buffer))
                        return 0;
@@ -1053,7 +1239,9 @@ static int unpack_sha1_header_to_strbuf(git_zstream *stream, unsigned char *map,
        return -1;
 }
 
-static void *unpack_sha1_rest(git_zstream *stream, void *buffer, unsigned long size, const unsigned char *sha1)
+static void *unpack_loose_rest(git_zstream *stream,
+                              void *buffer, unsigned long size,
+                              const struct object_id *oid)
 {
        int bytes = strlen(buffer) + 1;
        unsigned char *buf = xmallocz(size);
@@ -1081,8 +1269,11 @@ static void *unpack_sha1_rest(git_zstream *stream, void *buffer, unsigned long s
                 */
                stream->next_out = buf + bytes;
                stream->avail_out = size - bytes;
-               while (status == Z_OK)
+               while (status == Z_OK) {
+                       obj_read_unlock();
                        status = git_inflate(stream, Z_FINISH);
+                       obj_read_lock();
+               }
        }
        if (status == Z_STREAM_END && !stream->avail_in) {
                git_inflate_end(stream);
@@ -1090,10 +1281,10 @@ static void *unpack_sha1_rest(git_zstream *stream, void *buffer, unsigned long s
        }
 
        if (status < 0)
-               error(_("corrupt loose object '%s'"), sha1_to_hex(sha1));
+               error(_("corrupt loose object '%s'"), oid_to_hex(oid));
        else if (stream->avail_in)
                error(_("garbage at end of loose object '%s'"),
-                     sha1_to_hex(sha1));
+                     oid_to_hex(oid));
        free(buf);
        return NULL;
 }
@@ -1103,8 +1294,8 @@ static void *unpack_sha1_rest(git_zstream *stream, void *buffer, unsigned long s
  * too permissive for what we want to check. So do an anal
  * object header parse by hand.
  */
-static int parse_sha1_header_extended(const char *hdr, struct object_info *oi,
-                              unsigned int flags)
+static int parse_loose_header_extended(const char *hdr, struct object_info *oi,
+                                      unsigned int flags)
 {
        const char *type_buf = hdr;
        unsigned long size;
@@ -1164,17 +1355,17 @@ static int parse_sha1_header_extended(const char *hdr, struct object_info *oi,
        return *hdr ? -1 : type;
 }
 
-int parse_sha1_header(const char *hdr, unsigned long *sizep)
+int parse_loose_header(const char *hdr, unsigned long *sizep)
 {
        struct object_info oi = OBJECT_INFO_INIT;
 
        oi.sizep = sizep;
-       return parse_sha1_header_extended(hdr, &oi, 0);
+       return parse_loose_header_extended(hdr, &oi, 0);
 }
 
-static int sha1_loose_object_info(struct repository *r,
-                                 const unsigned char *sha1,
-                                 struct object_info *oi, int flags)
+static int loose_object_info(struct repository *r,
+                            const struct object_id *oid,
+                            struct object_info *oi, int flags)
 {
        int status = 0;
        unsigned long mapsize;
@@ -1184,8 +1375,8 @@ static int sha1_loose_object_info(struct repository *r,
        struct strbuf hdrbuf = STRBUF_INIT;
        unsigned long size_scratch;
 
-       if (oi->delta_base_sha1)
-               hashclr(oi->delta_base_sha1);
+       if (oi->delta_base_oid)
+               oidclr(oi->delta_base_oid);
 
        /*
         * If we don't care about type or size, then we don't
@@ -1198,14 +1389,16 @@ static int sha1_loose_object_info(struct repository *r,
        if (!oi->typep && !oi->type_name && !oi->sizep && !oi->contentp) {
                const char *path;
                struct stat st;
-               if (stat_sha1_file(r, sha1, &st, &path) < 0)
+               if (!oi->disk_sizep && (flags & OBJECT_INFO_QUICK))
+                       return quick_has_loose(r, oid) ? 0 : -1;
+               if (stat_loose_object(r, oid, &st, &path) < 0)
                        return -1;
                if (oi->disk_sizep)
                        *oi->disk_sizep = st.st_size;
                return 0;
        }
 
-       map = map_sha1_file(r, sha1, &mapsize);
+       map = map_loose_object(r, oid, &mapsize);
        if (!map)
                return -1;
 
@@ -1215,24 +1408,24 @@ static int sha1_loose_object_info(struct repository *r,
        if (oi->disk_sizep)
                *oi->disk_sizep = mapsize;
        if ((flags & OBJECT_INFO_ALLOW_UNKNOWN_TYPE)) {
-               if (unpack_sha1_header_to_strbuf(&stream, map, mapsize, hdr, sizeof(hdr), &hdrbuf) < 0)
+               if (unpack_loose_header_to_strbuf(&stream, map, mapsize, hdr, sizeof(hdr), &hdrbuf) < 0)
                        status = error(_("unable to unpack %s header with --allow-unknown-type"),
-                                      sha1_to_hex(sha1));
-       } else if (unpack_sha1_header(&stream, map, mapsize, hdr, sizeof(hdr)) < 0)
+                                      oid_to_hex(oid));
+       } else if (unpack_loose_header(&stream, map, mapsize, hdr, sizeof(hdr)) < 0)
                status = error(_("unable to unpack %s header"),
-                              sha1_to_hex(sha1));
+                              oid_to_hex(oid));
        if (status < 0)
                ; /* Do nothing */
        else if (hdrbuf.len) {
-               if ((status = parse_sha1_header_extended(hdrbuf.buf, oi, flags)) < 0)
+               if ((status = parse_loose_header_extended(hdrbuf.buf, oi, flags)) < 0)
                        status = error(_("unable to parse %s header with --allow-unknown-type"),
-                                      sha1_to_hex(sha1));
-       } else if ((status = parse_sha1_header_extended(hdr, oi, flags)) < 0)
-               status = error(_("unable to parse %s header"), sha1_to_hex(sha1));
+                                      oid_to_hex(oid));
+       } else if ((status = parse_loose_header_extended(hdr, oi, flags)) < 0)
+               status = error(_("unable to parse %s header"), oid_to_hex(oid));
 
        if (status >= 0 && oi->contentp) {
-               *oi->contentp = unpack_sha1_rest(&stream, hdr,
-                                                *oi->sizep, sha1);
+               *oi->contentp = unpack_loose_rest(&stream, hdr,
+                                                 *oi->sizep, oid);
                if (!*oi->contentp) {
                        git_inflate_end(&stream);
                        status = -1;
@@ -1250,17 +1443,41 @@ static int sha1_loose_object_info(struct repository *r,
        return (status < 0) ? status : 0;
 }
 
+int obj_read_use_lock = 0;
+pthread_mutex_t obj_read_mutex;
+
+void enable_obj_read_lock(void)
+{
+       if (obj_read_use_lock)
+               return;
+
+       obj_read_use_lock = 1;
+       init_recursive_mutex(&obj_read_mutex);
+}
+
+void disable_obj_read_lock(void)
+{
+       if (!obj_read_use_lock)
+               return;
+
+       obj_read_use_lock = 0;
+       pthread_mutex_destroy(&obj_read_mutex);
+}
+
 int fetch_if_missing = 1;
 
-int oid_object_info_extended(struct repository *r, const struct object_id *oid,
-                            struct object_info *oi, unsigned flags)
+static int do_oid_object_info_extended(struct repository *r,
+                                      const struct object_id *oid,
+                                      struct object_info *oi, unsigned flags)
 {
        static struct object_info blank_oi = OBJECT_INFO_INIT;
+       struct cached_object *co;
        struct pack_entry e;
        int rtype;
        const struct object_id *real = oid;
        int already_retried = 0;
 
+
        if (flags & OBJECT_INFO_LOOKUP_REPLACE)
                real = lookup_replace_object(r, oid);
 
@@ -1270,24 +1487,22 @@ int oid_object_info_extended(struct repository *r, const struct object_id *oid,
        if (!oi)
                oi = &blank_oi;
 
-       if (!(flags & OBJECT_INFO_SKIP_CACHED)) {
-               struct cached_object *co = find_cached_object(real);
-               if (co) {
-                       if (oi->typep)
-                               *(oi->typep) = co->type;
-                       if (oi->sizep)
-                               *(oi->sizep) = co->size;
-                       if (oi->disk_sizep)
-                               *(oi->disk_sizep) = 0;
-                       if (oi->delta_base_sha1)
-                               hashclr(oi->delta_base_sha1);
-                       if (oi->type_name)
-                               strbuf_addstr(oi->type_name, type_name(co->type));
-                       if (oi->contentp)
-                               *oi->contentp = xmemdupz(co->buf, co->size);
-                       oi->whence = OI_CACHED;
-                       return 0;
-               }
+       co = find_cached_object(real);
+       if (co) {
+               if (oi->typep)
+                       *(oi->typep) = co->type;
+               if (oi->sizep)
+                       *(oi->sizep) = co->size;
+               if (oi->disk_sizep)
+                       *(oi->disk_sizep) = 0;
+               if (oi->delta_base_oid)
+                       oidclr(oi->delta_base_oid);
+               if (oi->type_name)
+                       strbuf_addstr(oi->type_name, type_name(co->type));
+               if (oi->contentp)
+                       *oi->contentp = xmemdupz(co->buf, co->size);
+               oi->whence = OI_CACHED;
+               return 0;
        }
 
        while (1) {
@@ -1298,7 +1513,7 @@ int oid_object_info_extended(struct repository *r, const struct object_id *oid,
                        return -1;
 
                /* Most likely it's a loose object. */
-               if (!sha1_loose_object_info(r, real->hash, oi, flags))
+               if (!loose_object_info(r, real, oi, flags))
                        return 0;
 
                /* Not a loose object; someone else may have just packed it. */
@@ -1309,15 +1524,17 @@ int oid_object_info_extended(struct repository *r, const struct object_id *oid,
                }
 
                /* Check if it is a missing object */
-               if (fetch_if_missing && repository_format_partial_clone &&
-                   !already_retried && r == the_repository) {
+               if (fetch_if_missing && has_promisor_remote() &&
+                   !already_retried && r == the_repository &&
+                   !(flags & OBJECT_INFO_SKIP_FETCH_OBJECT)) {
                        /*
-                        * TODO Investigate having fetch_object() return
-                        * TODO error/success and stopping the music here.
-                        * TODO Pass a repository struct through fetch_object,
-                        * such that arbitrary repositories work.
+                        * TODO Investigate checking promisor_remote_get_direct()
+                        * TODO return value and stopping on error here.
+                        * TODO Pass a repository struct through
+                        * promisor_remote_get_direct(), such that arbitrary
+                        * repositories work.
                         */
-                       fetch_object(repository_format_partial_clone, real->hash);
+                       promisor_remote_get_direct(r, real, 1);
                        already_retried = 1;
                        continue;
                }
@@ -1334,7 +1551,7 @@ int oid_object_info_extended(struct repository *r, const struct object_id *oid,
        rtype = packed_object_info(r, e.p, e.offset, oi);
        if (rtype < 0) {
                mark_bad_packed_object(e.p, real->hash);
-               return oid_object_info_extended(r, real, oi, 0);
+               return do_oid_object_info_extended(r, real, oi, 0);
        } else if (oi->whence == OI_PACKED) {
                oi->u.packed.offset = e.offset;
                oi->u.packed.pack = e.p;
@@ -1345,6 +1562,17 @@ int oid_object_info_extended(struct repository *r, const struct object_id *oid,
        return 0;
 }
 
+int oid_object_info_extended(struct repository *r, const struct object_id *oid,
+                            struct object_info *oi, unsigned flags)
+{
+       int ret;
+       obj_read_lock();
+       ret = do_oid_object_info_extended(r, oid, oi, flags);
+       obj_read_unlock();
+       return ret;
+}
+
+
 /* returns enum object_type or negative */
 int oid_object_info(struct repository *r,
                    const struct object_id *oid,
@@ -1361,19 +1589,17 @@ int oid_object_info(struct repository *r,
        return type;
 }
 
-static void *read_object(const unsigned char *sha1, enum object_type *type,
+static void *read_object(struct repository *r,
+                        const struct object_id *oid, enum object_type *type,
                         unsigned long *size)
 {
-       struct object_id oid;
        struct object_info oi = OBJECT_INFO_INIT;
        void *content;
        oi.typep = type;
        oi.sizep = size;
        oi.contentp = &content;
 
-       hashcpy(oid.hash, sha1);
-
-       if (oid_object_info_extended(the_repository, &oid, &oi, 0) < 0)
+       if (oid_object_info_extended(r, oid, &oi, 0) < 0)
                return NULL;
        return content;
 }
@@ -1383,8 +1609,9 @@ int pretend_object_file(void *buf, unsigned long len, enum object_type type,
 {
        struct cached_object *co;
 
-       hash_object_file(buf, len, type_name(type), oid);
-       if (has_sha1_file(oid->hash) || find_cached_object(oid))
+       hash_object_file(the_hash_algo, buf, len, type_name(type), oid);
+       if (has_object_file_with_flags(oid, OBJECT_INFO_QUICK | OBJECT_INFO_SKIP_FETCH_OBJECT) ||
+           find_cached_object(oid))
                return 0;
        ALLOC_GROW(cached_objects, cached_object_nr + 1, cached_object_alloc);
        co = &cached_objects[cached_object_nr++];
@@ -1401,7 +1628,8 @@ int pretend_object_file(void *buf, unsigned long len, enum object_type type,
  * deal with them should arrange to call read_object() and give error
  * messages themselves.
  */
-void *read_object_file_extended(const struct object_id *oid,
+void *read_object_file_extended(struct repository *r,
+                               const struct object_id *oid,
                                enum object_type *type,
                                unsigned long *size,
                                int lookup_replace)
@@ -1411,13 +1639,14 @@ void *read_object_file_extended(const struct object_id *oid,
        const char *path;
        struct stat st;
        const struct object_id *repl = lookup_replace ?
-               lookup_replace_object(the_repository, oid) : oid;
+               lookup_replace_object(r, oid) : oid;
 
        errno = 0;
-       data = read_object(repl->hash, type, size);
+       data = read_object(r, repl, type, size);
        if (data)
                return data;
 
+       obj_read_lock();
        if (errno && errno != ENOENT)
                die_errno(_("failed to read object %s"), oid_to_hex(oid));
 
@@ -1426,18 +1655,20 @@ void *read_object_file_extended(const struct object_id *oid,
                die(_("replacement %s not found for %s"),
                    oid_to_hex(repl), oid_to_hex(oid));
 
-       if (!stat_sha1_file(the_repository, repl->hash, &st, &path))
+       if (!stat_loose_object(r, repl, &st, &path))
                die(_("loose object %s (stored in %s) is corrupt"),
                    oid_to_hex(repl), path);
 
-       if ((p = has_packed_and_bad(repl->hash)) != NULL)
+       if ((p = has_packed_and_bad(r, repl->hash)) != NULL)
                die(_("packed object %s (stored in %s) is corrupt"),
                    oid_to_hex(repl), p->pack_name);
+       obj_read_unlock();
 
        return NULL;
 }
 
-void *read_object_with_reference(const struct object_id *oid,
+void *read_object_with_reference(struct repository *r,
+                                const struct object_id *oid,
                                 const char *required_type_name,
                                 unsigned long *size,
                                 struct object_id *actual_oid_return)
@@ -1453,7 +1684,7 @@ void *read_object_with_reference(const struct object_id *oid,
                int ref_length = -1;
                const char *ref_type = NULL;
 
-               buffer = read_object_file(&actual_oid, &type, &isize);
+               buffer = repo_read_object_file(r, &actual_oid, &type, &isize);
                if (!buffer)
                        return NULL;
                if (type == required_type) {
@@ -1485,20 +1716,21 @@ void *read_object_with_reference(const struct object_id *oid,
        }
 }
 
-static void write_object_file_prepare(const void *buf, unsigned long len,
+static void write_object_file_prepare(const struct git_hash_algo *algo,
+                                     const void *buf, unsigned long len,
                                      const char *type, struct object_id *oid,
                                      char *hdr, int *hdrlen)
 {
        git_hash_ctx c;
 
        /* Generate the header */
-       *hdrlen = xsnprintf(hdr, *hdrlen, "%s %lu", type, len)+1;
+       *hdrlen = xsnprintf(hdr, *hdrlen, "%s %"PRIuMAX , type, (uintmax_t)len)+1;
 
        /* Sha1.. */
-       the_hash_algo->init_fn(&c);
-       the_hash_algo->update_fn(&c, hdr, *hdrlen);
-       the_hash_algo->update_fn(&c, buf, len);
-       the_hash_algo->final_fn(oid->hash, &c);
+       algo->init_fn(&c);
+       algo->update_fn(&c, hdr, *hdrlen);
+       algo->update_fn(&c, buf, len);
+       algo->final_fn(oid->hash, &c);
 }
 
 /*
@@ -1533,7 +1765,7 @@ int finalize_object_file(const char *tmpfile, const char *filename)
        unlink_or_warn(tmpfile);
        if (ret) {
                if (ret != EEXIST) {
-                       return error_errno(_("unable to write sha1 filename %s"), filename);
+                       return error_errno(_("unable to write file %s"), filename);
                }
                /* FIXME!!! Collision check here ? */
        }
@@ -1551,22 +1783,23 @@ static int write_buffer(int fd, const void *buf, size_t len)
        return 0;
 }
 
-int hash_object_file(const void *buf, unsigned long len, const char *type,
+int hash_object_file(const struct git_hash_algo *algo, const void *buf,
+                    unsigned long len, const char *type,
                     struct object_id *oid)
 {
        char hdr[MAX_HEADER_LEN];
        int hdrlen = sizeof(hdr);
-       write_object_file_prepare(buf, len, type, oid, hdr, &hdrlen);
+       write_object_file_prepare(algo, buf, len, type, oid, hdr, &hdrlen);
        return 0;
 }
 
 /* Finalize a file on disk, and close it. */
-static void close_sha1_file(int fd)
+static void close_loose_object(int fd)
 {
        if (fsync_object_files)
-               fsync_or_die(fd, "sha1 file");
+               fsync_or_die(fd, "loose object file");
        if (close(fd) != 0)
-               die_errno(_("error when closing sha1 file"));
+               die_errno(_("error when closing loose object file"));
 }
 
 /* Size of directory component, including the ending '/' */
@@ -1626,8 +1859,7 @@ static int write_loose_object(const struct object_id *oid, char *hdr,
        static struct strbuf tmp_file = STRBUF_INIT;
        static struct strbuf filename = STRBUF_INIT;
 
-       strbuf_reset(&filename);
-       sha1_file_name(the_repository, &filename, oid->hash);
+       loose_object_path(the_repository, &filename, oid);
 
        fd = create_tmpfile(&tmp_file, filename.buf);
        if (fd < 0) {
@@ -1658,7 +1890,7 @@ static int write_loose_object(const struct object_id *oid, char *hdr,
                ret = git_deflate(&stream, Z_FINISH);
                the_hash_algo->update_fn(&c, in0, stream.next_in - in0);
                if (write_buffer(fd, compressed, stream.next_out - compressed) < 0)
-                       die(_("unable to write sha1 file"));
+                       die(_("unable to write loose object file"));
                stream.next_out = compressed;
                stream.avail_out = sizeof(compressed);
        } while (ret == Z_OK);
@@ -1671,11 +1903,11 @@ static int write_loose_object(const struct object_id *oid, char *hdr,
                die(_("deflateEnd on object %s failed (%d)"), oid_to_hex(oid),
                    ret);
        the_hash_algo->final_fn(parano_oid.hash, &c);
-       if (oidcmp(oid, &parano_oid) != 0)
+       if (!oideq(oid, &parano_oid))
                die(_("confused by unstable object source data for %s"),
                    oid_to_hex(oid));
 
-       close_sha1_file(fd);
+       close_loose_object(fd);
 
        if (mtime) {
                struct utimbuf utb;
@@ -1715,7 +1947,8 @@ int write_object_file(const void *buf, unsigned long len, const char *type,
        /* Normally if we have it in the pack then we do not bother writing
         * it out into .git/objects/??/?{38} file.
         */
-       write_object_file_prepare(buf, len, type, oid, hdr, &hdrlen);
+       write_object_file_prepare(the_hash_algo, buf, len, type, oid, hdr,
+                                 &hdrlen);
        if (freshen_packed_object(oid) || freshen_loose_object(oid))
                return 0;
        return write_loose_object(oid, hdr, hdrlen, buf, len, 0);
@@ -1731,7 +1964,8 @@ int hash_object_file_literally(const void *buf, unsigned long len,
        /* type string, SP, %lu of the length plus NUL must fit this */
        hdrlen = strlen(type) + MAX_HEADER_LEN;
        header = xmalloc(hdrlen);
-       write_object_file_prepare(buf, len, type, oid, header, &hdrlen);
+       write_object_file_prepare(the_hash_algo, buf, len, type, oid, header,
+                                 &hdrlen);
 
        if (!(flags & HASH_WRITE_OBJECT))
                goto cleanup;
@@ -1755,34 +1989,40 @@ int force_object_loose(const struct object_id *oid, time_t mtime)
 
        if (has_loose_object(oid))
                return 0;
-       buf = read_object(oid->hash, &type, &len);
+       buf = read_object(the_repository, oid, &type, &len);
        if (!buf)
-               return error(_("cannot read sha1_file for %s"), oid_to_hex(oid));
-       hdrlen = xsnprintf(hdr, sizeof(hdr), "%s %lu", type_name(type), len) + 1;
+               return error(_("cannot read object for %s"), oid_to_hex(oid));
+       hdrlen = xsnprintf(hdr, sizeof(hdr), "%s %"PRIuMAX , type_name(type), (uintmax_t)len) + 1;
        ret = write_loose_object(oid, hdr, hdrlen, buf, len, mtime);
        free(buf);
 
        return ret;
 }
 
-int has_sha1_file_with_flags(const unsigned char *sha1, int flags)
+int has_object(struct repository *r, const struct object_id *oid,
+              unsigned flags)
 {
-       struct object_id oid;
+       int quick = !(flags & HAS_OBJECT_RECHECK_PACKED);
+       unsigned object_info_flags = OBJECT_INFO_SKIP_FETCH_OBJECT |
+               (quick ? OBJECT_INFO_QUICK : 0);
+
        if (!startup_info->have_repository)
                return 0;
-       hashcpy(oid.hash, sha1);
-       return oid_object_info_extended(the_repository, &oid, NULL,
-                                       flags | OBJECT_INFO_SKIP_CACHED) >= 0;
+       return oid_object_info_extended(r, oid, NULL, object_info_flags) >= 0;
 }
 
-int has_object_file(const struct object_id *oid)
+int repo_has_object_file_with_flags(struct repository *r,
+                                   const struct object_id *oid, int flags)
 {
-       return has_sha1_file(oid->hash);
+       if (!startup_info->have_repository)
+               return 0;
+       return oid_object_info_extended(r, oid, NULL, flags) >= 0;
 }
 
-int has_object_file_with_flags(const struct object_id *oid, int flags)
+int repo_has_object_file(struct repository *r,
+                        const struct object_id *oid)
 {
-       return has_sha1_file_with_flags(oid->hash, flags);
+       return repo_has_object_file_with_flags(r, oid, 0);
 }
 
 static void check_tree(const void *buf, size_t size)
@@ -1813,7 +2053,8 @@ static void check_tag(const void *buf, size_t size)
                die(_("corrupt tag"));
 }
 
-static int index_mem(struct object_id *oid, void *buf, size_t size,
+static int index_mem(struct index_state *istate,
+                    struct object_id *oid, void *buf, size_t size,
                     enum object_type type,
                     const char *path, unsigned flags)
 {
@@ -1828,7 +2069,7 @@ static int index_mem(struct object_id *oid, void *buf, size_t size,
         */
        if ((type == OBJ_BLOB) && path) {
                struct strbuf nbuf = STRBUF_INIT;
-               if (convert_to_git(&the_index, path, buf, size, &nbuf,
+               if (convert_to_git(istate, path, buf, size, &nbuf,
                                   get_conv_flags(flags))) {
                        buf = strbuf_detach(&nbuf, &size);
                        re_allocated = 1;
@@ -1846,43 +2087,48 @@ static int index_mem(struct object_id *oid, void *buf, size_t size,
        if (write_object)
                ret = write_object_file(buf, size, type_name(type), oid);
        else
-               ret = hash_object_file(buf, size, type_name(type), oid);
+               ret = hash_object_file(the_hash_algo, buf, size,
+                                      type_name(type), oid);
        if (re_allocated)
                free(buf);
        return ret;
 }
 
-static int index_stream_convert_blob(struct object_id *oid, int fd,
-                                    const char *path, unsigned flags)
+static int index_stream_convert_blob(struct index_state *istate,
+                                    struct object_id *oid,
+                                    int fd,
+                                    const char *path,
+                                    unsigned flags)
 {
        int ret;
        const int write_object = flags & HASH_WRITE_OBJECT;
        struct strbuf sbuf = STRBUF_INIT;
 
        assert(path);
-       assert(would_convert_to_git_filter_fd(&the_index, path));
+       assert(would_convert_to_git_filter_fd(istate, path));
 
-       convert_to_git_filter_fd(&the_index, path, fd, &sbuf,
+       convert_to_git_filter_fd(istate, path, fd, &sbuf,
                                 get_conv_flags(flags));
 
        if (write_object)
                ret = write_object_file(sbuf.buf, sbuf.len, type_name(OBJ_BLOB),
                                        oid);
        else
-               ret = hash_object_file(sbuf.buf, sbuf.len, type_name(OBJ_BLOB),
-                                      oid);
+               ret = hash_object_file(the_hash_algo, sbuf.buf, sbuf.len,
+                                      type_name(OBJ_BLOB), oid);
        strbuf_release(&sbuf);
        return ret;
 }
 
-static int index_pipe(struct object_id *oid, int fd, enum object_type type,
+static int index_pipe(struct index_state *istate, struct object_id *oid,
+                     int fd, enum object_type type,
                      const char *path, unsigned flags)
 {
        struct strbuf sbuf = STRBUF_INIT;
        int ret;
 
        if (strbuf_read(&sbuf, fd, 4096) >= 0)
-               ret = index_mem(oid, sbuf.buf, sbuf.len, type, path, flags);
+               ret = index_mem(istate, oid, sbuf.buf, sbuf.len, type, path, flags);
        else
                ret = -1;
        strbuf_release(&sbuf);
@@ -1891,14 +2137,15 @@ static int index_pipe(struct object_id *oid, int fd, enum object_type type,
 
 #define SMALL_FILE_SIZE (32*1024)
 
-static int index_core(struct object_id *oid, int fd, size_t size,
+static int index_core(struct index_state *istate,
+                     struct object_id *oid, int fd, size_t size,
                      enum object_type type, const char *path,
                      unsigned flags)
 {
        int ret;
 
        if (!size) {
-               ret = index_mem(oid, "", size, type, path, flags);
+               ret = index_mem(istate, oid, "", size, type, path, flags);
        } else if (size <= SMALL_FILE_SIZE) {
                char *buf = xmalloc(size);
                ssize_t read_result = read_in_full(fd, buf, size);
@@ -1909,11 +2156,11 @@ static int index_core(struct object_id *oid, int fd, size_t size,
                        ret = error(_("short read while indexing %s"),
                                    path ? path : "<unknown>");
                else
-                       ret = index_mem(oid, buf, size, type, path, flags);
+                       ret = index_mem(istate, oid, buf, size, type, path, flags);
                free(buf);
        } else {
                void *buf = xmmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
-               ret = index_mem(oid, buf, size, type, path, flags);
+               ret = index_mem(istate, oid, buf, size, type, path, flags);
                munmap(buf, size);
        }
        return ret;
@@ -1941,7 +2188,8 @@ static int index_stream(struct object_id *oid, int fd, size_t size,
        return index_bulk_checkin(oid, fd, size, type, path, flags);
 }
 
-int index_fd(struct object_id *oid, int fd, struct stat *st,
+int index_fd(struct index_state *istate, struct object_id *oid,
+            int fd, struct stat *st,
             enum object_type type, const char *path, unsigned flags)
 {
        int ret;
@@ -1950,14 +2198,14 @@ int index_fd(struct object_id *oid, int fd, struct stat *st,
         * Call xsize_t() only when needed to avoid potentially unnecessary
         * die() for large files.
         */
-       if (type == OBJ_BLOB && path && would_convert_to_git_filter_fd(&the_index, path))
-               ret = index_stream_convert_blob(oid, fd, path, flags);
+       if (type == OBJ_BLOB && path && would_convert_to_git_filter_fd(istate, path))
+               ret = index_stream_convert_blob(istate, oid, fd, path, flags);
        else if (!S_ISREG(st->st_mode))
-               ret = index_pipe(oid, fd, type, path, flags);
+               ret = index_pipe(istate, oid, fd, type, path, flags);
        else if (st->st_size <= big_file_threshold || type != OBJ_BLOB ||
-                (path && would_convert_to_git(&the_index, path)))
-               ret = index_core(oid, fd, xsize_t(st->st_size), type, path,
-                                flags);
+                (path && would_convert_to_git(istate, path)))
+               ret = index_core(istate, oid, fd, xsize_t(st->st_size),
+                                type, path, flags);
        else
                ret = index_stream(oid, fd, xsize_t(st->st_size), type, path,
                                   flags);
@@ -1965,7 +2213,8 @@ int index_fd(struct object_id *oid, int fd, struct stat *st,
        return ret;
 }
 
-int index_path(struct object_id *oid, const char *path, struct stat *st, unsigned flags)
+int index_path(struct index_state *istate, struct object_id *oid,
+              const char *path, struct stat *st, unsigned flags)
 {
        int fd;
        struct strbuf sb = STRBUF_INIT;
@@ -1976,7 +2225,7 @@ int index_path(struct object_id *oid, const char *path, struct stat *st, unsigne
                fd = open(path, O_RDONLY);
                if (fd < 0)
                        return error_errno("open(\"%s\")", path);
-               if (index_fd(oid, fd, st, OBJ_BLOB, path, flags) < 0)
+               if (index_fd(istate, oid, fd, st, OBJ_BLOB, path, flags) < 0)
                        return error(_("%s: failed to insert into database"),
                                     path);
                break;
@@ -1984,7 +2233,8 @@ int index_path(struct object_id *oid, const char *path, struct stat *st, unsigne
                if (strbuf_readlink(&sb, path, st->st_size))
                        return error_errno("readlink(\"%s\")", path);
                if (!(flags & HASH_WRITE_OBJECT))
-                       hash_object_file(sb.buf, sb.len, blob_type, oid);
+                       hash_object_file(the_hash_algo, sb.buf, sb.len,
+                                        blob_type, oid);
                else if (write_object_file(sb.buf, sb.len, blob_type, oid))
                        rc = error(_("%s: failed to insert into database"), path);
                strbuf_release(&sb);
@@ -2126,53 +2376,73 @@ int for_each_loose_file_in_objdir(const char *path,
        return r;
 }
 
-struct loose_alt_odb_data {
-       each_loose_object_fn *cb;
-       void *data;
-};
+int for_each_loose_object(each_loose_object_fn cb, void *data,
+                         enum for_each_object_flags flags)
+{
+       struct object_directory *odb;
+
+       prepare_alt_odb(the_repository);
+       for (odb = the_repository->objects->odb; odb; odb = odb->next) {
+               int r = for_each_loose_file_in_objdir(odb->path, cb, NULL,
+                                                     NULL, data);
+               if (r)
+                       return r;
 
-static int loose_from_alt_odb(struct alternate_object_database *alt,
-                             void *vdata)
+               if (flags & FOR_EACH_OBJECT_LOCAL_ONLY)
+                       break;
+       }
+
+       return 0;
+}
+
+static int append_loose_object(const struct object_id *oid, const char *path,
+                              void *data)
 {
-       struct loose_alt_odb_data *data = vdata;
+       oid_array_append(data, oid);
+       return 0;
+}
+
+struct oid_array *odb_loose_cache(struct object_directory *odb,
+                                 const struct object_id *oid)
+{
+       int subdir_nr = oid->hash[0];
        struct strbuf buf = STRBUF_INIT;
-       int r;
 
-       strbuf_addstr(&buf, alt->path);
-       r = for_each_loose_file_in_objdir_buf(&buf,
-                                             data->cb, NULL, NULL,
-                                             data->data);
+       if (subdir_nr < 0 ||
+           subdir_nr >= ARRAY_SIZE(odb->loose_objects_subdir_seen))
+               BUG("subdir_nr out of range");
+
+       if (odb->loose_objects_subdir_seen[subdir_nr])
+               return &odb->loose_objects_cache[subdir_nr];
+
+       strbuf_addstr(&buf, odb->path);
+       for_each_file_in_obj_subdir(subdir_nr, &buf,
+                                   append_loose_object,
+                                   NULL, NULL,
+                                   &odb->loose_objects_cache[subdir_nr]);
+       odb->loose_objects_subdir_seen[subdir_nr] = 1;
        strbuf_release(&buf);
-       return r;
+       return &odb->loose_objects_cache[subdir_nr];
 }
 
-int for_each_loose_object(each_loose_object_fn cb, void *data,
-                         enum for_each_object_flags flags)
+void odb_clear_loose_cache(struct object_directory *odb)
 {
-       struct loose_alt_odb_data alt;
-       int r;
-
-       r = for_each_loose_file_in_objdir(get_object_directory(),
-                                         cb, NULL, NULL, data);
-       if (r)
-               return r;
-
-       if (flags & FOR_EACH_OBJECT_LOCAL_ONLY)
-               return 0;
+       int i;
 
-       alt.cb = cb;
-       alt.data = data;
-       return foreach_alt_odb(loose_from_alt_odb, &alt);
+       for (i = 0; i < ARRAY_SIZE(odb->loose_objects_cache); i++)
+               oid_array_clear(&odb->loose_objects_cache[i]);
+       memset(&odb->loose_objects_subdir_seen, 0,
+              sizeof(odb->loose_objects_subdir_seen));
 }
 
-static int check_stream_sha1(git_zstream *stream,
-                            const char *hdr,
-                            unsigned long size,
-                            const char *path,
-                            const unsigned char *expected_sha1)
+static int check_stream_oid(git_zstream *stream,
+                           const char *hdr,
+                           unsigned long size,
+                           const char *path,
+                           const struct object_id *expected_oid)
 {
        git_hash_ctx c;
-       unsigned char real_sha1[GIT_MAX_RAWSZ];
+       struct object_id real_oid;
        unsigned char buf[4096];
        unsigned long total_read;
        int status = Z_OK;
@@ -2188,10 +2458,11 @@ static int check_stream_sha1(git_zstream *stream,
 
        /*
         * This size comparison must be "<=" to read the final zlib packets;
-        * see the comment in unpack_sha1_rest for details.
+        * see the comment in unpack_loose_rest for details.
         */
        while (total_read <= size &&
-              (status == Z_OK || status == Z_BUF_ERROR)) {
+              (status == Z_OK ||
+               (status == Z_BUF_ERROR && !stream->avail_out))) {
                stream->next_out = buf;
                stream->avail_out = sizeof(buf);
                if (size - total_read < stream->avail_out)
@@ -2203,19 +2474,19 @@ static int check_stream_sha1(git_zstream *stream,
        git_inflate_end(stream);
 
        if (status != Z_STREAM_END) {
-               error(_("corrupt loose object '%s'"), sha1_to_hex(expected_sha1));
+               error(_("corrupt loose object '%s'"), oid_to_hex(expected_oid));
                return -1;
        }
        if (stream->avail_in) {
                error(_("garbage at end of loose object '%s'"),
-                     sha1_to_hex(expected_sha1));
+                     oid_to_hex(expected_oid));
                return -1;
        }
 
-       the_hash_algo->final_fn(real_sha1, &c);
-       if (hashcmp(expected_sha1, real_sha1)) {
-               error(_("sha1 mismatch for %s (expected %s)"), path,
-                     sha1_to_hex(expected_sha1));
+       the_hash_algo->final_fn(real_oid.hash, &c);
+       if (!oideq(expected_oid, &real_oid)) {
+               error(_("hash mismatch for %s (expected %s)"), path,
+                     oid_to_hex(expected_oid));
                return -1;
        }
 
@@ -2236,18 +2507,18 @@ int read_loose_object(const char *path,
 
        *contents = NULL;
 
-       map = map_sha1_file_1(the_repository, path, NULL, &mapsize);
+       map = map_loose_object_1(the_repository, path, NULL, &mapsize);
        if (!map) {
                error_errno(_("unable to mmap %s"), path);
                goto out;
        }
 
-       if (unpack_sha1_header(&stream, map, mapsize, hdr, sizeof(hdr)) < 0) {
+       if (unpack_loose_header(&stream, map, mapsize, hdr, sizeof(hdr)) < 0) {
                error(_("unable to unpack header of %s"), path);
                goto out;
        }
 
-       *type = parse_sha1_header(hdr, size);
+       *type = parse_loose_header(hdr, size);
        if (*type < 0) {
                error(_("unable to parse header of %s"), path);
                git_inflate_end(&stream);
@@ -2255,18 +2526,19 @@ int read_loose_object(const char *path,
        }
 
        if (*type == OBJ_BLOB && *size > big_file_threshold) {
-               if (check_stream_sha1(&stream, hdr, *size, path, expected_oid->hash) < 0)
+               if (check_stream_oid(&stream, hdr, *size, path, expected_oid) < 0)
                        goto out;
        } else {
-               *contents = unpack_sha1_rest(&stream, hdr, *size, expected_oid->hash);
+               *contents = unpack_loose_rest(&stream, hdr, *size, expected_oid);
                if (!*contents) {
                        error(_("unable to unpack contents of %s"), path);
                        git_inflate_end(&stream);
                        goto out;
                }
-               if (check_object_signature(expected_oid, *contents,
-                                        *size, type_name(*type))) {
-                       error(_("sha1 mismatch for %s (expected %s)"), path,
+               if (check_object_signature(the_repository, expected_oid,
+                                          *contents, *size,
+                                          type_name(*type))) {
+                       error(_("hash mismatch for %s (expected %s)"), path,
                              oid_to_hex(expected_oid));
                        free(*contents);
                        goto out;