* jc/pack:
more lightweight revalidation while reusing deflated stream in packing
pack-objects: fix thinko in revalidate code
pack-objects: re-validate data we copy from elsewhere.
* The object names in objects array are hashed with this hashtable,
@ -242,6 +243,82 @@ static int encode_header(enum object_type type, unsigned long size, unsigned cha
@@ -242,6 +243,82 @@ static int encode_header(enum object_type type, unsigned long size, unsigned cha
return n;
}
static int check_inflate(unsigned char *data, unsigned long len, unsigned long expect)
{
z_stream stream;
unsigned char fakebuf[4096];
int st;
memset(&stream, 0, sizeof(stream));
stream.next_in = data;
stream.avail_in = len;
stream.next_out = fakebuf;
stream.avail_out = sizeof(fakebuf);
inflateInit(&stream);
while (1) {
st = inflate(&stream, Z_FINISH);
if (st == Z_STREAM_END || st == Z_OK) {
st = (stream.total_out == expect &&
stream.total_in == len) ? 0 : -1;
break;
}
if (st != Z_BUF_ERROR) {
st = -1;
break;
}
stream.next_out = fakebuf;
stream.avail_out = sizeof(fakebuf);
}
inflateEnd(&stream);
return st;
}
/*
* we are going to reuse the existing pack entry data. make
* sure it is not corrupt.
*/
static int revalidate_pack_entry(struct object_entry *entry, unsigned char *data, unsigned long len)
{
enum object_type type;
unsigned long size, used;
if (pack_to_stdout)
return 0;
/* the caller has already called use_packed_git() for us,
* so it is safe to access the pack data from mmapped location.
* make sure the entry inflates correctly.
*/
used = unpack_object_header_gently(data, len, &type, &size);
if (!used)
return -1;
if (type == OBJ_DELTA)
used += 20; /* skip base object name */
data += used;
len -= used;
return check_inflate(data, len, entry->size);
}
static int revalidate_loose_object(struct object_entry *entry,
unsigned char *map,
unsigned long mapsize)
{
/* we already know this is a loose object with new type header. */
enum object_type type;
unsigned long size, used;
if (pack_to_stdout)
return 0;
used = unpack_object_header_gently(map, mapsize, &type, &size);
if (!used)
return -1;
map += used;
mapsize -= used;
return check_inflate(map, mapsize, size);
}
static unsigned long write_object(struct sha1file *f,
struct object_entry *entry)
{
@ -276,6 +353,9 @@ static unsigned long write_object(struct sha1file *f,
@@ -276,6 +353,9 @@ static unsigned long write_object(struct sha1file *f,
map = map_sha1_file(entry->sha1, &mapsize);
if (map && !legacy_loose_object(map)) {
/* We can copy straight into the pack file */
if (revalidate_loose_object(entry, map, mapsize))
die("corrupt loose object %s",
sha1_to_hex(entry->sha1));
sha1write(f, map, mapsize);
munmap(map, mapsize);
written++;
@ -319,6 +399,9 @@ static unsigned long write_object(struct sha1file *f,
@@ -319,6 +399,9 @@ static unsigned long write_object(struct sha1file *f,