diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index 1d9dc31454..8ce3d0045a 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -1760,7 +1760,7 @@ static int want_object_in_pack_mtime(const struct object_id *oid, struct odb_source *source = the_repository->objects->sources->next; for (; source; source = source->next) { struct odb_source_files *files = odb_source_files_downcast(source); - if (!odb_source_read_object_info(&files->loose->base, oid, NULL, 0)) + if (!odb_source_read_object_info(&files->loose->base, oid, NULL, 0, NULL)) return 0; } } @@ -1787,7 +1787,7 @@ static int want_object_in_pack_mtime(const struct object_id *oid, struct multi_pack_index *m = get_multi_pack_index(files->packed); struct pack_entry e; - if (m && fill_midx_entry(m, oid, &e)) { + if (m && fill_midx_entry(m, oid, &e, NULL)) { want = want_object_in_pack_one(e.p, oid, exclude, found_pack, found_offset, found_mtime); if (want != -1) return want; @@ -4171,7 +4171,7 @@ static void add_cruft_object_entry(const struct object_id *oid, enum object_type for (; !found && source; source = source->next) { struct odb_source_files *files = odb_source_files_downcast(source); - if (!odb_source_read_object_info(&files->loose->base, oid, NULL, 0)) + if (!odb_source_read_object_info(&files->loose->base, oid, NULL, 0, NULL)) found = 1; } @@ -4637,7 +4637,7 @@ static int force_object_loose(struct odb_source *source, for (struct odb_source *s = source->odb->sources; s; s = s->next) { struct odb_source_files *files = odb_source_files_downcast(s); - if (!odb_source_read_object_info(&files->loose->base, oid, NULL, 0)) + if (!odb_source_read_object_info(&files->loose->base, oid, NULL, 0, NULL)) return 0; } diff --git a/midx.c b/midx.c index 76c3f92cc3..37f082dbdd 100644 --- a/midx.c +++ b/midx.c @@ -591,7 +591,8 @@ uint32_t nth_midxed_pack_int_id(struct multi_pack_index *m, uint32_t pos) int fill_midx_entry(struct multi_pack_index *m, const struct object_id *oid, - struct pack_entry *e) + struct pack_entry *e, + struct packed_git **bad_pack) { uint32_t pos; uint32_t pack_int_id; @@ -618,8 +619,11 @@ int fill_midx_entry(struct multi_pack_index *m, return 0; if (oidset_size(&p->bad_objects) && - oidset_contains(&p->bad_objects, oid)) + oidset_contains(&p->bad_objects, oid)) { + if (bad_pack && !*bad_pack) + *bad_pack = p; return 0; + } e->offset = nth_midxed_offset(m, pos); e->p = p; @@ -1028,7 +1032,7 @@ int verify_midx_file(struct odb_source_packed *source, unsigned flags) nth_midxed_object_oid(&oid, m, pairs[i].pos); - if (!fill_midx_entry(m, &oid, &e)) { + if (!fill_midx_entry(m, &oid, &e, NULL)) { midx_report(_("failed to load pack entry for oid[%d] = %s"), pairs[i].pos, oid_to_hex(&oid)); continue; diff --git a/midx.h b/midx.h index 939c18e588..1f2f2d5321 100644 --- a/midx.h +++ b/midx.h @@ -117,7 +117,8 @@ uint32_t nth_midxed_pack_int_id(struct multi_pack_index *m, uint32_t pos); struct object_id *nth_midxed_object_oid(struct object_id *oid, struct multi_pack_index *m, uint32_t n); -int fill_midx_entry(struct multi_pack_index *m, const struct object_id *oid, struct pack_entry *e); +int fill_midx_entry(struct multi_pack_index *m, const struct object_id *oid, + struct pack_entry *e, struct packed_git **bad_pack); int midx_contains_pack(struct multi_pack_index *m, const char *idx_or_pack_name); int midx_layer_contains_pack(struct multi_pack_index *m, diff --git a/odb.c b/odb.c index 7181c3652d..22417601ed 100644 --- a/odb.c +++ b/odb.c @@ -15,7 +15,6 @@ #include "object-name.h" #include "odb.h" #include "odb/source-inmemory.h" -#include "packfile.h" #include "path.h" #include "promisor-remote.h" #include "quote.h" @@ -547,12 +546,15 @@ static int register_all_submodule_sources(struct object_database *odb) return ret; } -static int do_oid_object_info_extended(struct object_database *odb, - const struct object_id *oid, - struct object_info *oi, unsigned flags) +static enum odb_read_status do_oid_object_info_extended(struct object_database *odb, + const struct object_id *oid, + struct object_info *oi, unsigned flags) { + struct strbuf corrupt_err = STRBUF_INIT; const struct object_id *real = oid; + enum odb_read_status ret; int already_retried = 0; + bool corrupt = false; if (flags & OBJECT_INFO_LOOKUP_REPLACE) real = lookup_replace_object(odb->repo, oid); @@ -560,7 +562,7 @@ static int do_oid_object_info_extended(struct object_database *odb, if (is_null_oid(real)) return -1; - if (!odb_source_read_object_info(odb->inmemory_objects, oid, oi, flags)) + if (!odb_source_read_object_info(odb->inmemory_objects, oid, oi, flags, NULL)) return 0; odb_prepare_alternates(odb); @@ -568,9 +570,14 @@ static int do_oid_object_info_extended(struct object_database *odb, while (1) { struct odb_source *source; - for (source = odb->sources; source; source = source->next) - if (!odb_source_read_object_info(source, real, oi, flags)) - return 0; + for (source = odb->sources; source; source = source->next) { + ret = odb_source_read_object_info(source, real, oi, flags, + corrupt_err.len ? NULL : &corrupt_err); + if (!ret) + goto out; + if (ret != ODB_READ_NOT_FOUND) + corrupt = true; + } /* * When the object hasn't been found we try a second read and @@ -578,10 +585,15 @@ static int do_oid_object_info_extended(struct object_database *odb, * caches or reload on-disk state. */ if (!(flags & OBJECT_INFO_QUICK)) { - for (source = odb->sources; source; source = source->next) - if (!odb_source_read_object_info(source, real, oi, - flags | OBJECT_INFO_SECOND_READ)) - return 0; + for (source = odb->sources; source; source = source->next) { + ret = odb_source_read_object_info(source, real, oi, + flags | OBJECT_INFO_SECOND_READ, + corrupt_err.len ? NULL : &corrupt_err); + if (!ret) + goto out; + if (ret != ODB_READ_NOT_FOUND) + corrupt = true; + } } /* @@ -604,16 +616,23 @@ static int do_oid_object_info_extended(struct object_database *odb, } if (flags & OBJECT_INFO_DIE_IF_CORRUPT) { - const struct packed_git *p; if ((flags & OBJECT_INFO_LOOKUP_REPLACE) && !oideq(real, oid)) die(_("replacement %s not found for %s"), oid_to_hex(real), oid_to_hex(oid)); - if ((p = has_packed_and_bad(odb->repo, real))) - die(_("packed object %s (stored in %s) is corrupt"), - oid_to_hex(real), p->pack_name); + if (corrupt) { + if (corrupt_err.len) + die("%s", corrupt_err.buf); + die(_("object %s is corrupt"), oid_to_hex(real)); + } } - return -1; + + ret = corrupt ? ODB_READ_ERROR : ODB_READ_NOT_FOUND; + goto out; } + +out: + strbuf_release(&corrupt_err); + return ret; } static int oid_object_info_convert(struct repository *r, @@ -696,12 +715,12 @@ static int oid_object_info_convert(struct repository *r, return ret; } -int odb_read_object_info_extended(struct object_database *odb, - const struct object_id *oid, - struct object_info *oi, - enum object_info_flags flags) +enum odb_read_status odb_read_object_info_extended(struct object_database *odb, + const struct object_id *oid, + struct object_info *oi, + enum object_info_flags flags) { - int ret; + enum odb_read_status ret; if (oid->algo && (hash_algo_by_ptr(odb->repo->hash_algo) != oid->algo)) return oid_object_info_convert(odb->repo, oid, oi, flags); diff --git a/odb.h b/odb.h index 3dd51fd85d..c41fb5d07c 100644 --- a/odb.h +++ b/odb.h @@ -448,14 +448,23 @@ enum object_info_flags { OBJECT_INFO_FOR_PREFETCH = (OBJECT_INFO_SKIP_FETCH_OBJECT | OBJECT_INFO_QUICK), }; +enum odb_read_status { + /* The read was successful. */ + ODB_READ_OK = 0, + /* The read resulted in a generic error. */ + ODB_READ_ERROR = -1, + /* The object could not be found. */ + ODB_READ_NOT_FOUND = -2, +}; + /* * Read object info from the object database and populate the `object_info` * structure. Returns 0 on success, a negative error code otherwise. */ -int odb_read_object_info_extended(struct object_database *odb, - const struct object_id *oid, - struct object_info *oi, - enum object_info_flags flags); +enum odb_read_status odb_read_object_info_extended(struct object_database *odb, + const struct object_id *oid, + struct object_info *oi, + enum object_info_flags flags); /* * Read a subset of object info for the given object ID. Returns an `enum diff --git a/odb/source-files.c b/odb/source-files.c index 3945d651b9..221448b910 100644 --- a/odb/source-files.c +++ b/odb/source-files.c @@ -75,18 +75,35 @@ static void odb_source_files_prepare(struct odb_source *source, odb_source_prepare(&files->packed->base, flags); } -static int odb_source_files_read_object_info(struct odb_source *source, - const struct object_id *oid, - struct object_info *oi, - enum object_info_flags flags) +static enum odb_read_status odb_source_files_read_object_info(struct odb_source *source, + const struct object_id *oid, + struct object_info *oi, + enum object_info_flags flags, + struct strbuf *errmsg) { struct odb_source_files *files = odb_source_files_downcast(source); + enum odb_read_status ret_packed, ret_loose; - if (!odb_source_read_object_info(&files->packed->base, oid, oi, flags) || - !odb_source_read_object_info(&files->loose->base, oid, oi, flags)) + ret_packed = odb_source_read_object_info(&files->packed->base, oid, oi, + flags, errmsg); + if (!ret_packed) return 0; - return -1; + ret_loose = odb_source_read_object_info(&files->loose->base, oid, oi, flags, + ret_packed == ODB_READ_NOT_FOUND ? errmsg : NULL); + if (!ret_loose) + return 0; + + /* + * Reading the packed object may have failed even though the object + * exists, for example because it is corrupt. Report this failure to + * the caller in case neither of the sources was able to read the + * object, and prefer the error of the packed source in case both + * reads have failed. + */ + if (ret_packed != ODB_READ_NOT_FOUND) + return ret_packed; + return ret_loose; } static int odb_source_files_read_object_stream(struct odb_stream **out, diff --git a/odb/source-inmemory.c b/odb/source-inmemory.c index 795672adf2..4905e71c7e 100644 --- a/odb/source-inmemory.c +++ b/odb/source-inmemory.c @@ -56,17 +56,18 @@ static void populate_object_info(struct odb_source_inmemory *source, oi->source_infop->source = &source->base; } -static int odb_source_inmemory_read_object_info(struct odb_source *source, - const struct object_id *oid, - struct object_info *oi, - enum object_info_flags flags UNUSED) +static enum odb_read_status odb_source_inmemory_read_object_info(struct odb_source *source, + const struct object_id *oid, + struct object_info *oi, + enum object_info_flags flags UNUSED, + struct strbuf *errmsg UNUSED) { struct odb_source_inmemory *inmemory = odb_source_inmemory_downcast(source); const struct inmemory_object *object; object = find_cached_object(inmemory, oid); if (!object) - return -1; + return ODB_READ_NOT_FOUND; populate_object_info(inmemory, oi, object); return 0; diff --git a/odb/source-loose.c b/odb/source-loose.c index 0921a87480..524405445b 100644 --- a/odb/source-loose.c +++ b/odb/source-loose.c @@ -67,7 +67,8 @@ static int read_object_info_from_path(struct odb_source_loose *loose, const char *path, const struct object_id *oid, struct object_info *oi, - enum object_info_flags flags) + enum object_info_flags flags, + struct strbuf *errmsg) { int ret; int fd; @@ -91,11 +92,16 @@ static int read_object_info_from_path(struct odb_source_loose *loose, struct stat st; if ((!oi || (!oi->disk_sizep && !oi->mtimep)) && (flags & OBJECT_INFO_QUICK)) { - ret = quick_has_loose(loose, oid) ? 0 : -1; + ret = quick_has_loose(loose, oid) ? 0 : ODB_READ_NOT_FOUND; goto out; } if (lstat(path, &st) < 0) { + if (errno == ENOENT) { + ret = ODB_READ_NOT_FOUND; + goto out; + } + ret = -1; goto out; } @@ -113,9 +119,12 @@ static int read_object_info_from_path(struct odb_source_loose *loose, fd = git_open(path); if (fd < 0) { - if (errno != ENOENT) - error_errno(_("unable to open loose object %s"), oid_to_hex(oid)); - ret = -1; + if (errno == ENOENT) { + ret = ODB_READ_NOT_FOUND; + goto out; + } + + ret = error_errno(_("unable to open loose object %s"), oid_to_hex(oid)); goto out; } @@ -155,7 +164,7 @@ static int read_object_info_from_path(struct odb_source_loose *loose, if (parse_loose_header(hdr, oi) < 0) { ret = error(_("unable to parse %s header"), oid_to_hex(oid)); - goto corrupt; + goto out; } if (*oi->typep < 0) @@ -165,7 +174,7 @@ static int read_object_info_from_path(struct odb_source_loose *loose, *oi->contentp = unpack_loose_rest(&stream, hdr, *oi->sizep, oid); if (!*oi->contentp) { ret = -1; - goto corrupt; + goto out; } } @@ -173,21 +182,19 @@ static int read_object_info_from_path(struct odb_source_loose *loose, case ULHR_BAD: ret = error(_("unable to unpack %s header"), oid_to_hex(oid)); - goto corrupt; + goto out; case ULHR_TOO_LONG: ret = error(_("header for %s too long, exceeds %d bytes"), oid_to_hex(oid), MAX_HEADER_LEN); - goto corrupt; + goto out; } ret = 0; -corrupt: - if (ret && (flags & OBJECT_INFO_DIE_IF_CORRUPT)) - die(_("loose object %s (stored in %s) is corrupt"), - oid_to_hex(oid), path); - out: + if (ret && ret != ODB_READ_NOT_FOUND && errmsg) + strbuf_addf(errmsg, _("loose object %s (stored in %s) is corrupt"), + oid_to_hex(oid), path); if (stream_to_end) git_inflate_end(stream_to_end); if (map) @@ -206,10 +213,11 @@ out: return ret; } -static int odb_source_loose_read_object_info(struct odb_source *source, - const struct object_id *oid, - struct object_info *oi, - enum object_info_flags flags) +static enum odb_read_status odb_source_loose_read_object_info(struct odb_source *source, + const struct object_id *oid, + struct object_info *oi, + enum object_info_flags flags, + struct strbuf *errmsg) { struct odb_source_loose *loose = odb_source_loose_downcast(source); static struct strbuf buf = STRBUF_INIT; @@ -221,10 +229,10 @@ static int odb_source_loose_read_object_info(struct odb_source *source, * second time. */ if (flags & OBJECT_INFO_SECOND_READ) - return -1; + return ODB_READ_NOT_FOUND; odb_loose_path(loose, &buf, oid); - return read_object_info_from_path(loose, buf.buf, oid, oi, flags); + return read_object_info_from_path(loose, buf.buf, oid, oi, flags, errmsg); } /* @@ -421,7 +429,7 @@ static int for_each_object_wrapper_cb(const struct object_id *oid, if (data->request) { struct object_info oi = *data->request; - if (read_object_info_from_path(data->loose, path, oid, &oi, 0) < 0) + if (read_object_info_from_path(data->loose, path, oid, &oi, 0, NULL) < 0) return -1; return data->cb(oid, &oi, data->cb_data); @@ -439,7 +447,7 @@ static int for_each_prefixed_object_wrapper_cb(const struct object_id *oid, struct object_info oi = *data->request; if (odb_source_read_object_info(&data->loose->base, - oid, &oi, 0) < 0) + oid, &oi, 0, NULL) < 0) return -1; return data->cb(oid, &oi, data->cb_data); diff --git a/odb/source-packed.c b/odb/source-packed.c index 9b23ea15dc..1d90e714e6 100644 --- a/odb/source-packed.c +++ b/odb/source-packed.c @@ -2,7 +2,9 @@ #include "abspath.h" #include "chdir-notify.h" #include "dir.h" +#include "gettext.h" #include "git-zlib.h" +#include "hex.h" #include "list-objects-filter-options.h" #include "mergesort.h" #include "midx.h" @@ -10,21 +12,23 @@ #include "odb/streaming.h" #include "packfile.h" #include "pack-bitmap.h" +#include "strbuf.h" static int find_pack_entry(struct odb_source_packed *store, const struct object_id *oid, - struct pack_entry *e) + struct pack_entry *e, + struct packed_git **bad_pack) { struct packfile_list_entry *l; odb_source_prepare(&store->base, 0); - if (store->midx && fill_midx_entry(store->midx, oid, e)) + if (store->midx && fill_midx_entry(store->midx, oid, e, bad_pack)) return 1; for (l = store->packs.head; l; l = l->next) { struct packed_git *p = l->pack; - if (!p->multi_pack_index && packfile_fill_entry(p, oid, e)) { + if (!p->multi_pack_index && packfile_fill_entry(p, oid, e, bad_pack)) { if (!store->skip_mru_updates) packfile_list_prepend(&store->packs, p); return 1; @@ -34,12 +38,14 @@ static int find_pack_entry(struct odb_source_packed *store, return 0; } -static int odb_source_packed_read_object_info(struct odb_source *source, - const struct object_id *oid, - struct object_info *oi, - enum object_info_flags flags) +static enum odb_read_status odb_source_packed_read_object_info(struct odb_source *source, + const struct object_id *oid, + struct object_info *oi, + enum object_info_flags flags, + struct strbuf *errmsg) { struct odb_source_packed *packed = odb_source_packed_downcast(source); + struct packed_git *bad_pack = NULL; struct pack_entry e; int ret; @@ -51,23 +57,45 @@ static int odb_source_packed_read_object_info(struct odb_source *source, if (flags & OBJECT_INFO_SECOND_READ) odb_source_prepare(source, ODB_PREPARE_FLUSH_CACHES); - if (!find_pack_entry(packed, oid, &e)) - return 1; + if (!find_pack_entry(packed, oid, &e, &bad_pack)) { + /* + * The lookup may have failed because the object is known to be + * corrupt in one of the packfiles. Report the object as + * corrupt instead of missing in that case. + */ + if (bad_pack) { + ret = -1; + goto out; + } + + ret = ODB_READ_NOT_FOUND; + goto out; + } /* * We know that the caller doesn't actually need the * information below, so return early. */ - if (!oi) - return 0; + if (!oi) { + ret = 0; + goto out; + } ret = packed_object_info(packed, e.p, e.offset, oi); if (ret < 0) { + bad_pack = e.p; mark_bad_packed_object(e.p, oid); - return -1; + goto out; } - return 0; + ret = 0; + +out: + if (ret < 0 && bad_pack && errmsg) + strbuf_addf(errmsg, _("packed object %s (stored in %s) is corrupt"), + oid_to_hex(oid), bad_pack->pack_name); + + return ret; } static int odb_source_packed_read_object_stream(struct odb_stream **out, @@ -77,7 +105,7 @@ static int odb_source_packed_read_object_stream(struct odb_stream **out, struct odb_source_packed *packed = odb_source_packed_downcast(source); struct pack_entry e; - if (!find_pack_entry(packed, oid, &e)) + if (!find_pack_entry(packed, oid, &e, NULL)) return -1; return packfile_read_object_stream(out, oid, e.p, e.offset); @@ -583,7 +611,7 @@ static int odb_source_packed_freshen_object(struct odb_source *source, timesp = × } - if (!find_pack_entry(packed, oid, &e)) + if (!find_pack_entry(packed, oid, &e, NULL)) return 0; if (e.p->is_cruft) return 0; diff --git a/odb/source.h b/odb/source.h index fed5692096..1aba10eae9 100644 --- a/odb/source.h +++ b/odb/source.h @@ -33,6 +33,7 @@ const char *odb_source_type_to_name(enum odb_source_type type); struct object_id; struct odb_stream; +struct strbuf; struct strvec; /* @@ -128,13 +129,17 @@ struct odb_source { * second read in case they know that the first read would have * already surfaced the object without reloading any on-disk state. * - * The callback is expected to return a negative error code in case - * reading the object has failed, 0 otherwise. + * The callback is expected to return an `enum odb_read_status`. Please + * refer to the individual values that can be returned. In case reading + * the object has failed with a generic error and `errmsg` is non-NULL, + * the callback is expected to populate it with a human-readable + * message that describes the failure. */ - int (*read_object_info)(struct odb_source *source, - const struct object_id *oid, - struct object_info *oi, - enum object_info_flags flags); + enum odb_read_status (*read_object_info)(struct odb_source *source, + const struct object_id *oid, + struct object_info *oi, + enum object_info_flags flags, + struct strbuf *errmsg); /* * This callback is expected to create a new read stream that can be @@ -369,14 +374,19 @@ static inline void odb_source_prepare(struct odb_source *source, /* * Read an object from the object database source identified by its object ID. - * Returns 0 on success, a negative error code otherwise. + * Please refer to `enum odb_read_status` for the individual error codes. + * + * In case reading the object has failed with a generic error and `errmsg` is + * non-NULL it will be populated with a human-readable message that describes + * the failure. */ -static inline int odb_source_read_object_info(struct odb_source *source, - const struct object_id *oid, - struct object_info *oi, - enum object_info_flags flags) +static inline enum odb_read_status odb_source_read_object_info(struct odb_source *source, + const struct object_id *oid, + struct object_info *oi, + enum object_info_flags flags, + struct strbuf *errmsg) { - return source->read_object_info(source, oid, oi, flags); + return source->read_object_info(source, oid, oi, flags, errmsg); } /* diff --git a/packfile.c b/packfile.c index 2ec5d221b4..047a59ea6c 100644 --- a/packfile.c +++ b/packfile.c @@ -983,23 +983,6 @@ void mark_bad_packed_object(struct packed_git *p, const struct object_id *oid) oidset_insert(&p->bad_objects, oid); } -const struct packed_git *has_packed_and_bad(struct repository *r, - const struct object_id *oid) -{ - struct odb_source *source; - - for (source = r->objects->sources; source; source = source->next) { - struct odb_source_files *files = odb_source_files_downcast(source); - struct packfile_list_entry *e; - - for (e = files->packed->packs.head; e; e = e->next) - if (oidset_contains(&e->pack->bad_objects, oid)) - return e->pack; - } - - return NULL; -} - off_t get_delta_base(struct packed_git *p, struct pack_window **w_curs, off_t *curpos, @@ -1857,13 +1840,17 @@ int is_pack_valid(struct packed_git *p) int packfile_fill_entry(struct packed_git *p, const struct object_id *oid, - struct pack_entry *e) + struct pack_entry *e, + struct packed_git **bad_pack) { off_t offset; if (oidset_size(&p->bad_objects) && - oidset_contains(&p->bad_objects, oid)) + oidset_contains(&p->bad_objects, oid)) { + if (bad_pack && !*bad_pack) + *bad_pack = p; return 0; + } offset = find_pack_entry_one(oid, p); if (!offset) @@ -1939,7 +1926,7 @@ int has_object_pack(struct repository *r, const struct object_id *oid) odb_prepare_alternates(r->objects); for (source = r->objects->sources; source; source = source->next) { struct odb_source_files *files = odb_source_files_downcast(source); - if (!odb_source_read_object_info(&files->packed->base, oid, NULL, 0)) + if (!odb_source_read_object_info(&files->packed->base, oid, NULL, 0, NULL)) return 1; } @@ -1960,7 +1947,7 @@ int has_object_kept_pack(struct repository *r, const struct object_id *oid, for (; *cache; cache++) { struct packed_git *p = *cache; - if (packfile_fill_entry(p, oid, &e)) + if (packfile_fill_entry(p, oid, &e, NULL)) return 1; } } diff --git a/packfile.h b/packfile.h index c1e387d635..7149ad9f43 100644 --- a/packfile.h +++ b/packfile.h @@ -295,7 +295,8 @@ off_t find_pack_entry_one(const struct object_id *oid, struct packed_git *); int packfile_fill_entry(struct packed_git *p, const struct object_id *oid, - struct pack_entry *e); + struct pack_entry *e, + struct packed_git **bad_pack); int is_pack_valid(struct packed_git *); void *unpack_entry(struct repository *r, struct packed_git *, off_t, @@ -330,7 +331,6 @@ int packed_object_info_with_index_pos(struct odb_source_packed *source, uint32_t *maybe_index_pos, struct object_info *oi); void mark_bad_packed_object(struct packed_git *, const struct object_id *); -const struct packed_git *has_packed_and_bad(struct repository *, const struct object_id *); int has_object_pack(struct repository *r, const struct object_id *oid); int has_object_kept_pack(struct repository *r, const struct object_id *oid, diff --git a/t/helper/test-read-midx.c b/t/helper/test-read-midx.c index fb16ec0176..27a05da957 100644 --- a/t/helper/test-read-midx.c +++ b/t/helper/test-read-midx.c @@ -82,7 +82,7 @@ static int read_midx_file(const char *object_dir, const char *checksum, for (i = 0; i < m->num_objects; i++) { nth_midxed_object_oid(&oid, m, i + m->num_objects_in_base); - fill_midx_entry(m, &oid, &e); + fill_midx_entry(m, &oid, &e, NULL); printf("%s %"PRIu64"\t%s\n", oid_to_hex(&oid), e.offset, e.p->pack_name); diff --git a/t/t1060-object-corruption.sh b/t/t1060-object-corruption.sh index 502a5ea1c5..d2ef468b45 100755 --- a/t/t1060-object-corruption.sh +++ b/t/t1060-object-corruption.sh @@ -145,4 +145,22 @@ test_expect_success 'partial clone of corrupted repository' ' test_must_fail git -C corrupt-partial checkout --force ' +test_expect_success 'corrupted loose commit can be read from alternate' ' + git init repo-a && + tree=$(git -C repo-a write-tree) && + commit=$(git -C repo-a commit-tree $tree .git/objects/info/alternates && + corrupt_byte "$commit" 1 + ) && + + git -C repo-a cat-file -p "$commit" >expect && + git -C repo-b cat-file -p "$commit" >actual 2>err && + test_cmp expect actual && + test_grep "inflate: data stream error" err +' + test_done diff --git a/t/unit-tests/u-odb-inmemory.c b/t/unit-tests/u-odb-inmemory.c index 2f0ff331b4..a8da278c68 100644 --- a/t/unit-tests/u-odb-inmemory.c +++ b/t/unit-tests/u-odb-inmemory.c @@ -29,7 +29,7 @@ static void cl_assert_object_info(struct odb_source_inmemory *source, .contentp = &actual_content, }; - cl_must_pass(odb_source_read_object_info(&source->base, oid, &oi, 0)); + cl_must_pass(odb_source_read_object_info(&source->base, oid, &oi, 0, NULL)); cl_assert_equal_u(actual_size, strlen(expected_content)); cl_assert_equal_u(actual_type, expected_type); cl_assert_equal_s((char *) actual_content, expected_content); @@ -72,7 +72,8 @@ void test_odb_inmemory__read_missing_object(void) const char *end; cl_must_pass(parse_oid_hex_algop(RANDOM_OID, &oid, &end, repo.hash_algo)); - cl_must_fail(odb_source_read_object_info(&source->base, &oid, NULL, 0)); + cl_assert_equal_i(odb_source_read_object_info(&source->base, &oid, NULL, 0, NULL), + ODB_READ_NOT_FOUND); odb_source_free(&source->base); }