summaryrefslogtreecommitdiff
path: root/builtin-pack-objects.c
diff options
context:
space:
mode:
authorJunio C Hamano <junkio@cox.net>2006-09-03 21:09:18 -0700
committerJunio C Hamano <junkio@cox.net>2006-09-03 21:09:18 -0700
commit72518e9c2623af0b5de864a7b66208ea94aacadb (patch)
tree42d0ed3b6202af7e9f60639101e36827bd200128 /builtin-pack-objects.c
parent7042dbf7a1e9137eb856b3b086a062561c50b8a3 (diff)
downloadgit-72518e9c2623af0b5de864a7b66208ea94aacadb.tar.gz
more lightweight revalidation while reusing deflated stream in packing
When copying from an existing pack and when copying from a loose object with new style header, the code makes sure that the piece we are going to copy out inflates well and inflate() consumes the data in full while doing so. The check to see if the xdelta really apply is quite expensive as you described, because you would need to have the image of the base object which can be represented as a delta against something else. Signed-off-by: Junio C Hamano <junkio@cox.net>
Diffstat (limited to 'builtin-pack-objects.c')
-rw-r--r--builtin-pack-objects.c81
1 files changed, 52 insertions, 29 deletions
diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c
index 5e42387a45..149fa28397 100644
--- a/builtin-pack-objects.c
+++ b/builtin-pack-objects.c
@@ -243,41 +243,61 @@ static int encode_header(enum object_type type, unsigned long size, unsigned cha
return n;
}
-static int revalidate_one(struct object_entry *entry,
- void *data, char *type, unsigned long size)
+static int check_inflate(unsigned char *data, unsigned long len, unsigned long expect)
{
- int err;
- if ((!data) ||
- ((entry->type != OBJ_DELTA) &&
- ( (size != entry->size) ||
- strcmp(type_names[entry->type], type))))
- err = -1;
- else
- err = check_sha1_signature(entry->sha1, data, size, type);
- free(data);
- return err;
+ 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)
+static int revalidate_pack_entry(struct object_entry *entry, unsigned char *data, unsigned long len)
{
- void *data;
- char type[20];
- unsigned long size;
- struct pack_entry e;
+ enum object_type type;
+ unsigned long size, used;
if (pack_to_stdout)
return 0;
- e.p = entry->in_pack;
- e.offset = entry->in_pack_offset;
-
- /* the caller has already called use_packed_git() for us */
- data = unpack_entry_gently(&e, type, &size);
- return revalidate_one(entry, data, type, size);
+ /* 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,
@@ -285,15 +305,18 @@ static int revalidate_loose_object(struct object_entry *entry,
unsigned long mapsize)
{
/* we already know this is a loose object with new type header. */
- void *data;
- char type[20];
- unsigned long size;
+ enum object_type type;
+ unsigned long size, used;
if (pack_to_stdout)
return 0;
- data = unpack_sha1_file(map, mapsize, type, &size);
- return revalidate_one(entry, data, type, size);
+ 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,
@@ -377,7 +400,7 @@ static unsigned long write_object(struct sha1file *f,
datalen = find_packed_object_size(p, entry->in_pack_offset);
buf = (char *) p->pack_base + entry->in_pack_offset;
- if (revalidate_pack_entry(entry))
+ if (revalidate_pack_entry(entry, buf, datalen))
die("corrupt delta in pack %s", sha1_to_hex(entry->sha1));
sha1write(f, buf, datalen);
unuse_packed_git(p);