1#include "cache.h"
2#include "pack.h"
3
4#define BATCH (1u<<20)
5
6static int verify_packfile(struct packed_git *p)
7{
8 unsigned long index_size = p->index_size;
9 void *index_base = p->index_base;
10 SHA_CTX ctx;
11 unsigned char sha1[20];
12 struct pack_header *hdr;
13 int nr_objects, err, i;
14 unsigned char *packdata;
15 unsigned long datasize;
16
17 /* Header consistency check */
18 hdr = p->pack_base;
19 if (hdr->hdr_signature != htonl(PACK_SIGNATURE))
20 return error("Packfile %s signature mismatch", p->pack_name);
21 if (!pack_version_ok(hdr->hdr_version))
22 return error("Packfile version %d unsupported",
23 ntohl(hdr->hdr_version));
24 nr_objects = ntohl(hdr->hdr_entries);
25 if (num_packed_objects(p) != nr_objects)
26 return error("Packfile claims to have %d objects, "
27 "while idx size expects %d", nr_objects,
28 num_packed_objects(p));
29
30 /* Check integrity of pack data with its SHA-1 checksum */
31 SHA1_Init(&ctx);
32 packdata = p->pack_base;
33 datasize = p->pack_size - 20;
34 while (datasize) {
35 unsigned long batch = (datasize < BATCH) ? datasize : BATCH;
36 SHA1_Update(&ctx, packdata, batch);
37 datasize -= batch;
38 packdata += batch;
39 }
40 SHA1_Final(sha1, &ctx);
41
42 if (hashcmp(sha1, (unsigned char *)(p->pack_base) + p->pack_size - 20))
43 return error("Packfile %s SHA1 mismatch with itself",
44 p->pack_name);
45 if (hashcmp(sha1, (unsigned char *)index_base + index_size - 40))
46 return error("Packfile %s SHA1 mismatch with idx",
47 p->pack_name);
48
49 /* Make sure everything reachable from idx is valid. Since we
50 * have verified that nr_objects matches between idx and pack,
51 * we do not do scan-streaming check on the pack file.
52 */
53 for (i = err = 0; i < nr_objects; i++) {
54 unsigned char sha1[20];
55 void *data;
56 char type[20];
57 unsigned long size, offset;
58
59 if (nth_packed_object_sha1(p, i, sha1))
60 die("internal error pack-check nth-packed-object");
61 offset = find_pack_entry_one(sha1, p);
62 if (!offset)
63 die("internal error pack-check find-pack-entry-one");
64 data = unpack_entry_gently(p, offset, type, &size);
65 if (!data) {
66 err = error("cannot unpack %s from %s",
67 sha1_to_hex(sha1), p->pack_name);
68 continue;
69 }
70 if (check_sha1_signature(sha1, data, size, type)) {
71 err = error("packed %s from %s is corrupt",
72 sha1_to_hex(sha1), p->pack_name);
73 free(data);
74 continue;
75 }
76 free(data);
77 }
78
79 return err;
80}
81
82
83#define MAX_CHAIN 40
84
85static void show_pack_info(struct packed_git *p)
86{
87 struct pack_header *hdr;
88 int nr_objects, i;
89 unsigned int chain_histogram[MAX_CHAIN];
90
91 hdr = p->pack_base;
92 nr_objects = ntohl(hdr->hdr_entries);
93 memset(chain_histogram, 0, sizeof(chain_histogram));
94
95 for (i = 0; i < nr_objects; i++) {
96 unsigned char sha1[20], base_sha1[20];
97 char type[20];
98 unsigned long size;
99 unsigned long store_size;
100 unsigned long offset;
101 unsigned int delta_chain_length;
102
103 if (nth_packed_object_sha1(p, i, sha1))
104 die("internal error pack-check nth-packed-object");
105 offset = find_pack_entry_one(sha1, p);
106 if (!offset)
107 die("internal error pack-check find-pack-entry-one");
108
109 packed_object_info_detail(p, offset, type, &size, &store_size,
110 &delta_chain_length,
111 base_sha1);
112 printf("%s ", sha1_to_hex(sha1));
113 if (!delta_chain_length)
114 printf("%-6s %lu %lu\n", type, size, offset);
115 else {
116 printf("%-6s %lu %lu %u %s\n", type, size, offset,
117 delta_chain_length, sha1_to_hex(base_sha1));
118 if (delta_chain_length < MAX_CHAIN)
119 chain_histogram[delta_chain_length]++;
120 else
121 chain_histogram[0]++;
122 }
123 }
124
125 for (i = 0; i < MAX_CHAIN; i++) {
126 if (!chain_histogram[i])
127 continue;
128 printf("chain length %s %d: %d object%s\n",
129 i ? "=" : ">=",
130 i ? i : MAX_CHAIN,
131 chain_histogram[i],
132 1 < chain_histogram[i] ? "s" : "");
133 }
134}
135
136int verify_pack(struct packed_git *p, int verbose)
137{
138 unsigned long index_size = p->index_size;
139 void *index_base = p->index_base;
140 SHA_CTX ctx;
141 unsigned char sha1[20];
142 int ret;
143
144 ret = 0;
145 /* Verify SHA1 sum of the index file */
146 SHA1_Init(&ctx);
147 SHA1_Update(&ctx, index_base, index_size - 20);
148 SHA1_Final(sha1, &ctx);
149 if (hashcmp(sha1, (unsigned char *)index_base + index_size - 20))
150 ret = error("Packfile index for %s SHA1 mismatch",
151 p->pack_name);
152
153 if (!ret) {
154 /* Verify pack file */
155 use_packed_git(p);
156 ret = verify_packfile(p);
157 unuse_packed_git(p);
158 }
159
160 if (verbose) {
161 if (ret)
162 printf("%s: bad\n", p->pack_name);
163 else {
164 use_packed_git(p);
165 show_pack_info(p);
166 unuse_packed_git(p);
167 printf("%s: ok\n", p->pack_name);
168 }
169 }
170
171 return ret;
172}