summary refs log tree commit diff
path: root/pack-check.c
diff options
context:
space:
mode:
authorNicolas Pitre <nico@cam.org>2008-06-24 23:19:02 -0400
committerJunio C Hamano <gitster@pobox.com>2008-06-24 23:58:57 -0700
commitc41a4a9468b0c728e77ec5d97da7bfb63776ac3f (patch)
tree6f17dc7359d8edae4043aa06a50eb88cba8d4304 /pack-check.c
parent77d3ecee85dbf354d2059d7ef65d788d90db3efa (diff)
verify-pack: check packed object CRC when using index version 2
To do so, check_pack_crc() moved from builtin-pack-objects.c to
pack-check.c where it is more logical to share.

Signed-off-by: Nicolas Pitre <nico@cam.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'pack-check.c')
-rw-r--r--pack-check.c39
1 files changed, 37 insertions, 2 deletions
diff --git a/pack-check.c b/pack-check.c
index 5f02a65b6e..f596bf2db5 100644
--- a/pack-check.c
+++ b/pack-check.c
@@ -4,8 +4,9 @@
 
 struct idx_entry
 {
-	const unsigned char *sha1;
 	off_t                offset;
+	const unsigned char *sha1;
+	unsigned int nr;
 };
 
 static int compare_entries(const void *e1, const void *e2)
@@ -19,6 +20,28 @@ static int compare_entries(const void *e1, const void *e2)
 	return 0;
 }
 
+int check_pack_crc(struct packed_git *p, struct pack_window **w_curs,
+		   off_t offset, off_t len, unsigned int nr)
+{
+	const uint32_t *index_crc;
+	uint32_t data_crc = crc32(0, Z_NULL, 0);
+
+	do {
+		unsigned int avail;
+		void *data = use_pack(p, w_curs, offset, &avail);
+		if (avail > len)
+			avail = len;
+		data_crc = crc32(data_crc, data, avail);
+		offset += avail;
+		len -= avail;
+	} while (len);
+
+	index_crc = p->index_data;
+	index_crc += 2 + 256 + p->num_objects * (20/4) + nr;
+
+	return data_crc != ntohl(*index_crc);
+}
+
 static int verify_packfile(struct packed_git *p,
 		struct pack_window **w_curs)
 {
@@ -61,13 +84,15 @@ static int verify_packfile(struct packed_git *p,
 	 * we do not do scan-streaming check on the pack file.
 	 */
 	nr_objects = p->num_objects;
-	entries = xmalloc(nr_objects * sizeof(*entries));
+	entries = xmalloc((nr_objects + 1) * sizeof(*entries));
+	entries[nr_objects].offset = pack_sig_ofs;
 	/* first sort entries by pack offset, since unpacking them is more efficient that way */
 	for (i = 0; i < nr_objects; i++) {
 		entries[i].sha1 = nth_packed_object_sha1(p, i);
 		if (!entries[i].sha1)
 			die("internal error pack-check nth-packed-object");
 		entries[i].offset = nth_packed_object_offset(p, i);
+		entries[i].nr = i;
 	}
 	qsort(entries, nr_objects, sizeof(*entries), compare_entries);
 
@@ -76,6 +101,16 @@ static int verify_packfile(struct packed_git *p,
 		enum object_type type;
 		unsigned long size;
 
+		if (p->index_version > 1) {
+			off_t offset = entries[i].offset;
+			off_t len = entries[i+1].offset - offset;
+			unsigned int nr = entries[i].nr;
+			if (check_pack_crc(p, w_curs, offset, len, nr))
+				err = error("index CRC mismatch for object %s "
+					    "from %s at offset %"PRIuMAX"",
+					    sha1_to_hex(entries[i].sha1),
+					    p->pack_name, (uintmax_t)offset);
+		}
 		data = unpack_entry(p, entries[i].offset, &type, &size);
 		if (!data) {
 			err = error("cannot unpack %s from %s at offset %"PRIuMAX"",