Merge branch 'bc/hash-algo' into next
authorJunio C Hamano <gitster@pobox.com>
Thu, 8 Feb 2018 23:08:27 +0000 (15:08 -0800)
committerJunio C Hamano <gitster@pobox.com>
Thu, 8 Feb 2018 23:08:27 +0000 (15:08 -0800)
More abstraction of hash function from the codepath.

* bc/hash-algo:
bulk-checkin: abstract SHA-1 usage
csum-file: abstract uses of SHA-1
csum-file: rename sha1file to hashfile
read-cache: abstract away uses of SHA-1
pack-write: switch various SHA-1 values to abstract forms
pack-check: convert various uses of SHA-1 to abstract forms
fast-import: switch various uses of SHA-1 to the_hash_algo
sha1_file: switch uses of SHA-1 to the_hash_algo
builtin/unpack-objects: switch uses of SHA-1 to the_hash_algo
builtin/index-pack: improve hash function abstraction
hash: create union for hash context allocation
hash: move SHA-1 macros to hash.h

1  2 
builtin/index-pack.c
builtin/pack-objects.c
builtin/unpack-objects.c
cache.h
read-cache.c
sha1_file.c
diff --combined builtin/index-pack.c
index 16edfebf632a7938889d35d4d6332a0d7e814ae2,0bb520c731394e536ee107e0e212db54ddeea179..7e3e1a461c4469ea0272d9545d7173e984b1ebf4
@@@ -91,7 -91,7 +91,7 @@@ static unsigned int input_offset, input
  static off_t consumed_bytes;
  static off_t max_input_size;
  static unsigned deepest_delta;
- static git_SHA_CTX input_ctx;
+ static git_hash_ctx input_ctx;
  static uint32_t input_crc32;
  static int input_fd, output_fd;
  static const char *curr_pack;
@@@ -253,7 -253,7 +253,7 @@@ static void flush(void
        if (input_offset) {
                if (output_fd >= 0)
                        write_or_die(output_fd, input_buffer, input_offset);
-               git_SHA1_Update(&input_ctx, input_buffer, input_offset);
+               the_hash_algo->update_fn(&input_ctx, input_buffer, input_offset);
                memmove(input_buffer, input_buffer + input_offset, input_len);
                input_offset = 0;
        }
@@@ -326,7 -326,7 +326,7 @@@ static const char *open_pack_file(cons
                output_fd = -1;
                nothread_data.pack_fd = input_fd;
        }
-       git_SHA1_Init(&input_ctx);
+       the_hash_algo->init_fn(&input_ctx);
        return pack_name;
  }
  
@@@ -437,22 -437,22 +437,22 @@@ static int is_delta_type(enum object_ty
  }
  
  static void *unpack_entry_data(off_t offset, unsigned long size,
-                              enum object_type type, unsigned char *sha1)
+                              enum object_type type, struct object_id *oid)
  {
        static char fixed_buf[8192];
        int status;
        git_zstream stream;
        void *buf;
-       git_SHA_CTX c;
+       git_hash_ctx c;
        char hdr[32];
        int hdrlen;
  
        if (!is_delta_type(type)) {
                hdrlen = xsnprintf(hdr, sizeof(hdr), "%s %lu", typename(type), size) + 1;
-               git_SHA1_Init(&c);
-               git_SHA1_Update(&c, hdr, hdrlen);
+               the_hash_algo->init_fn(&c);
+               the_hash_algo->update_fn(&c, hdr, hdrlen);
        } else
-               sha1 = NULL;
+               oid = NULL;
        if (type == OBJ_BLOB && size > big_file_threshold)
                buf = fixed_buf;
        else
                stream.avail_in = input_len;
                status = git_inflate(&stream, 0);
                use(input_len - stream.avail_in);
-               if (sha1)
-                       git_SHA1_Update(&c, last_out, stream.next_out - last_out);
+               if (oid)
+                       the_hash_algo->update_fn(&c, last_out, stream.next_out - last_out);
                if (buf == fixed_buf) {
                        stream.next_out = buf;
                        stream.avail_out = sizeof(fixed_buf);
        if (stream.total_out != size || status != Z_STREAM_END)
                bad_object(offset, _("inflate returned %d"), status);
        git_inflate_end(&stream);
-       if (sha1)
-               git_SHA1_Final(sha1, &c);
+       if (oid)
+               the_hash_algo->final_fn(oid->hash, &c);
        return buf == fixed_buf ? NULL : buf;
  }
  
  static void *unpack_raw_entry(struct object_entry *obj,
                              off_t *ofs_offset,
-                             unsigned char *ref_sha1,
-                             unsigned char *sha1)
+                             struct object_id *ref_oid,
+                             struct object_id *oid)
  {
        unsigned char *p;
        unsigned long size, c;
  
        switch (obj->type) {
        case OBJ_REF_DELTA:
-               hashcpy(ref_sha1, fill(20));
-               use(20);
+               hashcpy(ref_oid->hash, fill(the_hash_algo->rawsz));
+               use(the_hash_algo->rawsz);
                break;
        case OBJ_OFS_DELTA:
                p = fill(1);
        }
        obj->hdr_size = consumed_bytes - obj->idx.offset;
  
-       data = unpack_entry_data(obj->idx.offset, obj->size, obj->type, sha1);
+       data = unpack_entry_data(obj->idx.offset, obj->size, obj->type, oid);
        obj->idx.crc32 = input_crc32;
        return data;
  }
@@@ -958,8 -958,9 +958,8 @@@ static void resolve_delta(struct object
        free(delta_data);
        if (!result->data)
                bad_object(delta_obj->idx.offset, _("failed to apply delta"));
 -      hash_sha1_file(result->data, result->size,
 -                     typename(delta_obj->real_type),
 -                     delta_obj->idx.oid.hash);
 +      hash_object_file(result->data, result->size,
 +                       typename(delta_obj->real_type), &delta_obj->idx.oid);
        sha1_object(result->data, NULL, result->size, delta_obj->real_type,
                    &delta_obj->idx.oid);
        counter_lock();
@@@ -1118,11 -1119,11 +1118,11 @@@ static void *threaded_second_pass(void 
   * - calculate SHA1 of all non-delta objects;
   * - remember base (SHA1 or offset) for all deltas.
   */
- static void parse_pack_objects(unsigned char *sha1)
+ static void parse_pack_objects(unsigned char *hash)
  {
        int i, nr_delays = 0;
        struct ofs_delta_entry *ofs_delta = ofs_deltas;
-       unsigned char ref_delta_sha1[20];
+       struct object_id ref_delta_oid;
        struct stat st;
  
        if (verbose)
        for (i = 0; i < nr_objects; i++) {
                struct object_entry *obj = &objects[i];
                void *data = unpack_raw_entry(obj, &ofs_delta->offset,
-                                             ref_delta_sha1,
-                                             obj->idx.oid.hash);
+                                             &ref_delta_oid,
+                                             &obj->idx.oid);
                obj->real_type = obj->type;
                if (obj->type == OBJ_OFS_DELTA) {
                        nr_ofs_deltas++;
                        ofs_delta++;
                } else if (obj->type == OBJ_REF_DELTA) {
                        ALLOC_GROW(ref_deltas, nr_ref_deltas + 1, ref_deltas_alloc);
-                       hashcpy(ref_deltas[nr_ref_deltas].sha1, ref_delta_sha1);
+                       hashcpy(ref_deltas[nr_ref_deltas].sha1, ref_delta_oid.hash);
                        ref_deltas[nr_ref_deltas].obj_no = i;
                        nr_ref_deltas++;
                } else if (!data) {
  
        /* Check pack integrity */
        flush();
-       git_SHA1_Final(sha1, &input_ctx);
-       if (hashcmp(fill(20), sha1))
+       the_hash_algo->final_fn(hash, &input_ctx);
+       if (hashcmp(fill(the_hash_algo->rawsz), hash))
                die(_("pack is corrupted (SHA1 mismatch)"));
-       use(20);
+       use(the_hash_algo->rawsz);
  
        /* If input_fd is a file, we should have reached its end now. */
        if (fstat(input_fd, &st))
@@@ -1238,21 -1239,21 +1238,21 @@@ static void resolve_deltas(void
  /*
   * Third pass:
   * - append objects to convert thin pack to full pack if required
-  * - write the final 20-byte SHA-1
+  * - write the final pack hash
   */
- static void fix_unresolved_deltas(struct sha1file *f);
- static void conclude_pack(int fix_thin_pack, const char *curr_pack, unsigned char *pack_sha1)
+ static void fix_unresolved_deltas(struct hashfile *f);
+ static void conclude_pack(int fix_thin_pack, const char *curr_pack, unsigned char *pack_hash)
  {
        if (nr_ref_deltas + nr_ofs_deltas == nr_resolved_deltas) {
                stop_progress(&progress);
-               /* Flush remaining pack final 20-byte SHA1. */
+               /* Flush remaining pack final hash. */
                flush();
                return;
        }
  
        if (fix_thin_pack) {
-               struct sha1file *f;
-               unsigned char read_sha1[20], tail_sha1[20];
+               struct hashfile *f;
+               unsigned char read_hash[GIT_MAX_RAWSZ], tail_hash[GIT_MAX_RAWSZ];
                struct strbuf msg = STRBUF_INIT;
                int nr_unresolved = nr_ofs_deltas + nr_ref_deltas - nr_resolved_deltas;
                int nr_objects_initial = nr_objects;
                REALLOC_ARRAY(objects, nr_objects + nr_unresolved + 1);
                memset(objects + nr_objects + 1, 0,
                       nr_unresolved * sizeof(*objects));
-               f = sha1fd(output_fd, curr_pack);
+               f = hashfd(output_fd, curr_pack);
                fix_unresolved_deltas(f);
                strbuf_addf(&msg, Q_("completed with %d local object",
                                     "completed with %d local objects",
                            nr_objects - nr_objects_initial);
                stop_progress_msg(&progress, msg.buf);
                strbuf_release(&msg);
-               sha1close(f, tail_sha1, 0);
-               hashcpy(read_sha1, pack_sha1);
-               fixup_pack_header_footer(output_fd, pack_sha1,
+               hashclose(f, tail_hash, 0);
+               hashcpy(read_hash, pack_hash);
+               fixup_pack_header_footer(output_fd, pack_hash,
                                         curr_pack, nr_objects,
-                                        read_sha1, consumed_bytes-20);
-               if (hashcmp(read_sha1, tail_sha1) != 0)
+                                        read_hash, consumed_bytes-the_hash_algo->rawsz);
+               if (hashcmp(read_hash, tail_hash) != 0)
                        die(_("Unexpected tail checksum for %s "
                              "(disk corruption?)"), curr_pack);
        }
                    nr_ofs_deltas + nr_ref_deltas - nr_resolved_deltas);
  }
  
- static int write_compressed(struct sha1file *f, void *in, unsigned int size)
+ static int write_compressed(struct hashfile *f, void *in, unsigned int size)
  {
        git_zstream stream;
        int status;
                stream.next_out = outbuf;
                stream.avail_out = sizeof(outbuf);
                status = git_deflate(&stream, Z_FINISH);
-               sha1write(f, outbuf, sizeof(outbuf) - stream.avail_out);
+               hashwrite(f, outbuf, sizeof(outbuf) - stream.avail_out);
        } while (status == Z_OK);
  
        if (status != Z_STREAM_END)
        return size;
  }
  
- static struct object_entry *append_obj_to_pack(struct sha1file *f,
+ static struct object_entry *append_obj_to_pack(struct hashfile *f,
                               const unsigned char *sha1, void *buf,
                               unsigned long size, enum object_type type)
  {
        }
        header[n++] = c;
        crc32_begin(f);
-       sha1write(f, header, n);
+       hashwrite(f, header, n);
        obj[0].size = size;
        obj[0].hdr_size = n;
        obj[0].type = type;
        obj[1].idx.offset = obj[0].idx.offset + n;
        obj[1].idx.offset += write_compressed(f, buf, size);
        obj[0].idx.crc32 = crc32_end(f);
-       sha1flush(f);
+       hashflush(f);
        hashcpy(obj->idx.oid.hash, sha1);
        return obj;
  }
@@@ -1346,7 -1347,7 +1346,7 @@@ static int delta_pos_compare(const voi
        return a->obj_no - b->obj_no;
  }
  
- static void fix_unresolved_deltas(struct sha1file *f)
+ static void fix_unresolved_deltas(struct hashfile *f)
  {
        struct ref_delta_entry **sorted_by_pos;
        int i;
        free(sorted_by_pos);
  }
  
-                              const char *pack_name, const unsigned char *sha1,
 +static const char *derive_filename(const char *pack_name, const char *suffix,
 +                                 struct strbuf *buf)
 +{
 +      size_t len;
 +      if (!strip_suffix(pack_name, ".pack", &len))
 +              die(_("packfile name '%s' does not end with '.pack'"),
 +                  pack_name);
 +      strbuf_add(buf, pack_name, len);
 +      strbuf_addch(buf, '.');
 +      strbuf_addstr(buf, suffix);
 +      return buf->buf;
 +}
 +
 +static void write_special_file(const char *suffix, const char *msg,
-               filename = odb_pack_name(&name_buf, sha1, suffix);
++                             const char *pack_name, const unsigned char *hash,
 +                             const char **report)
 +{
 +      struct strbuf name_buf = STRBUF_INIT;
 +      const char *filename;
 +      int fd;
 +      int msg_len = strlen(msg);
 +
 +      if (pack_name)
 +              filename = derive_filename(pack_name, suffix, &name_buf);
 +      else
++              filename = odb_pack_name(&name_buf, hash, suffix);
 +
 +      fd = odb_pack_keep(filename);
 +      if (fd < 0) {
 +              if (errno != EEXIST)
 +                      die_errno(_("cannot write %s file '%s'"),
 +                                suffix, filename);
 +      } else {
 +              if (msg_len > 0) {
 +                      write_or_die(fd, msg, msg_len);
 +                      write_or_die(fd, "\n", 1);
 +              }
 +              if (close(fd) != 0)
 +                      die_errno(_("cannot close written %s file '%s'"),
 +                                suffix, filename);
 +              if (report)
 +                      *report = suffix;
 +      }
 +      strbuf_release(&name_buf);
 +}
 +
  static void final(const char *final_pack_name, const char *curr_pack_name,
                  const char *final_index_name, const char *curr_index_name,
 -                const char *keep_name, const char *keep_msg,
 +                const char *keep_msg, const char *promisor_msg,
-                 unsigned char *sha1)
+                 unsigned char *hash)
  {
        const char *report = "pack";
        struct strbuf pack_name = STRBUF_INIT;
        struct strbuf index_name = STRBUF_INIT;
 -      struct strbuf keep_name_buf = STRBUF_INIT;
        int err;
  
        if (!from_stdin) {
                        die_errno(_("error while closing pack file"));
        }
  
 -      if (keep_msg) {
 -              int keep_fd, keep_msg_len = strlen(keep_msg);
 -
 -              if (!keep_name)
 -                      keep_name = odb_pack_name(&keep_name_buf, hash, "keep");
 -
 -              keep_fd = odb_pack_keep(keep_name);
 -              if (keep_fd < 0) {
 -                      if (errno != EEXIST)
 -                              die_errno(_("cannot write keep file '%s'"),
 -                                        keep_name);
 -              } else {
 -                      if (keep_msg_len > 0) {
 -                              write_or_die(keep_fd, keep_msg, keep_msg_len);
 -                              write_or_die(keep_fd, "\n", 1);
 -                      }
 -                      if (close(keep_fd) != 0)
 -                              die_errno(_("cannot close written keep file '%s'"),
 -                                        keep_name);
 -                      report = "keep";
 -              }
 -      }
 +      if (keep_msg)
-               write_special_file("keep", keep_msg, final_pack_name, sha1,
++              write_special_file("keep", keep_msg, final_pack_name, hash,
 +                                 &report);
 +      if (promisor_msg)
 +              write_special_file("promisor", promisor_msg, final_pack_name,
-                                  sha1, NULL);
++                                 hash, NULL);
  
        if (final_pack_name != curr_pack_name) {
                if (!final_pack_name)
-                       final_pack_name = odb_pack_name(&pack_name, sha1, "pack");
+                       final_pack_name = odb_pack_name(&pack_name, hash, "pack");
                if (finalize_object_file(curr_pack_name, final_pack_name))
                        die(_("cannot store pack file"));
        } else if (from_stdin)
  
        if (final_index_name != curr_index_name) {
                if (!final_index_name)
-                       final_index_name = odb_pack_name(&index_name, sha1, "idx");
+                       final_index_name = odb_pack_name(&index_name, hash, "idx");
                if (finalize_object_file(curr_index_name, final_index_name))
                        die(_("cannot store index file"));
        } else
                chmod(final_index_name, 0444);
  
        if (!from_stdin) {
-               printf("%s\n", sha1_to_hex(sha1));
+               printf("%s\n", sha1_to_hex(hash));
        } else {
                struct strbuf buf = STRBUF_INIT;
  
-               strbuf_addf(&buf, "%s\t%s\n", report, sha1_to_hex(sha1));
+               strbuf_addf(&buf, "%s\t%s\n", report, sha1_to_hex(hash));
                write_or_die(1, buf.buf, buf.len);
                strbuf_release(&buf);
  
  
        strbuf_release(&index_name);
        strbuf_release(&pack_name);
 -      strbuf_release(&keep_name_buf);
  }
  
  static int git_index_pack_config(const char *k, const char *v, void *cb)
@@@ -1642,26 -1615,32 +1642,26 @@@ static void show_pack_info(int stat_onl
        }
  }
  
 -static const char *derive_filename(const char *pack_name, const char *suffix,
 -                                 struct strbuf *buf)
 -{
 -      size_t len;
 -      if (!strip_suffix(pack_name, ".pack", &len))
 -              die(_("packfile name '%s' does not end with '.pack'"),
 -                  pack_name);
 -      strbuf_add(buf, pack_name, len);
 -      strbuf_addstr(buf, suffix);
 -      return buf->buf;
 -}
 -
  int cmd_index_pack(int argc, const char **argv, const char *prefix)
  {
        int i, fix_thin_pack = 0, verify = 0, stat_only = 0;
        const char *curr_index;
        const char *index_name = NULL, *pack_name = NULL;
 -      const char *keep_name = NULL, *keep_msg = NULL;
 -      struct strbuf index_name_buf = STRBUF_INIT,
 -                    keep_name_buf = STRBUF_INIT;
 +      const char *keep_msg = NULL;
 +      const char *promisor_msg = NULL;
 +      struct strbuf index_name_buf = STRBUF_INIT;
        struct pack_idx_entry **idx_objects;
        struct pack_idx_option opts;
-       unsigned char pack_sha1[20];
+       unsigned char pack_hash[GIT_MAX_RAWSZ];
        unsigned foreign_nr = 1;        /* zero is a "good" value, assume bad */
        int report_end_of_input = 0;
  
 +      /*
 +       * index-pack never needs to fetch missing objects, since it only
 +       * accesses the repo to do hash collision checks
 +       */
 +      fetch_if_missing = 0;
 +
        if (argc == 2 && !strcmp(argv[1], "-h"))
                usage(index_pack_usage);
  
                                stat_only = 1;
                        } else if (skip_to_optional_arg(arg, "--keep", &keep_msg)) {
                                ; /* nothing to do */
 +                      } else if (skip_to_optional_arg(arg, "--promisor", &promisor_msg)) {
 +                              ; /* already parsed */
                        } else if (starts_with(arg, "--threads=")) {
                                char *end;
                                nr_threads = strtoul(arg+10, &end, 0);
        if (from_stdin && !startup_info->have_repository)
                die(_("--stdin requires a git repository"));
        if (!index_name && pack_name)
 -              index_name = derive_filename(pack_name, ".idx", &index_name_buf);
 -      if (keep_msg && !keep_name && pack_name)
 -              keep_name = derive_filename(pack_name, ".keep", &keep_name_buf);
 +              index_name = derive_filename(pack_name, "idx", &index_name_buf);
  
        if (verify) {
                if (!index_name)
        if (show_stat)
                obj_stat = xcalloc(st_add(nr_objects, 1), sizeof(struct object_stat));
        ofs_deltas = xcalloc(nr_objects, sizeof(struct ofs_delta_entry));
-       parse_pack_objects(pack_sha1);
+       parse_pack_objects(pack_hash);
        if (report_end_of_input)
                write_in_full(2, "\0", 1);
        resolve_deltas();
-       conclude_pack(fix_thin_pack, curr_pack, pack_sha1);
+       conclude_pack(fix_thin_pack, curr_pack, pack_hash);
        free(ofs_deltas);
        free(ref_deltas);
        if (strict)
        ALLOC_ARRAY(idx_objects, nr_objects);
        for (i = 0; i < nr_objects; i++)
                idx_objects[i] = &objects[i].idx;
-       curr_index = write_idx_file(index_name, idx_objects, nr_objects, &opts, pack_sha1);
+       curr_index = write_idx_file(index_name, idx_objects, nr_objects, &opts, pack_hash);
        free(idx_objects);
  
        if (!verify)
                final(pack_name, curr_pack,
                      index_name, curr_index,
 -                    keep_name, keep_msg,
 +                    keep_msg, promisor_msg,
-                     pack_sha1);
+                     pack_hash);
        else
                close(input_fd);
        free(objects);
        strbuf_release(&index_name_buf);
 -      strbuf_release(&keep_name_buf);
        if (pack_name == NULL)
                free((void *) curr_pack);
        if (index_name == NULL)
diff --combined builtin/pack-objects.c
index 81ad914cfc20e30ce7480b76d6143b0f6f0b6230,d91cbd460ed9716354aecfe5d8289adacd77c6cf..5c674b2843ccadec710596f7b8c293bbbc6130ea
@@@ -26,7 -26,7 +26,7 @@@
  #include "reachable.h"
  #include "sha1-array.h"
  #include "argv-array.h"
 -#include "mru.h"
 +#include "list.h"
  #include "packfile.h"
  
  static const char *pack_usage[] = {
@@@ -75,8 -75,6 +75,8 @@@ static int use_bitmap_index = -1
  static int write_bitmap_index;
  static uint16_t write_bitmap_options;
  
 +static int exclude_promisor_objects;
 +
  static unsigned long delta_cache_size = 0;
  static unsigned long max_delta_cache_size = 256 * 1024 * 1024;
  static unsigned long cache_max_small_delta_size = 1000;
@@@ -86,9 -84,8 +86,9 @@@ static unsigned long window_memory_limi
  static struct list_objects_filter_options filter_options;
  
  enum missing_action {
 -      MA_ERROR = 0,    /* fail if any missing objects are encountered */
 -      MA_ALLOW_ANY,    /* silently allow ALL missing objects */
 +      MA_ERROR = 0,      /* fail if any missing objects are encountered */
 +      MA_ALLOW_ANY,      /* silently allow ALL missing objects */
 +      MA_ALLOW_PROMISOR, /* silently allow all missing PROMISOR objects */
  };
  static enum missing_action arg_missing_action;
  static show_object_fn fn_show_object;
@@@ -164,7 -161,7 +164,7 @@@ static unsigned long do_compress(void *
        return stream.total_out;
  }
  
- static unsigned long write_large_blob_data(struct git_istream *st, struct sha1file *f,
+ static unsigned long write_large_blob_data(struct git_istream *st, struct hashfile *f,
                                           const struct object_id *oid)
  {
        git_zstream stream;
                        stream.next_out = obuf;
                        stream.avail_out = sizeof(obuf);
                        zret = git_deflate(&stream, readlen ? 0 : Z_FINISH);
-                       sha1write(f, obuf, stream.next_out - obuf);
+                       hashwrite(f, obuf, stream.next_out - obuf);
                        olen += stream.next_out - obuf;
                }
                if (stream.avail_in)
@@@ -233,7 -230,7 +233,7 @@@ static int check_pack_inflate(struct pa
                stream.total_in == len) ? 0 : -1;
  }
  
- static void copy_pack_data(struct sha1file *f,
+ static void copy_pack_data(struct hashfile *f,
                struct packed_git *p,
                struct pack_window **w_curs,
                off_t offset,
                in = use_pack(p, w_curs, offset, &avail);
                if (avail > len)
                        avail = (unsigned long)len;
-               sha1write(f, in, avail);
+               hashwrite(f, in, avail);
                offset += avail;
                len -= avail;
        }
  }
  
  /* Return 0 if we will bust the pack-size limit */
- static unsigned long write_no_reuse_object(struct sha1file *f, struct object_entry *entry,
+ static unsigned long write_no_reuse_object(struct hashfile *f, struct object_entry *entry,
                                           unsigned long limit, int usable_delta)
  {
        unsigned long size, datalen;
                        free(buf);
                        return 0;
                }
-               sha1write(f, header, hdrlen);
-               sha1write(f, dheader + pos, sizeof(dheader) - pos);
+               hashwrite(f, header, hdrlen);
+               hashwrite(f, dheader + pos, sizeof(dheader) - pos);
                hdrlen += sizeof(dheader) - pos;
        } else if (type == OBJ_REF_DELTA) {
                /*
                        free(buf);
                        return 0;
                }
-               sha1write(f, header, hdrlen);
-               sha1write(f, entry->delta->idx.oid.hash, 20);
+               hashwrite(f, header, hdrlen);
+               hashwrite(f, entry->delta->idx.oid.hash, 20);
                hdrlen += 20;
        } else {
                if (limit && hdrlen + datalen + 20 >= limit) {
                        free(buf);
                        return 0;
                }
-               sha1write(f, header, hdrlen);
+               hashwrite(f, header, hdrlen);
        }
        if (st) {
                datalen = write_large_blob_data(st, f, &entry->idx.oid);
                close_istream(st);
        } else {
-               sha1write(f, buf, datalen);
+               hashwrite(f, buf, datalen);
                free(buf);
        }
  
  }
  
  /* Return 0 if we will bust the pack-size limit */
- static off_t write_reuse_object(struct sha1file *f, struct object_entry *entry,
+ static off_t write_reuse_object(struct hashfile *f, struct object_entry *entry,
                                unsigned long limit, int usable_delta)
  {
        struct packed_git *p = entry->in_pack;
                        unuse_pack(&w_curs);
                        return 0;
                }
-               sha1write(f, header, hdrlen);
-               sha1write(f, dheader + pos, sizeof(dheader) - pos);
+               hashwrite(f, header, hdrlen);
+               hashwrite(f, dheader + pos, sizeof(dheader) - pos);
                hdrlen += sizeof(dheader) - pos;
                reused_delta++;
        } else if (type == OBJ_REF_DELTA) {
                        unuse_pack(&w_curs);
                        return 0;
                }
-               sha1write(f, header, hdrlen);
-               sha1write(f, entry->delta->idx.oid.hash, 20);
+               hashwrite(f, header, hdrlen);
+               hashwrite(f, entry->delta->idx.oid.hash, 20);
                hdrlen += 20;
                reused_delta++;
        } else {
                        unuse_pack(&w_curs);
                        return 0;
                }
-               sha1write(f, header, hdrlen);
+               hashwrite(f, header, hdrlen);
        }
        copy_pack_data(f, p, &w_curs, offset, datalen);
        unuse_pack(&w_curs);
  }
  
  /* Return 0 if we will bust the pack-size limit */
- static off_t write_object(struct sha1file *f,
+ static off_t write_object(struct hashfile *f,
                          struct object_entry *entry,
                          off_t write_offset)
  {
@@@ -515,7 -512,7 +515,7 @@@ enum write_one_status 
        WRITE_ONE_RECURSIVE = 2 /* already scheduled to be written */
  };
  
- static enum write_one_status write_one(struct sha1file *f,
+ static enum write_one_status write_one(struct hashfile *f,
                                       struct object_entry *e,
                                       off_t *offset)
  {
@@@ -734,7 -731,7 +734,7 @@@ static struct object_entry **compute_wr
        return wo;
  }
  
- static off_t write_reused_pack(struct sha1file *f)
+ static off_t write_reused_pack(struct hashfile *f)
  {
        unsigned char buffer[8192];
        off_t to_write, total;
                if (read_pack > to_write)
                        read_pack = to_write;
  
-               sha1write(f, buffer, read_pack);
+               hashwrite(f, buffer, read_pack);
                to_write -= read_pack;
  
                /*
@@@ -794,7 -791,7 +794,7 @@@ static const char no_split_warning[] = 
  static void write_pack_file(void)
  {
        uint32_t i = 0, j;
-       struct sha1file *f;
+       struct hashfile *f;
        off_t offset;
        uint32_t nr_remaining = nr_result;
        time_t last_mtime = 0;
                char *pack_tmp_name = NULL;
  
                if (pack_to_stdout)
-                       f = sha1fd_throughput(1, "<stdout>", progress_state);
+                       f = hashfd_throughput(1, "<stdout>", progress_state);
                else
                        f = create_tmp_packfile(&pack_tmp_name);
  
                 * If so, rewrite it like in fast-import
                 */
                if (pack_to_stdout) {
-                       sha1close(f, oid.hash, CSUM_CLOSE);
+                       hashclose(f, oid.hash, CSUM_CLOSE);
                } else if (nr_written == nr_remaining) {
-                       sha1close(f, oid.hash, CSUM_FSYNC);
+                       hashclose(f, oid.hash, CSUM_FSYNC);
                } else {
-                       int fd = sha1close(f, oid.hash, 0);
+                       int fd = hashclose(f, oid.hash, 0);
                        fixup_pack_header_footer(fd, oid.hash, pack_tmp_name,
                                                 nr_written, oid.hash, offset);
                        close(fd);
@@@ -1009,8 -1006,8 +1009,8 @@@ static int want_object_in_pack(const st
                               struct packed_git **found_pack,
                               off_t *found_offset)
  {
 -      struct mru_entry *entry;
        int want;
 +      struct list_head *pos;
  
        if (!exclude && local && has_loose_object_nonlocal(oid->hash))
                return 0;
                        return want;
        }
  
 -      for (entry = packed_git_mru.head; entry; entry = entry->next) {
 -              struct packed_git *p = entry->item;
 +      list_for_each(pos, &packed_git_mru) {
 +              struct packed_git *p = list_entry(pos, struct packed_git, mru);
                off_t offset;
  
                if (p == *found_pack)
                        }
                        want = want_found_object(exclude, p);
                        if (!exclude && want > 0)
 -                              mru_mark(&packed_git_mru, entry);
 +                              list_move(&p->mru, &packed_git_mru);
                        if (want != -1)
                                return want;
                }
@@@ -2581,20 -2578,6 +2581,20 @@@ static void show_object__ma_allow_any(s
        show_object(obj, name, data);
  }
  
 +static void show_object__ma_allow_promisor(struct object *obj, const char *name, void *data)
 +{
 +      assert(arg_missing_action == MA_ALLOW_PROMISOR);
 +
 +      /*
 +       * Quietly ignore EXPECTED missing objects.  This avoids problems with
 +       * staging them now and getting an odd error later.
 +       */
 +      if (!has_object_file(&obj->oid) && is_promisor_object(&obj->oid))
 +              return;
 +
 +      show_object(obj, name, data);
 +}
 +
  static int option_parse_missing_action(const struct option *opt,
                                       const char *arg, int unset)
  {
  
        if (!strcmp(arg, "allow-any")) {
                arg_missing_action = MA_ALLOW_ANY;
 +              fetch_if_missing = 0;
                fn_show_object = show_object__ma_allow_any;
                return 0;
        }
  
 +      if (!strcmp(arg, "allow-promisor")) {
 +              arg_missing_action = MA_ALLOW_PROMISOR;
 +              fetch_if_missing = 0;
 +              fn_show_object = show_object__ma_allow_promisor;
 +              return 0;
 +      }
 +
        die(_("invalid value for --missing"));
        return 0;
  }
@@@ -2793,7 -2768,7 +2793,7 @@@ static void loosen_unused_packed_object
                        if (!packlist_find(&to_pack, oid.hash, NULL) &&
                            !has_sha1_pack_kept_or_nonlocal(&oid) &&
                            !loosened_object_can_be_discarded(&oid, p->mtime))
 -                              if (force_object_loose(oid.hash, p->mtime))
 +                              if (force_object_loose(&oid, p->mtime))
                                        die("unable to force loose object");
                }
        }
@@@ -3034,8 -3009,6 +3034,8 @@@ int cmd_pack_objects(int argc, const ch
                { OPTION_CALLBACK, 0, "missing", NULL, N_("action"),
                  N_("handling for missing objects"), PARSE_OPT_NONEG,
                  option_parse_missing_action },
 +              OPT_BOOL(0, "exclude-promisor-objects", &exclude_promisor_objects,
 +                       N_("do not pack objects in promisor packfiles")),
                OPT_END(),
        };
  
                argv_array_push(&rp, "--unpacked");
        }
  
 +      if (exclude_promisor_objects) {
 +              use_internal_rev_list = 1;
 +              fetch_if_missing = 0;
 +              argv_array_push(&rp, "--exclude-promisor-objects");
 +      }
 +
        if (!reuse_object)
                reuse_delta = 0;
        if (pack_compression_level == -1)
diff --combined builtin/unpack-objects.c
index 397371eb3dc4949e9c072616ee0e8cd36108a6e2,813ca319790665c0344a86e7ebd8cfe609ce307e..7235d2ffbff78400384f92ea53233ec4dfbf0687
@@@ -21,7 -21,7 +21,7 @@@ static unsigned char buffer[4096]
  static unsigned int offset, len;
  static off_t consumed_bytes;
  static off_t max_input_size;
- static git_SHA_CTX ctx;
+ static git_hash_ctx ctx;
  static struct fsck_options fsck_options = FSCK_OPTIONS_STRICT;
  
  /*
@@@ -62,7 -62,7 +62,7 @@@ static void *fill(int min
        if (min > sizeof(buffer))
                die("cannot fill %d bytes", min);
        if (offset) {
-               git_SHA1_Update(&ctx, buffer, offset);
+               the_hash_algo->update_fn(&ctx, buffer, offset);
                memmove(buffer, buffer + offset, len);
                offset = 0;
        }
@@@ -172,8 -172,7 +172,8 @@@ static void write_cached_object(struct 
  {
        struct object_id oid;
  
 -      if (write_sha1_file(obj_buf->buffer, obj_buf->size, typename(obj->type), oid.hash) < 0)
 +      if (write_object_file(obj_buf->buffer, obj_buf->size,
 +                            typename(obj->type), &oid) < 0)
                die("failed to write object %s", oid_to_hex(&obj->oid));
        obj->flags |= FLAG_WRITTEN;
  }
@@@ -238,16 -237,14 +238,16 @@@ static void write_object(unsigned nr, e
                         void *buf, unsigned long size)
  {
        if (!strict) {
 -              if (write_sha1_file(buf, size, typename(type), obj_list[nr].oid.hash) < 0)
 +              if (write_object_file(buf, size, typename(type),
 +                                    &obj_list[nr].oid) < 0)
                        die("failed to write object");
                added_object(nr, type, buf, size);
                free(buf);
                obj_list[nr].obj = NULL;
        } else if (type == OBJ_BLOB) {
                struct blob *blob;
 -              if (write_sha1_file(buf, size, typename(type), obj_list[nr].oid.hash) < 0)
 +              if (write_object_file(buf, size, typename(type),
 +                                    &obj_list[nr].oid) < 0)
                        die("failed to write object");
                added_object(nr, type, buf, size);
                free(buf);
        } else {
                struct object *obj;
                int eaten;
 -              hash_sha1_file(buf, size, typename(type), obj_list[nr].oid.hash);
 +              hash_object_file(buf, size, typename(type), &obj_list[nr].oid);
                added_object(nr, type, buf, size);
                obj = parse_object_buffer(&obj_list[nr].oid, type, size, buf,
                                          &eaten);
@@@ -348,8 -345,8 +348,8 @@@ static void unpack_delta_entry(enum obj
        struct object_id base_oid;
  
        if (type == OBJ_REF_DELTA) {
-               hashcpy(base_oid.hash, fill(GIT_SHA1_RAWSZ));
-               use(GIT_SHA1_RAWSZ);
+               hashcpy(base_oid.hash, fill(the_hash_algo->rawsz));
+               use(the_hash_algo->rawsz);
                delta_data = get_data(delta_size);
                if (dry_run || !delta_data) {
                        free(delta_data);
@@@ -567,15 -564,15 +567,15 @@@ int cmd_unpack_objects(int argc, const 
                /* We don't take any non-flag arguments now.. Maybe some day */
                usage(unpack_usage);
        }
-       git_SHA1_Init(&ctx);
+       the_hash_algo->init_fn(&ctx);
        unpack_all();
-       git_SHA1_Update(&ctx, buffer, offset);
-       git_SHA1_Final(oid.hash, &ctx);
+       the_hash_algo->update_fn(&ctx, buffer, offset);
+       the_hash_algo->final_fn(oid.hash, &ctx);
        if (strict)
                write_rest();
-       if (hashcmp(fill(GIT_SHA1_RAWSZ), oid.hash))
+       if (hashcmp(fill(the_hash_algo->rawsz), oid.hash))
                die("final sha1 did not match");
-       use(GIT_SHA1_RAWSZ);
+       use(the_hash_algo->rawsz);
  
        /* Write the last part of the buffer to stdout */
        while (len) {
diff --combined cache.h
index c2d14a2c3761f855352ba5c825fe78fa07ec6a78,bfde6f757a6ac966b0fbfc3f68f6b7d09e3c9574..21fbcc2414953d00929185aeb97f3a6ae9a3f73a
+++ b/cache.h
@@@ -4,7 -4,7 +4,7 @@@
  #include "git-compat-util.h"
  #include "strbuf.h"
  #include "hashmap.h"
 -#include "mru.h"
 +#include "list.h"
  #include "advice.h"
  #include "gettext.h"
  #include "convert.h"
  #include "sha1-array.h"
  #include "repository.h"
  
- #ifndef platform_SHA_CTX
- /*
-  * platform's underlying implementation of SHA-1; could be OpenSSL,
-  * blk_SHA, Apple CommonCrypto, etc...  Note that including
-  * SHA1_HEADER may have already defined platform_SHA_CTX for our
-  * own implementations like block-sha1 and ppc-sha1, so we list
-  * the default for OpenSSL compatible SHA-1 implementations here.
-  */
- #define platform_SHA_CTX      SHA_CTX
- #define platform_SHA1_Init    SHA1_Init
- #define platform_SHA1_Update  SHA1_Update
- #define platform_SHA1_Final           SHA1_Final
- #endif
- #define git_SHA_CTX           platform_SHA_CTX
- #define git_SHA1_Init         platform_SHA1_Init
- #define git_SHA1_Update               platform_SHA1_Update
- #define git_SHA1_Final                platform_SHA1_Final
- #ifdef SHA1_MAX_BLOCK_SIZE
- #include "compat/sha1-chunked.h"
- #undef git_SHA1_Update
- #define git_SHA1_Update               git_SHA1_Update_Chunked
- #endif
  #include <zlib.h>
  typedef struct git_zstream {
        z_stream z;
@@@ -345,8 -320,7 +320,8 @@@ struct index_state 
        struct split_index *split_index;
        struct cache_time timestamp;
        unsigned name_hash_initialized : 1,
 -               initialized : 1;
 +               initialized : 1,
 +               drop_cache_tree : 1;
        struct hashmap name_hash;
        struct hashmap dir_hash;
        unsigned char sha1[20];
@@@ -372,7 -346,7 +347,7 @@@ extern void free_name_hash(struct index
  #define active_cache_tree (the_index.cache_tree)
  
  #define read_cache() read_index(&the_index)
 -#define read_cache_from(path) read_index_from(&the_index, (path))
 +#define read_cache_from(path) read_index_from(&the_index, (path), (get_git_dir()))
  #define read_cache_preload(pathspec) read_index_preload(&the_index, (pathspec))
  #define is_cache_unborn() is_index_unborn(&the_index)
  #define read_cache_unmerged() read_index_unmerged(&the_index)
@@@ -617,8 -591,7 +592,8 @@@ extern int read_index(struct index_stat
  extern int read_index_preload(struct index_state *, const struct pathspec *pathspec);
  extern int do_read_index(struct index_state *istate, const char *path,
                         int must_exist); /* for testting only! */
 -extern int read_index_from(struct index_state *, const char *path);
 +extern int read_index_from(struct index_state *, const char *path,
 +                         const char *gitdir);
  extern int is_index_unborn(struct index_state *);
  extern int read_index_unmerged(struct index_state *);
  
@@@ -916,13 -889,10 +891,13 @@@ extern int grafts_replace_parents
  #define GIT_REPO_VERSION 0
  #define GIT_REPO_VERSION_READ 1
  extern int repository_format_precious_objects;
 +extern char *repository_format_partial_clone;
 +extern const char *core_partial_clone_filter_default;
  
  struct repository_format {
        int version;
        int precious_objects;
 +      char *partial_clone; /* value of extensions.partialclone */
        int is_bare;
        int hash_algo;
        char *work_tree;
@@@ -962,10 -932,12 +937,10 @@@ extern void check_repository_format(voi
  #define TYPE_CHANGED    0x0040
  
  /*
 - * Return the name of the file in the local object database that would
 - * be used to store a loose object with the specified sha1.  The
 - * return value is a pointer to a statically allocated buffer that is
 - * overwritten each time the function is called.
 + * Put in `buf` the name of the file in the local object database that
 + * would be used to store a loose object with the specified sha1.
   */
 -extern const char *sha1_file_name(const unsigned char *sha1);
 +extern void sha1_file_name(struct strbuf *buf, const unsigned char *sha1);
  
  /*
   * Return an abbreviated sha1 unique within this repository's object database.
@@@ -1032,7 -1004,7 +1007,7 @@@ static inline void hashclr(unsigned cha
  
  static inline void oidclr(struct object_id *oid)
  {
 -      hashclr(oid->hash);
 +      memset(oid->hash, 0, GIT_MAX_RAWSZ);
  }
  
  
@@@ -1050,6 -1022,8 +1025,6 @@@ extern const struct object_id empty_tre
        "\xe6\x9d\xe2\x9b\xb2\xd1\xd6\x43\x4b\x8b" \
        "\x29\xae\x77\x5a\xd8\xc2\xe4\x8c\x53\x91"
  extern const struct object_id empty_blob_oid;
 -#define EMPTY_BLOB_SHA1_BIN (empty_blob_oid.hash)
 -
  
  static inline int is_empty_blob_sha1(const unsigned char *sha1)
  {
@@@ -1239,22 -1213,11 +1214,22 @@@ static inline const unsigned char *look
  
  /* Read and unpack a sha1 file into memory, write memory to a sha1 file */
  extern int sha1_object_info(const unsigned char *, unsigned long *);
 -extern int hash_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *sha1);
 -extern int write_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *return_sha1);
 -extern int hash_sha1_file_literally(const void *buf, unsigned long len, const char *type, struct object_id *oid, unsigned flags);
 -extern int pretend_sha1_file(void *, unsigned long, enum object_type, unsigned char *);
 -extern int force_object_loose(const unsigned char *sha1, time_t mtime);
 +
 +extern int hash_object_file(const void *buf, unsigned long len,
 +                          const char *type, struct object_id *oid);
 +
 +extern int write_object_file(const void *buf, unsigned long len,
 +                           const char *type, struct object_id *oid);
 +
 +extern int hash_object_file_literally(const void *buf, unsigned long len,
 +                                    const char *type, struct object_id *oid,
 +                                    unsigned flags);
 +
 +extern int pretend_object_file(void *, unsigned long, enum object_type,
 +                             struct object_id *oid);
 +
 +extern int force_object_loose(const struct object_id *oid, time_t mtime);
 +
  extern int git_open_cloexec(const char *name, int flags);
  #define git_open(name) git_open_cloexec(name, O_RDONLY)
  extern void *map_sha1_file(const unsigned char *sha1, unsigned long *size);
@@@ -1647,7 -1610,6 +1622,7 @@@ struct pack_window 
  
  extern struct packed_git {
        struct packed_git *next;
 +      struct list_head mru;
        struct pack_window *windows;
        off_t pack_size;
        const void *index_data;
        unsigned pack_local:1,
                 pack_keep:1,
                 freshened:1,
 -               do_not_close:1;
 +               do_not_close:1,
 +               pack_promisor:1;
        unsigned char sha1[20];
        struct revindex_entry *revindex;
        /* something like ".git/objects/pack/xxxxx.pack" */
  } *packed_git;
  
  /*
 - * A most-recently-used ordered version of the packed_git list, which can
 - * be iterated instead of packed_git (and marked via mru_mark).
 + * A most-recently-used ordered version of the packed_git list.
   */
 -extern struct mru packed_git_mru;
 +extern struct list_head packed_git_mru;
  
  struct pack_entry {
        off_t offset;
@@@ -1800,14 -1762,6 +1775,14 @@@ struct object_info 
  #define OBJECT_INFO_QUICK 8
  extern int sha1_object_info_extended(const unsigned char *, struct object_info *, unsigned flags);
  
 +/*
 + * Set this to 0 to prevent sha1_object_info_extended() from fetching missing
 + * blobs. This has a difference only if extensions.partialClone is set.
 + *
 + * Its default value is 1.
 + */
 +extern int fetch_if_missing;
 +
  /* Dumb servers support */
  extern int update_server_info(int);
  
diff --combined read-cache.c
index f9871cde33ef5423f6e7e4e9d41ea7775bdb10f2,15bbb9bab497446519dfc69da33bd96a979a3587..6339e61760e9fbd59f341016903fc78143d30e53
@@@ -631,10 -631,10 +631,10 @@@ static struct cache_entry *create_alias
  
  void set_object_name_for_intent_to_add_entry(struct cache_entry *ce)
  {
 -      unsigned char sha1[20];
 -      if (write_sha1_file("", 0, blob_type, sha1))
 +      struct object_id oid;
 +      if (write_object_file("", 0, blob_type, &oid))
                die("cannot create an empty blob in the object database");
 -      hashcpy(ce->oid.hash, sha1);
 +      oidcpy(&ce->oid, &oid);
  }
  
  int add_to_index(struct index_state *istate, const char *path, struct stat *st, int flags)
@@@ -1217,8 -1217,9 +1217,8 @@@ int add_index_entry(struct index_state 
        /* Add it in.. */
        istate->cache_nr++;
        if (istate->cache_nr > pos + 1)
 -              memmove(istate->cache + pos + 1,
 -                      istate->cache + pos,
 -                      (istate->cache_nr - pos - 1) * sizeof(ce));
 +              MOVE_ARRAY(istate->cache + pos + 1, istate->cache + pos,
 +                         istate->cache_nr - pos - 1);
        set_index_entry(istate, pos, ce);
        istate->cache_changed |= CE_ENTRY_ADDED;
        return 0;
@@@ -1544,8 -1545,8 +1544,8 @@@ int verify_ce_order
  
  static int verify_hdr(struct cache_header *hdr, unsigned long size)
  {
-       git_SHA_CTX c;
-       unsigned char sha1[20];
+       git_hash_ctx c;
+       unsigned char hash[GIT_MAX_RAWSZ];
        int hdr_version;
  
        if (hdr->hdr_signature != htonl(CACHE_SIGNATURE))
        if (!verify_index_checksum)
                return 0;
  
-       git_SHA1_Init(&c);
-       git_SHA1_Update(&c, hdr, size - 20);
-       git_SHA1_Final(sha1, &c);
-       if (hashcmp(sha1, (unsigned char *)hdr + size - 20))
+       the_hash_algo->init_fn(&c);
+       the_hash_algo->update_fn(&c, hdr, size - the_hash_algo->rawsz);
+       the_hash_algo->final_fn(hash, &c);
+       if (hashcmp(hash, (unsigned char *)hdr + size - the_hash_algo->rawsz))
                return error("bad index file sha1 signature");
        return 0;
  }
@@@ -1602,7 -1603,7 +1602,7 @@@ int hold_locked_index(struct lock_file 
  
  int read_index(struct index_state *istate)
  {
 -      return read_index_from(istate, get_index_file());
 +      return read_index_from(istate, get_index_file(), get_git_dir());
  }
  
  static struct cache_entry *cache_entry_from_ondisk(struct ondisk_cache_entry *ondisk,
@@@ -1790,7 -1791,7 +1790,7 @@@ int do_read_index(struct index_state *i
                die_errno("cannot stat the open index");
  
        mmap_size = xsize_t(st.st_size);
-       if (mmap_size < sizeof(struct cache_header) + 20)
+       if (mmap_size < sizeof(struct cache_header) + the_hash_algo->rawsz)
                die("index file smaller than expected");
  
        mmap = xmmap(NULL, mmap_size, PROT_READ, MAP_PRIVATE, fd, 0);
        if (verify_hdr(hdr, mmap_size) < 0)
                goto unmap;
  
-       hashcpy(istate->sha1, (const unsigned char *)hdr + mmap_size - 20);
+       hashcpy(istate->sha1, (const unsigned char *)hdr + mmap_size - the_hash_algo->rawsz);
        istate->version = ntohl(hdr->hdr_version);
        istate->cache_nr = ntohl(hdr->hdr_entries);
        istate->cache_alloc = alloc_nr(istate->cache_nr);
        istate->timestamp.sec = st.st_mtime;
        istate->timestamp.nsec = ST_MTIME_NSEC(st);
  
-       while (src_offset <= mmap_size - 20 - 8) {
+       while (src_offset <= mmap_size - the_hash_algo->rawsz - 8) {
                /* After an array of active_nr index entries,
                 * there can be arbitrary number of extended
                 * sections, each of which is prefixed with
@@@ -1862,19 -1863,20 +1862,19 @@@ unmap
   * This way, shared index can be removed if they have not been used
   * for some time.
   */
 -static void freshen_shared_index(char *base_sha1_hex, int warn)
 +static void freshen_shared_index(const char *shared_index, int warn)
  {
 -      char *shared_index = git_pathdup("sharedindex.%s", base_sha1_hex);
        if (!check_and_freshen_file(shared_index, 1) && warn)
                warning("could not freshen shared index '%s'", shared_index);
 -      free(shared_index);
  }
  
 -int read_index_from(struct index_state *istate, const char *path)
 +int read_index_from(struct index_state *istate, const char *path,
 +                  const char *gitdir)
  {
        struct split_index *split_index;
        int ret;
        char *base_sha1_hex;
 -      const char *base_path;
 +      char *base_path;
  
        /* istate->initialized covers both .git/index and .git/sharedindex.xxx */
        if (istate->initialized)
                split_index->base = xcalloc(1, sizeof(*split_index->base));
  
        base_sha1_hex = sha1_to_hex(split_index->base_sha1);
 -      base_path = git_path("sharedindex.%s", base_sha1_hex);
 +      base_path = xstrfmt("%s/sharedindex.%s", gitdir, base_sha1_hex);
        ret = do_read_index(split_index->base, base_path, 1);
        if (hashcmp(split_index->base_sha1, split_index->base->sha1))
                die("broken index, expect %s in %s, got %s",
                    base_sha1_hex, base_path,
                    sha1_to_hex(split_index->base->sha1));
  
 -      freshen_shared_index(base_sha1_hex, 0);
 +      freshen_shared_index(base_path, 0);
        merge_base_index(istate);
        post_read_index_from(istate);
 +      free(base_path);
        return ret;
  }
  
@@@ -1956,11 -1957,11 +1956,11 @@@ int unmerged_index(const struct index_s
  static unsigned char write_buffer[WRITE_BUFFER_SIZE];
  static unsigned long write_buffer_len;
  
- static int ce_write_flush(git_SHA_CTX *context, int fd)
+ static int ce_write_flush(git_hash_ctx *context, int fd)
  {
        unsigned int buffered = write_buffer_len;
        if (buffered) {
-               git_SHA1_Update(context, write_buffer, buffered);
+               the_hash_algo->update_fn(context, write_buffer, buffered);
                if (write_in_full(fd, write_buffer, buffered) < 0)
                        return -1;
                write_buffer_len = 0;
        return 0;
  }
  
- static int ce_write(git_SHA_CTX *context, int fd, void *data, unsigned int len)
+ static int ce_write(git_hash_ctx *context, int fd, void *data, unsigned int len)
  {
        while (len) {
                unsigned int buffered = write_buffer_len;
        return 0;
  }
  
- static int write_index_ext_header(git_SHA_CTX *context, int fd,
+ static int write_index_ext_header(git_hash_ctx *context, int fd,
                                  unsigned int ext, unsigned int sz)
  {
        ext = htonl(ext);
                (ce_write(context, fd, &sz, 4) < 0)) ? -1 : 0;
  }
  
- static int ce_flush(git_SHA_CTX *context, int fd, unsigned char *sha1)
+ static int ce_flush(git_hash_ctx *context, int fd, unsigned char *hash)
  {
        unsigned int left = write_buffer_len;
  
        if (left) {
                write_buffer_len = 0;
-               git_SHA1_Update(context, write_buffer, left);
+               the_hash_algo->update_fn(context, write_buffer, left);
        }
  
-       /* Flush first if not enough space for SHA1 signature */
-       if (left + 20 > WRITE_BUFFER_SIZE) {
+       /* Flush first if not enough space for hash signature */
+       if (left + the_hash_algo->rawsz > WRITE_BUFFER_SIZE) {
                if (write_in_full(fd, write_buffer, left) < 0)
                        return -1;
                left = 0;
        }
  
-       /* Append the SHA1 signature at the end */
-       git_SHA1_Final(write_buffer + left, context);
-       hashcpy(sha1, write_buffer + left);
-       left += 20;
+       /* Append the hash signature at the end */
+       the_hash_algo->final_fn(write_buffer + left, context);
+       hashcpy(hash, write_buffer + left);
+       left += the_hash_algo->rawsz;
        return (write_in_full(fd, write_buffer, left) < 0) ? -1 : 0;
  }
  
@@@ -2099,7 -2100,7 +2099,7 @@@ static void copy_cache_entry_to_ondisk(
        }
  }
  
- static int ce_write_entry(git_SHA_CTX *c, int fd, struct cache_entry *ce,
+ static int ce_write_entry(git_hash_ctx *c, int fd, struct cache_entry *ce,
                          struct strbuf *previous_name, struct ondisk_cache_entry *ondisk)
  {
        int size;
@@@ -2166,7 -2167,7 +2166,7 @@@ static int verify_index_from(const stru
        int fd;
        ssize_t n;
        struct stat st;
-       unsigned char sha1[20];
+       unsigned char hash[GIT_MAX_RAWSZ];
  
        if (!istate->initialized)
                return 0;
        if (fstat(fd, &st))
                goto out;
  
-       if (st.st_size < sizeof(struct cache_header) + 20)
+       if (st.st_size < sizeof(struct cache_header) + the_hash_algo->rawsz)
                goto out;
  
-       n = pread_in_full(fd, sha1, 20, st.st_size - 20);
-       if (n != 20)
+       n = pread_in_full(fd, hash, the_hash_algo->rawsz, st.st_size - the_hash_algo->rawsz);
+       if (n != the_hash_algo->rawsz)
                goto out;
  
-       if (hashcmp(istate->sha1, sha1))
+       if (hashcmp(istate->sha1, hash))
                goto out;
  
        close(fd);
@@@ -2234,7 -2235,7 +2234,7 @@@ static int do_write_index(struct index_
                          int strip_extensions)
  {
        int newfd = tempfile->fd;
-       git_SHA_CTX c;
+       git_hash_ctx c;
        struct cache_header hdr;
        int i, err = 0, removed, extended, hdr_version;
        struct cache_entry **cache = istate->cache;
        struct stat st;
        struct ondisk_cache_entry_extended ondisk;
        struct strbuf previous_name_buf = STRBUF_INIT, *previous_name;
 -      int drop_cache_tree = 0;
 +      int drop_cache_tree = istate->drop_cache_tree;
  
        for (i = removed = extended = 0; i < entries; i++) {
                if (cache[i]->ce_flags & CE_REMOVE)
        hdr.hdr_version = htonl(hdr_version);
        hdr.hdr_entries = htonl(entries - removed);
  
-       git_SHA1_Init(&c);
+       the_hash_algo->init_fn(&c);
        if (ce_write(&c, newfd, &hdr, sizeof(hdr)) < 0)
                return -1;
  
@@@ -2471,21 -2472,32 +2471,21 @@@ static int clean_shared_index_files(con
  }
  
  static int write_shared_index(struct index_state *istate,
 -                            struct lock_file *lock, unsigned flags)
 +                            struct tempfile **temp)
  {
 -      struct tempfile *temp;
        struct split_index *si = istate->split_index;
        int ret;
  
 -      temp = mks_tempfile(git_path("sharedindex_XXXXXX"));
 -      if (!temp) {
 -              hashclr(si->base_sha1);
 -              return do_write_locked_index(istate, lock, flags);
 -      }
        move_cache_to_base_index(istate);
 -      ret = do_write_index(si->base, temp, 1);
 -      if (ret) {
 -              delete_tempfile(&temp);
 +      ret = do_write_index(si->base, *temp, 1);
 +      if (ret)
                return ret;
 -      }
 -      ret = adjust_shared_perm(get_tempfile_path(temp));
 +      ret = adjust_shared_perm(get_tempfile_path(*temp));
        if (ret) {
 -              int save_errno = errno;
 -              error("cannot fix permission bits on %s", get_tempfile_path(temp));
 -              delete_tempfile(&temp);
 -              errno = save_errno;
 +              error("cannot fix permission bits on %s", get_tempfile_path(*temp));
                return ret;
        }
 -      ret = rename_tempfile(&temp,
 +      ret = rename_tempfile(temp,
                              git_path("sharedindex.%s", sha1_to_hex(si->base->sha1)));
        if (!ret) {
                hashcpy(si->base_sha1, si->base->sha1);
@@@ -2553,22 -2565,7 +2553,22 @@@ int write_locked_index(struct index_sta
        new_shared_index = istate->cache_changed & SPLIT_INDEX_ORDERED;
  
        if (new_shared_index) {
 -              ret = write_shared_index(istate, lock, flags);
 +              struct tempfile *temp;
 +              int saved_errno;
 +
 +              temp = mks_tempfile(git_path("sharedindex_XXXXXX"));
 +              if (!temp) {
 +                      hashclr(si->base_sha1);
 +                      ret = do_write_locked_index(istate, lock, flags);
 +                      goto out;
 +              }
 +              ret = write_shared_index(istate, &temp);
 +
 +              saved_errno = errno;
 +              if (is_tempfile_active(temp))
 +                      delete_tempfile(&temp);
 +              errno = saved_errno;
 +
                if (ret)
                        goto out;
        }
        ret = write_split_index(istate, lock, flags);
  
        /* Freshen the shared index only if the split-index was written */
 -      if (!ret && !new_shared_index)
 -              freshen_shared_index(sha1_to_hex(si->base_sha1), 1);
 +      if (!ret && !new_shared_index) {
 +              const char *shared_index = git_path("sharedindex.%s",
 +                                                  sha1_to_hex(si->base_sha1));
 +              freshen_shared_index(shared_index, 1);
 +      }
  
  out:
        if (flags & COMMIT_LOCK)
diff --combined sha1_file.c
index 81a4bfb80137d0e76cefa65b8282806131006fd0,ff55fb303dcbc0c0a67d1bffc740896c5bc4116c..826d7a0ae377445c117a646ef26f79dc02785122
  #include "bulk-checkin.h"
  #include "streaming.h"
  #include "dir.h"
 -#include "mru.h"
  #include "list.h"
  #include "mergesort.h"
  #include "quote.h"
  #include "packfile.h"
 +#include "fetch-object.h"
  
  const unsigned char null_sha1[GIT_MAX_RAWSZ];
  const struct object_id null_oid;
@@@ -39,32 -39,32 +39,32 @@@ const struct object_id empty_blob_oid 
        EMPTY_BLOB_SHA1_BIN_LITERAL
  };
  
- static void git_hash_sha1_init(void *ctx)
+ static void git_hash_sha1_init(git_hash_ctx *ctx)
  {
-       git_SHA1_Init((git_SHA_CTX *)ctx);
+       git_SHA1_Init(&ctx->sha1);
  }
  
- static void git_hash_sha1_update(void *ctx, const void *data, size_t len)
+ static void git_hash_sha1_update(git_hash_ctx *ctx, const void *data, size_t len)
  {
-       git_SHA1_Update((git_SHA_CTX *)ctx, data, len);
+       git_SHA1_Update(&ctx->sha1, data, len);
  }
  
- static void git_hash_sha1_final(unsigned char *hash, void *ctx)
+ static void git_hash_sha1_final(unsigned char *hash, git_hash_ctx *ctx)
  {
-       git_SHA1_Final(hash, (git_SHA_CTX *)ctx);
+       git_SHA1_Final(hash, &ctx->sha1);
  }
  
- static void git_hash_unknown_init(void *ctx)
+ static void git_hash_unknown_init(git_hash_ctx *ctx)
  {
        die("trying to init unknown hash");
  }
  
- static void git_hash_unknown_update(void *ctx, const void *data, size_t len)
+ static void git_hash_unknown_update(git_hash_ctx *ctx, const void *data, size_t len)
  {
        die("trying to update unknown hash");
  }
  
- static void git_hash_unknown_final(unsigned char *hash, void *ctx)
+ static void git_hash_unknown_final(unsigned char *hash, git_hash_ctx *ctx)
  {
        die("trying to finalize unknown hash");
  }
@@@ -75,7 -75,6 +75,6 @@@ const struct git_hash_algo hash_algos[G
                0x00000000,
                0,
                0,
-               0,
                git_hash_unknown_init,
                git_hash_unknown_update,
                git_hash_unknown_final,
@@@ -86,7 -85,6 +85,6 @@@
                "sha-1",
                /* "sha1", big-endian */
                0x73686131,
-               sizeof(git_SHA_CTX),
                GIT_SHA1_RAWSZ,
                GIT_SHA1_HEXSZ,
                git_hash_sha1_init,
@@@ -133,14 -131,14 +131,14 @@@ static struct cached_object *find_cache
  }
  
  
 -static enum safe_crlf get_safe_crlf(unsigned flags)
 +static int get_conv_flags(unsigned flags)
  {
        if (flags & HASH_RENORMALIZE)
 -              return SAFE_CRLF_RENORMALIZE;
 +              return CONV_EOL_RENORMALIZE;
        else if (flags & HASH_WRITE_OBJECT)
 -              return safe_crlf;
 +        return global_conv_flags_eol;
        else
 -              return SAFE_CRLF_FALSE;
 +              return 0;
  }
  
  
@@@ -321,11 -319,15 +319,11 @@@ static void fill_sha1_path(struct strbu
        }
  }
  
 -const char *sha1_file_name(const unsigned char *sha1)
 +void sha1_file_name(struct strbuf *buf, const unsigned char *sha1)
  {
 -      static struct strbuf buf = STRBUF_INIT;
 -
 -      strbuf_reset(&buf);
 -      strbuf_addf(&buf, "%s/", get_object_directory());
 -
 -      fill_sha1_path(&buf, sha1);
 -      return buf.buf;
 +      strbuf_addstr(buf, get_object_directory());
 +      strbuf_addch(buf, '/');
 +      fill_sha1_path(buf, sha1);
  }
  
  struct strbuf *alt_scratch_buf(struct alternate_object_database *alt)
@@@ -706,12 -708,7 +704,12 @@@ int check_and_freshen_file(const char *
  
  static int check_and_freshen_local(const unsigned char *sha1, int freshen)
  {
 -      return check_and_freshen_file(sha1_file_name(sha1), freshen);
 +      static struct strbuf buf = STRBUF_INIT;
 +
 +      strbuf_reset(&buf);
 +      sha1_file_name(&buf, sha1);
 +
 +      return check_and_freshen_file(buf.buf, freshen);
  }
  
  static int check_and_freshen_nonlocal(const unsigned char *sha1, int freshen)
@@@ -792,12 -789,12 +790,12 @@@ int check_sha1_signature(const unsigne
        struct object_id real_oid;
        enum object_type obj_type;
        struct git_istream *st;
-       git_SHA_CTX c;
+       git_hash_ctx c;
        char hdr[32];
        int hdrlen;
  
        if (map) {
 -              hash_sha1_file(map, size, type, real_oid.hash);
 +              hash_object_file(map, size, type, &real_oid);
                return hashcmp(sha1, real_oid.hash) ? -1 : 0;
        }
  
        hdrlen = xsnprintf(hdr, sizeof(hdr), "%s %lu", typename(obj_type), size) + 1;
  
        /* Sha1.. */
-       git_SHA1_Init(&c);
-       git_SHA1_Update(&c, hdr, hdrlen);
+       the_hash_algo->init_fn(&c);
+       the_hash_algo->update_fn(&c, hdr, hdrlen);
        for (;;) {
                char buf[1024 * 16];
                ssize_t readlen = read_istream(st, buf, sizeof(buf));
                }
                if (!readlen)
                        break;
-               git_SHA1_Update(&c, buf, readlen);
+               the_hash_algo->update_fn(&c, buf, readlen);
        }
-       git_SHA1_Final(real_oid.hash, &c);
+       the_hash_algo->final_fn(real_oid.hash, &c);
        close_istream(st);
        return hashcmp(sha1, real_oid.hash) ? -1 : 0;
  }
@@@ -867,12 -864,8 +865,12 @@@ static int stat_sha1_file(const unsigne
                          const char **path)
  {
        struct alternate_object_database *alt;
 +      static struct strbuf buf = STRBUF_INIT;
 +
 +      strbuf_reset(&buf);
 +      sha1_file_name(&buf, sha1);
 +      *path = buf.buf;
  
 -      *path = sha1_file_name(sha1);
        if (!lstat(*path, st))
                return 0;
  
@@@ -896,12 -889,8 +894,12 @@@ static int open_sha1_file(const unsigne
        int fd;
        struct alternate_object_database *alt;
        int most_interesting_errno;
 +      static struct strbuf buf = STRBUF_INIT;
 +
 +      strbuf_reset(&buf);
 +      sha1_file_name(&buf, sha1);
 +      *path = buf.buf;
  
 -      *path = sha1_file_name(sha1);
        fd = git_open(*path);
        if (fd >= 0)
                return fd;
@@@ -1222,8 -1211,6 +1220,8 @@@ static int sha1_loose_object_info(cons
        return (status < 0) ? status : 0;
  }
  
 +int fetch_if_missing = 1;
 +
  int sha1_object_info_extended(const unsigned char *sha1, struct object_info *oi, unsigned flags)
  {
        static struct object_info blank_oi = OBJECT_INFO_INIT;
        const unsigned char *real = (flags & OBJECT_INFO_LOOKUP_REPLACE) ?
                                    lookup_replace_object(sha1) :
                                    sha1;
 +      int already_retried = 0;
  
        if (is_null_sha1(real))
                return -1;
                }
        }
  
 -      if (!find_pack_entry(real, &e)) {
 +      while (1) {
 +              if (find_pack_entry(real, &e))
 +                      break;
 +
                /* Most likely it's a loose object. */
                if (!sha1_loose_object_info(real, oi, flags))
                        return 0;
  
                /* Not a loose object; someone else may have just packed it. */
 -              if (flags & OBJECT_INFO_QUICK) {
 -                      return -1;
 -              } else {
 -                      reprepare_packed_git();
 -                      if (!find_pack_entry(real, &e))
 -                              return -1;
 +              reprepare_packed_git();
 +              if (find_pack_entry(real, &e))
 +                      break;
 +
 +              /* Check if it is a missing object */
 +              if (fetch_if_missing && repository_format_partial_clone &&
 +                  !already_retried) {
 +                      /*
 +                       * TODO Investigate haveing fetch_object() return
 +                       * TODO error/success and stopping the music here.
 +                       */
 +                      fetch_object(repository_format_partial_clone, real);
 +                      already_retried = 1;
 +                      continue;
                }
 +
 +              return -1;
        }
  
        if (oi == &blank_oi)
                 * information below, so return early.
                 */
                return 0;
 -
        rtype = packed_object_info(e.p, e.offset, oi);
        if (rtype < 0) {
                mark_bad_packed_object(e.p, real);
@@@ -1336,13 -1310,13 +1334,13 @@@ static void *read_object(const unsigne
        return content;
  }
  
 -int pretend_sha1_file(void *buf, unsigned long len, enum object_type type,
 -                    unsigned char *sha1)
 +int pretend_object_file(void *buf, unsigned long len, enum object_type type,
 +                      struct object_id *oid)
  {
        struct cached_object *co;
  
 -      hash_sha1_file(buf, len, typename(type), sha1);
 -      if (has_sha1_file(sha1) || find_cached_object(sha1))
 +      hash_object_file(buf, len, typename(type), oid);
 +      if (has_sha1_file(oid->hash) || find_cached_object(oid->hash))
                return 0;
        ALLOC_GROW(cached_objects, cached_object_nr + 1, cached_object_alloc);
        co = &cached_objects[cached_object_nr++];
        co->type = type;
        co->buf = xmalloc(len);
        memcpy(co->buf, buf, len);
 -      hashcpy(co->sha1, sha1);
 +      hashcpy(co->sha1, oid->hash);
        return 0;
  }
  
@@@ -1443,20 -1417,20 +1441,20 @@@ void *read_object_with_reference(const 
        }
  }
  
 -static void write_sha1_file_prepare(const void *buf, unsigned long len,
 -                                    const char *type, unsigned char *sha1,
 -                                    char *hdr, int *hdrlen)
 +static void write_object_file_prepare(const void *buf, unsigned long len,
 +                                    const char *type, struct object_id *oid,
 +                                    char *hdr, int *hdrlen)
  {
-       git_SHA_CTX c;
+       git_hash_ctx c;
  
        /* Generate the header */
        *hdrlen = xsnprintf(hdr, *hdrlen, "%s %lu", type, len)+1;
  
        /* Sha1.. */
-       git_SHA1_Init(&c);
-       git_SHA1_Update(&c, hdr, *hdrlen);
-       git_SHA1_Update(&c, buf, len);
-       git_SHA1_Final(oid->hash, &c);
+       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(sha1, &c);
++      the_hash_algo->final_fn(oid->hash, &c);
  }
  
  /*
@@@ -1509,12 -1483,12 +1507,12 @@@ static int write_buffer(int fd, const v
        return 0;
  }
  
 -int hash_sha1_file(const void *buf, unsigned long len, const char *type,
 -                   unsigned char *sha1)
 +int hash_object_file(const void *buf, unsigned long len, const char *type,
 +                   struct object_id *oid)
  {
        char hdr[32];
        int hdrlen = sizeof(hdr);
 -      write_sha1_file_prepare(buf, len, type, sha1, hdr, &hdrlen);
 +      write_object_file_prepare(buf, len, type, oid, hdr, &hdrlen);
        return 0;
  }
  
@@@ -1572,22 -1546,18 +1570,22 @@@ static int create_tmpfile(struct strbu
        return fd;
  }
  
 -static int write_loose_object(const unsigned char *sha1, char *hdr, int hdrlen,
 -                            const void *buf, unsigned long len, time_t mtime)
 +static int write_loose_object(const struct object_id *oid, char *hdr,
 +                            int hdrlen, const void *buf, unsigned long len,
 +                            time_t mtime)
  {
        int fd, ret;
        unsigned char compressed[4096];
        git_zstream stream;
-       git_SHA_CTX c;
+       git_hash_ctx c;
        struct object_id parano_oid;
        static struct strbuf tmp_file = STRBUF_INIT;
 -      const char *filename = sha1_file_name(sha1);
 +      static struct strbuf filename = STRBUF_INIT;
 +
 +      strbuf_reset(&filename);
 +      sha1_file_name(&filename, oid->hash);
  
 -      fd = create_tmpfile(&tmp_file, filename);
 +      fd = create_tmpfile(&tmp_file, filename.buf);
        if (fd < 0) {
                if (errno == EACCES)
                        return error("insufficient permission for adding an object to repository database %s", get_object_directory());
        git_deflate_init(&stream, zlib_compression_level);
        stream.next_out = compressed;
        stream.avail_out = sizeof(compressed);
-       git_SHA1_Init(&c);
+       the_hash_algo->init_fn(&c);
  
        /* First header.. */
        stream.next_in = (unsigned char *)hdr;
        stream.avail_in = hdrlen;
        while (git_deflate(&stream, 0) == Z_OK)
                ; /* nothing */
-       git_SHA1_Update(&c, hdr, hdrlen);
+       the_hash_algo->update_fn(&c, hdr, hdrlen);
  
        /* Then the data itself.. */
        stream.next_in = (void *)buf;
        do {
                unsigned char *in0 = stream.next_in;
                ret = git_deflate(&stream, Z_FINISH);
-               git_SHA1_Update(&c, in0, stream.next_in - in0);
+               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");
                stream.next_out = compressed;
        } while (ret == Z_OK);
  
        if (ret != Z_STREAM_END)
 -              die("unable to deflate new object %s (%d)", sha1_to_hex(sha1), ret);
 +              die("unable to deflate new object %s (%d)", oid_to_hex(oid),
 +                  ret);
        ret = git_deflate_end_gently(&stream);
        if (ret != Z_OK)
 -              die("deflateEnd on object %s failed (%d)", sha1_to_hex(sha1), ret);
 +              die("deflateEnd on object %s failed (%d)", oid_to_hex(oid),
 +                  ret);
-       git_SHA1_Final(parano_oid.hash, &c);
+       the_hash_algo->final_fn(parano_oid.hash, &c);
 -      if (hashcmp(sha1, parano_oid.hash) != 0)
 -              die("confused by unstable object source data for %s", sha1_to_hex(sha1));
 +      if (oidcmp(oid, &parano_oid) != 0)
 +              die("confused by unstable object source data for %s",
 +                  oid_to_hex(oid));
  
        close_sha1_file(fd);
  
                        warning_errno("failed utime() on %s", tmp_file.buf);
        }
  
 -      return finalize_object_file(tmp_file.buf, filename);
 +      return finalize_object_file(tmp_file.buf, filename.buf);
  }
  
  static int freshen_loose_object(const unsigned char *sha1)
@@@ -1664,8 -1631,7 +1662,8 @@@ static int freshen_packed_object(const 
        return 1;
  }
  
 -int write_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *sha1)
 +int write_object_file(const void *buf, unsigned long len, const char *type,
 +                    struct object_id *oid)
  {
        char hdr[32];
        int hdrlen = sizeof(hdr);
        /* Normally if we have it in the pack then we do not bother writing
         * it out into .git/objects/??/?{38} file.
         */
 -      write_sha1_file_prepare(buf, len, type, sha1, hdr, &hdrlen);
 -      if (freshen_packed_object(sha1) || freshen_loose_object(sha1))
 +      write_object_file_prepare(buf, len, type, oid, hdr, &hdrlen);
 +      if (freshen_packed_object(oid->hash) || freshen_loose_object(oid->hash))
                return 0;
 -      return write_loose_object(sha1, hdr, hdrlen, buf, len, 0);
 +      return write_loose_object(oid, hdr, hdrlen, buf, len, 0);
  }
  
 -int hash_sha1_file_literally(const void *buf, unsigned long len, const char *type,
 -                           struct object_id *oid, unsigned flags)
 +int hash_object_file_literally(const void *buf, unsigned long len,
 +                             const char *type, struct object_id *oid,
 +                             unsigned flags)
  {
        char *header;
        int hdrlen, status = 0;
        /* type string, SP, %lu of the length plus NUL must fit this */
        hdrlen = strlen(type) + 32;
        header = xmalloc(hdrlen);
 -      write_sha1_file_prepare(buf, len, type, oid->hash, header, &hdrlen);
 +      write_object_file_prepare(buf, len, type, oid, header, &hdrlen);
  
        if (!(flags & HASH_WRITE_OBJECT))
                goto cleanup;
        if (freshen_packed_object(oid->hash) || freshen_loose_object(oid->hash))
                goto cleanup;
 -      status = write_loose_object(oid->hash, header, hdrlen, buf, len, 0);
 +      status = write_loose_object(oid, header, hdrlen, buf, len, 0);
  
  cleanup:
        free(header);
        return status;
  }
  
 -int force_object_loose(const unsigned char *sha1, time_t mtime)
 +int force_object_loose(const struct object_id *oid, time_t mtime)
  {
        void *buf;
        unsigned long len;
        int hdrlen;
        int ret;
  
 -      if (has_loose_object(sha1))
 +      if (has_loose_object(oid->hash))
                return 0;
 -      buf = read_object(sha1, &type, &len);
 +      buf = read_object(oid->hash, &type, &len);
        if (!buf)
 -              return error("cannot read sha1_file for %s", sha1_to_hex(sha1));
 +              return error("cannot read sha1_file for %s", oid_to_hex(oid));
        hdrlen = xsnprintf(hdr, sizeof(hdr), "%s %lu", typename(type), len) + 1;
 -      ret = write_loose_object(sha1, hdr, hdrlen, buf, len, mtime);
 +      ret = write_loose_object(oid, hdr, hdrlen, buf, len, mtime);
        free(buf);
  
        return ret;
@@@ -1785,7 -1750,7 +1783,7 @@@ static int index_mem(struct object_id *
        if ((type == OBJ_BLOB) && path) {
                struct strbuf nbuf = STRBUF_INIT;
                if (convert_to_git(&the_index, path, buf, size, &nbuf,
 -                                 get_safe_crlf(flags))) {
 +                                 get_conv_flags(flags))) {
                        buf = strbuf_detach(&nbuf, &size);
                        re_allocated = 1;
                }
        }
  
        if (write_object)
 -              ret = write_sha1_file(buf, size, typename(type), oid->hash);
 +              ret = write_object_file(buf, size, typename(type), oid);
        else
 -              ret = hash_sha1_file(buf, size, typename(type), oid->hash);
 +              ret = hash_object_file(buf, size, typename(type), oid);
        if (re_allocated)
                free(buf);
        return ret;
@@@ -1819,14 -1784,14 +1817,14 @@@ static int index_stream_convert_blob(st
        assert(would_convert_to_git_filter_fd(path));
  
        convert_to_git_filter_fd(&the_index, path, fd, &sbuf,
 -                               get_safe_crlf(flags));
 +                               get_conv_flags(flags));
  
        if (write_object)
 -              ret = write_sha1_file(sbuf.buf, sbuf.len, typename(OBJ_BLOB),
 -                                    oid->hash);
 +              ret = write_object_file(sbuf.buf, sbuf.len, typename(OBJ_BLOB),
 +                                      oid);
        else
 -              ret = hash_sha1_file(sbuf.buf, sbuf.len, typename(OBJ_BLOB),
 -                                   oid->hash);
 +              ret = hash_object_file(sbuf.buf, sbuf.len, typename(OBJ_BLOB),
 +                                     oid);
        strbuf_release(&sbuf);
        return ret;
  }
@@@ -1940,8 -1905,8 +1938,8 @@@ int index_path(struct object_id *oid, c
                if (strbuf_readlink(&sb, path, st->st_size))
                        return error_errno("readlink(\"%s\")", path);
                if (!(flags & HASH_WRITE_OBJECT))
 -                      hash_sha1_file(sb.buf, sb.len, blob_type, oid->hash);
 -              else if (write_sha1_file(sb.buf, sb.len, blob_type, oid->hash))
 +                      hash_object_file(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);
                break;
@@@ -2126,14 -2091,14 +2124,14 @@@ static int check_stream_sha1(git_zstrea
                             const char *path,
                             const unsigned char *expected_sha1)
  {
-       git_SHA_CTX c;
+       git_hash_ctx c;
        unsigned char real_sha1[GIT_MAX_RAWSZ];
        unsigned char buf[4096];
        unsigned long total_read;
        int status = Z_OK;
  
-       git_SHA1_Init(&c);
-       git_SHA1_Update(&c, hdr, stream->total_out);
+       the_hash_algo->init_fn(&c);
+       the_hash_algo->update_fn(&c, hdr, stream->total_out);
  
        /*
         * We already read some bytes into hdr, but the ones up to the NUL
                if (size - total_read < stream->avail_out)
                        stream->avail_out = size - total_read;
                status = git_inflate(stream, Z_FINISH);
-               git_SHA1_Update(&c, buf, stream->next_out - buf);
+               the_hash_algo->update_fn(&c, buf, stream->next_out - buf);
                total_read += stream->next_out - buf;
        }
        git_inflate_end(stream);
                return -1;
        }
  
-       git_SHA1_Final(real_sha1, &c);
+       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));