make packed_object_info() resilient to pack corruptions

In the same spirit as commit 8eca0b47ff, let's try to survive a pack
corruption by making packed_object_info() able to fall back to alternate
packs or loose objects.

Signed-off-by: Nicolas Pitre <nico@cam.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
maint
Nicolas Pitre 2008-10-29 19:02:47 -04:00 committed by Junio C Hamano
parent 09ded04b7e
commit 3d77d8774f
1 changed files with 30 additions and 6 deletions

View File

@ -1314,8 +1314,10 @@ unsigned long get_size_from_delta(struct packed_git *p,
} while ((st == Z_OK || st == Z_BUF_ERROR) && } while ((st == Z_OK || st == Z_BUF_ERROR) &&
stream.total_out < sizeof(delta_head)); stream.total_out < sizeof(delta_head));
inflateEnd(&stream); inflateEnd(&stream);
if ((st != Z_STREAM_END) && stream.total_out != sizeof(delta_head)) if ((st != Z_STREAM_END) && stream.total_out != sizeof(delta_head)) {
die("delta data unpack-initial failed"); error("delta data unpack-initial failed");
return 0;
}


/* Examine the initial part of the delta to figure out /* Examine the initial part of the delta to figure out
* the result size. * the result size.
@ -1382,15 +1384,29 @@ static int packed_delta_info(struct packed_git *p,
off_t base_offset; off_t base_offset;


base_offset = get_delta_base(p, w_curs, &curpos, type, obj_offset); base_offset = get_delta_base(p, w_curs, &curpos, type, obj_offset);
if (!base_offset)
return OBJ_BAD;
type = packed_object_info(p, base_offset, NULL); type = packed_object_info(p, base_offset, NULL);
if (type <= OBJ_NONE) {
struct revindex_entry *revidx = find_pack_revindex(p, base_offset);
const unsigned char *base_sha1 =
nth_packed_object_sha1(p, revidx->nr);
mark_bad_packed_object(p, base_sha1);
type = sha1_object_info(base_sha1, NULL);
if (type <= OBJ_NONE)
return OBJ_BAD;
}


/* We choose to only get the type of the base object and /* We choose to only get the type of the base object and
* ignore potentially corrupt pack file that expects the delta * ignore potentially corrupt pack file that expects the delta
* based on a base with a wrong size. This saves tons of * based on a base with a wrong size. This saves tons of
* inflate() calls. * inflate() calls.
*/ */
if (sizep) if (sizep) {
*sizep = get_size_from_delta(p, w_curs, curpos); *sizep = get_size_from_delta(p, w_curs, curpos);
if (*sizep == 0)
type = OBJ_BAD;
}


return type; return type;
} }
@ -1500,8 +1516,9 @@ static int packed_object_info(struct packed_git *p, off_t obj_offset,
*sizep = size; *sizep = size;
break; break;
default: default:
die("pack %s contains unknown object type %d", error("unknown object type %i at offset %"PRIuMAX" in %s",
p->pack_name, type); type, (uintmax_t)obj_offset, p->pack_name);
type = OBJ_BAD;
} }
unuse_pack(&w_curs); unuse_pack(&w_curs);
return type; return type;
@ -1971,7 +1988,14 @@ int sha1_object_info(const unsigned char *sha1, unsigned long *sizep)
if (!find_pack_entry(sha1, &e, NULL)) if (!find_pack_entry(sha1, &e, NULL))
return status; return status;
} }
return packed_object_info(e.p, e.offset, sizep);
status = packed_object_info(e.p, e.offset, sizep);
if (status < 0) {
mark_bad_packed_object(e.p, sha1);
status = sha1_object_info(sha1, sizep);
}

return status;
} }


static void *read_packed_sha1(const unsigned char *sha1, static void *read_packed_sha1(const unsigned char *sha1,