aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJunio C Hamano <junkio@cox.net>2006-09-04 18:57:35 -0700
committerJunio C Hamano <junkio@cox.net>2006-09-04 18:57:35 -0700
commit8f5d6b469fdb41d549fb8624a54dc62ff1760c41 (patch)
tree4a6ab165ff8a64bb99f2cf7e81d94c194c2fa602
parentf685d07de045423a69045e42e72d2efc22a541ca (diff)
parent72518e9c2623af0b5de864a7b66208ea94aacadb (diff)
downloadgit-8f5d6b469fdb41d549fb8624a54dc62ff1760c41.tar.gz
git-8f5d6b469fdb41d549fb8624a54dc62ff1760c41.tar.xz
Merge branch 'jc/pack'
* 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.
-rw-r--r--builtin-pack-objects.c91
-rw-r--r--cache.h12
-rw-r--r--object.h11
-rw-r--r--sha1_file.c2
4 files changed, 100 insertions, 16 deletions
diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c
index 46f524dfc..149fa2839 100644
--- a/builtin-pack-objects.c
+++ b/builtin-pack-objects.c
@@ -65,6 +65,7 @@ static unsigned char pack_file_sha1[20];
static int progress = 1;
static volatile sig_atomic_t progress_update;
static int window = 10;
+static int pack_to_stdout;
/*
* 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
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,
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++;
@@ -286,7 +366,7 @@ static unsigned long write_object(struct sha1file *f,
munmap(map, mapsize);
}
- if (! to_reuse) {
+ if (!to_reuse) {
buf = read_sha1_file(entry->sha1, type, &size);
if (!buf)
die("unable to read %s", sha1_to_hex(entry->sha1));
@@ -319,6 +399,9 @@ 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, buf, datalen))
+ die("corrupt delta in pack %s", sha1_to_hex(entry->sha1));
sha1write(f, buf, datalen);
unuse_packed_git(p);
hdrlen = 0; /* not really */
@@ -1163,7 +1246,7 @@ static void prepare_pack(int window, int depth)
find_deltas(sorted_by_type, window+1, depth);
}
-static int reuse_cached_pack(unsigned char *sha1, int pack_to_stdout)
+static int reuse_cached_pack(unsigned char *sha1)
{
static const char cache[] = "pack-cache/pack-%s.%s";
char *cached_pack, *cached_idx;
@@ -1247,7 +1330,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
{
SHA_CTX ctx;
char line[40 + 1 + PATH_MAX + 2];
- int depth = 10, pack_to_stdout = 0;
+ int depth = 10;
struct object_entry **list;
int num_preferred_base = 0;
int i;
@@ -1367,7 +1450,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
if (progress && (nr_objects != nr_result))
fprintf(stderr, "Result has %d objects.\n", nr_result);
- if (reuse_cached_pack(object_list_sha1, pack_to_stdout))
+ if (reuse_cached_pack(object_list_sha1))
;
else {
if (nr_result)
diff --git a/cache.h b/cache.h
index 195908fc3..a53204f6d 100644
--- a/cache.h
+++ b/cache.h
@@ -267,6 +267,17 @@ extern int legacy_loose_object(unsigned char *);
extern int has_pack_file(const unsigned char *sha1);
extern int has_pack_index(const unsigned char *sha1);
+enum object_type {
+ OBJ_NONE = 0,
+ OBJ_COMMIT = 1,
+ OBJ_TREE = 2,
+ OBJ_BLOB = 3,
+ OBJ_TAG = 4,
+ /* 5/6 for future expansion */
+ OBJ_DELTA = 7,
+ OBJ_BAD,
+};
+
/* Convert to/from hex/sha1 representation */
#define MINIMUM_ABBREV 4
#define DEFAULT_ABBREV 7
@@ -374,6 +385,7 @@ extern int num_packed_objects(const struct packed_git *p);
extern int nth_packed_object_sha1(const struct packed_git *, int, unsigned char*);
extern int find_pack_entry_one(const unsigned char *, struct pack_entry *, struct packed_git *);
extern void *unpack_entry_gently(struct pack_entry *, char *, unsigned long *);
+extern unsigned long unpack_object_header_gently(const unsigned char *buf, unsigned long len, enum object_type *type, unsigned long *sizep);
extern void packed_object_info_detail(struct pack_entry *, char *, unsigned long *, unsigned long *, unsigned int *, unsigned char *);
/* Dumb servers support */
diff --git a/object.h b/object.h
index 733faac4c..3d4ff4611 100644
--- a/object.h
+++ b/object.h
@@ -27,17 +27,6 @@ struct object_array {
/*
* The object type is stored in 3 bits.
*/
-enum object_type {
- OBJ_NONE = 0,
- OBJ_COMMIT = 1,
- OBJ_TREE = 2,
- OBJ_BLOB = 3,
- OBJ_TAG = 4,
- /* 5/6 for future expansion */
- OBJ_DELTA = 7,
- OBJ_BAD,
-};
-
struct object {
unsigned parsed : 1;
unsigned used : 1;
diff --git a/sha1_file.c b/sha1_file.c
index 4ef98053f..428d791ba 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -711,7 +711,7 @@ int legacy_loose_object(unsigned char *map)
return 0;
}
-static unsigned long unpack_object_header_gently(const unsigned char *buf, unsigned long len, enum object_type *type, unsigned long *sizep)
+unsigned long unpack_object_header_gently(const unsigned char *buf, unsigned long len, enum object_type *type, unsigned long *sizep)
{
unsigned shift;
unsigned char c;