odb/source-packed: flag known-bad objects as corrupt and not missing

When reading packed objects we know to tell apart missing objects and
corrupt objects by returning a positive error code in the former case,
and a negative one in the latter case. We do that by distinguishing
between errors returned by `find_pack_entry()`, which yields the offset
of the object, and `packed_object_info()`, which reads the object
contents.

But even though we already distinguish those cases when reading packed
objects, the logic is broken in case a caller tries to read an object
that has been marked as corrupt. In that case, `find_pack_entry()` will
tell us that the object in question does not exist, and consequently
we'll not flag the object as corrupt but as missing.

Fix this issue by bubbling up whether the object is corrupt and, if so,
which packfile contains the corrupted object.

Note that we don't yet need the information about the specific packfile,
so we could've just as well made this a `bool *corrupted` pointer. But
we'll need information about the containing packfile in a subsequent
commit so that we can generate a proper error message telling the user
which packfile contains the broken object.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
main
Patrick Steinhardt 2026-08-19 14:17:19 +02:00 committed by Junio C Hamano
parent dea0ea3582
commit 47ef2193b3
7 changed files with 36 additions and 16 deletions

View File

@ -1786,7 +1786,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;

10
midx.c
View File

@ -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;

3
midx.h
View File

@ -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,

View File

@ -13,18 +13,19 @@

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;
@ -40,6 +41,7 @@ static int odb_source_packed_read_object_info(struct odb_source *source,
enum object_info_flags flags)
{
struct odb_source_packed *packed = odb_source_packed_downcast(source);
struct packed_git *bad_pack = NULL;
struct pack_entry e;
int ret;

@ -51,8 +53,16 @@ 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))
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)
return -1;
return 1;
}

/*
* We know that the caller doesn't actually need the
@ -77,7 +87,7 @@ static int odb_source_packed_read_object_stream(struct odb_read_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 +593,7 @@ static int odb_source_packed_freshen_object(struct odb_source *source,
timesp = &times;
}

if (!find_pack_entry(packed, oid, &e))
if (!find_pack_entry(packed, oid, &e, NULL))
return 0;
if (e.p->is_cruft)
return 0;

View File

@ -1859,13 +1859,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)
@ -1962,7 +1966,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;
}
}

View File

@ -294,7 +294,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,

View File

@ -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);