1 #define USE_THE_REPOSITORY_VARIABLE
2 #define DISABLE_SIGN_COMPARE_WARNINGS
4 #include "git-compat-util.h"
5 #include "environment.h"
7 #include "repository.h"
11 #include "object-file.h"
12 #include "object-store-ll.h"
19 static int compare_entries(const void *e1
, const void *e2
)
21 const struct idx_entry
*entry1
= e1
;
22 const struct idx_entry
*entry2
= e2
;
23 if (entry1
->offset
< entry2
->offset
)
25 if (entry1
->offset
> entry2
->offset
)
30 int check_pack_crc(struct packed_git
*p
, struct pack_window
**w_curs
,
31 off_t offset
, off_t len
, unsigned int nr
)
33 const uint32_t *index_crc
;
34 uint32_t data_crc
= crc32(0, NULL
, 0);
38 void *data
= use_pack(p
, w_curs
, offset
, &avail
);
41 data_crc
= crc32(data_crc
, data
, avail
);
46 index_crc
= p
->index_data
;
47 index_crc
+= 2 + 256 + (size_t)p
->num_objects
* (the_hash_algo
->rawsz
/4) + nr
;
49 return data_crc
!= ntohl(*index_crc
);
52 static int verify_packfile(struct repository
*r
,
54 struct pack_window
**w_curs
,
56 struct progress
*progress
, uint32_t base_count
)
59 off_t index_size
= p
->index_size
;
60 const unsigned char *index_base
= p
->index_data
;
62 unsigned char hash
[GIT_MAX_RAWSZ
], *pack_sig
;
63 off_t offset
= 0, pack_sig_ofs
= 0;
64 uint32_t nr_objects
, i
;
66 struct idx_entry
*entries
;
68 if (!is_pack_valid(p
))
69 return error("packfile %s cannot be accessed", p
->pack_name
);
71 r
->hash_algo
->init_fn(&ctx
);
73 unsigned long remaining
;
74 unsigned char *in
= use_pack(p
, w_curs
, offset
, &remaining
);
77 pack_sig_ofs
= p
->pack_size
- r
->hash_algo
->rawsz
;
78 if (offset
> pack_sig_ofs
)
79 remaining
-= (unsigned int)(offset
- pack_sig_ofs
);
80 r
->hash_algo
->update_fn(&ctx
, in
, remaining
);
81 } while (offset
< pack_sig_ofs
);
82 r
->hash_algo
->final_fn(hash
, &ctx
);
83 pack_sig
= use_pack(p
, w_curs
, pack_sig_ofs
, NULL
);
84 if (!hasheq(hash
, pack_sig
, the_repository
->hash_algo
))
85 err
= error("%s pack checksum mismatch",
87 if (!hasheq(index_base
+ index_size
- r
->hash_algo
->hexsz
, pack_sig
,
88 the_repository
->hash_algo
))
89 err
= error("%s pack checksum does not match its index",
93 /* Make sure everything reachable from idx is valid. Since we
94 * have verified that nr_objects matches between idx and pack,
95 * we do not do scan-streaming check on the pack file.
97 nr_objects
= p
->num_objects
;
98 ALLOC_ARRAY(entries
, nr_objects
+ 1);
99 entries
[nr_objects
].offset
= pack_sig_ofs
;
100 /* first sort entries by pack offset, since unpacking them is more efficient that way */
101 for (i
= 0; i
< nr_objects
; i
++) {
102 entries
[i
].offset
= nth_packed_object_offset(p
, i
);
105 QSORT(entries
, nr_objects
, compare_entries
);
107 for (i
= 0; i
< nr_objects
; i
++) {
109 struct object_id oid
;
110 enum object_type type
;
115 if (nth_packed_object_id(&oid
, p
, entries
[i
].nr
) < 0)
116 BUG("unable to get oid of object %lu from %s",
117 (unsigned long)entries
[i
].nr
, p
->pack_name
);
119 if (p
->index_version
> 1) {
120 off_t offset
= entries
[i
].offset
;
121 off_t len
= entries
[i
+1].offset
- offset
;
122 unsigned int nr
= entries
[i
].nr
;
123 if (check_pack_crc(p
, w_curs
, offset
, len
, nr
))
124 err
= error("index CRC mismatch for object %s "
125 "from %s at offset %"PRIuMAX
"",
127 p
->pack_name
, (uintmax_t)offset
);
130 curpos
= entries
[i
].offset
;
131 type
= unpack_object_header(p
, w_curs
, &curpos
, &size
);
134 if (type
== OBJ_BLOB
&& big_file_threshold
<= size
) {
136 * Let stream_object_signature() check it with
137 * the streaming interface; no point slurping
138 * the data in-core only to discard.
143 data
= unpack_entry(r
, p
, entries
[i
].offset
, &type
, &size
);
147 if (data_valid
&& !data
)
148 err
= error("cannot unpack %s from %s at offset %"PRIuMAX
"",
149 oid_to_hex(&oid
), p
->pack_name
,
150 (uintmax_t)entries
[i
].offset
);
151 else if (data
&& check_object_signature(r
, &oid
, data
, size
,
153 err
= error("packed %s from %s is corrupt",
154 oid_to_hex(&oid
), p
->pack_name
);
155 else if (!data
&& stream_object_signature(r
, &oid
) < 0)
156 err
= error("packed %s from %s is corrupt",
157 oid_to_hex(&oid
), p
->pack_name
);
160 err
|= fn(&oid
, type
, size
, data
, &eaten
);
164 if (((base_count
+ i
) & 1023) == 0)
165 display_progress(progress
, base_count
+ i
);
169 display_progress(progress
, base_count
+ i
);
175 int verify_pack_index(struct packed_git
*p
)
179 if (open_pack_index(p
))
180 return error("packfile %s index not opened", p
->pack_name
);
182 /* Verify SHA1 sum of the index file */
183 if (!hashfile_checksum_valid(p
->index_data
, p
->index_size
))
184 err
= error("Packfile index for %s hash mismatch",
189 int verify_pack(struct repository
*r
, struct packed_git
*p
, verify_fn fn
,
190 struct progress
*progress
, uint32_t base_count
)
193 struct pack_window
*w_curs
= NULL
;
195 err
|= verify_pack_index(p
);
199 err
|= verify_packfile(r
, p
, &w_curs
, fn
, progress
, base_count
);