From: Junio C Hamano Date: Thu, 8 Feb 2018 23:08:27 +0000 (-0800) Subject: Merge branch 'bc/hash-algo' into next X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/18f36d12ed609328e43ff1b79a35e37fbd7941b4?hp=-c Merge branch 'bc/hash-algo' into next 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 --- 18f36d12ed609328e43ff1b79a35e37fbd7941b4 diff --combined builtin/index-pack.c index 16edfebf63,0bb520c731..7e3e1a461c --- a/builtin/index-pack.c +++ b/builtin/index-pack.c @@@ -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 @@@ -469,8 -469,8 +469,8 @@@ 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); @@@ -479,15 -479,15 +479,15 @@@ 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; @@@ -515,8 -515,8 +515,8 @@@ 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); @@@ -546,7 -546,7 +546,7 @@@ } 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) @@@ -1132,8 -1133,8 +1132,8 @@@ 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++; @@@ -1141,7 -1142,7 +1141,7 @@@ 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) { @@@ -1159,10 -1160,10 +1159,10 @@@ /* 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; @@@ -1261,7 -1262,7 +1261,7 @@@ 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", @@@ -1269,12 -1270,12 +1269,12 @@@ 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); } @@@ -1285,7 -1286,7 +1285,7 @@@ 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; @@@ -1299,7 -1300,7 +1299,7 @@@ 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) @@@ -1309,7 -1310,7 +1309,7 @@@ 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) { @@@ -1326,7 -1327,7 +1326,7 @@@ } 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; @@@ -1334,7 -1335,7 +1334,7 @@@ 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; @@@ -1388,60 -1389,15 +1388,60 @@@ free(sorted_by_pos); } +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, - const char *pack_name, const unsigned char *sha1, ++ 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, sha1, suffix); ++ 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) { @@@ -1453,16 -1409,32 +1453,16 @@@ 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) @@@ -1470,18 -1442,18 +1470,18 @@@ 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); @@@ -1500,6 -1472,7 +1500,6 @@@ 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); @@@ -1699,8 -1678,6 +1699,8 @@@ 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); @@@ -1763,7 -1740,9 +1763,7 @@@ 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) @@@ -1789,11 -1768,11 +1789,11 @@@ 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) @@@ -1805,18 -1784,19 +1805,18 @@@ 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 81ad914cfc,d91cbd460e..5c674b2843 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@@ -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; @@@ -188,7 -185,7 +188,7 @@@ 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, @@@ -246,14 -243,14 +246,14 @@@ 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; @@@ -326,8 -323,8 +326,8 @@@ 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) { /* @@@ -340,8 -337,8 +340,8 @@@ 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) { @@@ -350,13 -347,13 +350,13 @@@ 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); } @@@ -364,7 -361,7 +364,7 @@@ } /* 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; @@@ -415,8 -412,8 +415,8 @@@ 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) { @@@ -424,8 -421,8 +424,8 @@@ 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 { @@@ -433,7 -430,7 +433,7 @@@ 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); @@@ -442,7 -439,7 +442,7 @@@ } /* 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; @@@ -765,7 -762,7 +765,7 @@@ 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; @@@ -810,7 -807,7 +810,7 @@@ char *pack_tmp_name = NULL; if (pack_to_stdout) - f = sha1fd_throughput(1, "", progress_state); + f = hashfd_throughput(1, "", progress_state); else f = create_tmp_packfile(&pack_tmp_name); @@@ -837,11 -834,11 +837,11 @@@ * 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; @@@ -1026,8 -1023,8 +1026,8 @@@ 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) @@@ -1044,7 -1041,7 +1044,7 @@@ } 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) { @@@ -2609,18 -2592,10 +2609,18 @@@ 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(), }; @@@ -3081,12 -3054,6 +3081,12 @@@ 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 397371eb3d,813ca31979..7235d2ffbf --- a/builtin/unpack-objects.c +++ b/builtin/unpack-objects.c @@@ -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); @@@ -261,7 -258,7 +261,7 @@@ } 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 c2d14a2c37,bfde6f757a..21fbcc2414 --- a/cache.h +++ 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" @@@ -16,31 -16,6 +16,6 @@@ #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 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; @@@ -1661,8 -1623,7 +1636,8 @@@ 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" */ @@@ -1670,9 -1631,10 +1645,9 @@@ } *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 f9871cde33,15bbb9bab4..6339e61760 --- a/read-cache.c +++ b/read-cache.c @@@ -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)) @@@ -1557,10 -1558,10 +1557,10 @@@ 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); @@@ -1802,7 -1803,7 +1802,7 @@@ 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); @@@ -1830,7 -1831,7 +1830,7 @@@ 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) @@@ -1894,17 -1896,16 +1894,17 @@@ 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; @@@ -1968,7 -1969,7 +1968,7 @@@ 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; @@@ -1990,7 -1991,7 +1990,7 @@@ 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); @@@ -1999,26 -2000,26 +1999,26 @@@ (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; @@@ -2178,14 -2179,14 +2178,14 @@@ 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; @@@ -2242,7 -2243,7 +2242,7 @@@ 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) @@@ -2272,7 -2273,7 +2272,7 @@@ 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; } @@@ -2576,11 -2573,8 +2576,11 @@@ 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 81a4bfb801,ff55fb303d..826d7a0ae3 --- a/sha1_file.c +++ b/sha1_file.c @@@ -24,11 -24,11 +24,11 @@@ #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; } @@@ -809,8 -806,8 +807,8 @@@ 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)); @@@ -821,9 -818,9 +819,9 @@@ } 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; @@@ -1232,7 -1219,6 +1230,7 @@@ 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; @@@ -1260,32 -1246,19 +1258,32 @@@ } } - 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) @@@ -1294,6 -1267,7 +1292,6 @@@ * 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++]; @@@ -1350,7 -1324,7 +1348,7 @@@ 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()); @@@ -1599,14 -1569,14 +1597,14 @@@ 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; @@@ -1614,7 -1584,7 +1612,7 @@@ 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; @@@ -1622,16 -1592,13 +1620,16 @@@ } 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, ¶no_oid) != 0) + die("confused by unstable object source data for %s", + oid_to_hex(oid)); close_sha1_file(fd); @@@ -1643,7 -1610,7 +1641,7 @@@ 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); @@@ -1673,15 -1639,14 +1671,15 @@@ /* 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; @@@ -1689,20 -1654,20 +1687,20 @@@ /* 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; @@@ -1711,13 -1676,13 +1709,13 @@@ 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; } @@@ -1800,9 -1765,9 +1798,9 @@@ } 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 @@@ -2152,7 -2117,7 +2150,7 @@@ 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); @@@ -2167,7 -2132,7 +2165,7 @@@ 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));