3
3
#include "pack.h"
4
4
#include "packfile.h"
5
5
#include "midx.h"
6
+ #include "object-store.h"
6
7
7
8
#define MIDX_SIGNATURE 0x4d494458 /* "MIDX" */
8
9
#define MIDX_CHUNKID_PACKLOOKUP 0x504c4f4f /* "PLOO" */
@@ -134,17 +135,19 @@ static struct midxed_git *load_midxed_git_one(const char *midx_file, const char
134
135
135
136
hdr = midx_map ;
136
137
if (ntohl (hdr -> midx_signature ) != MIDX_SIGNATURE ) {
138
+ uint32_t signature = ntohl (hdr -> midx_signature );
137
139
munmap (midx_map , midx_size );
138
140
close (fd );
139
141
die ("midx signature %X does not match signature %X" ,
140
- ntohl ( hdr -> midx_signature ) , MIDX_SIGNATURE );
142
+ signature , MIDX_SIGNATURE );
141
143
}
142
144
143
145
if (ntohl (hdr -> midx_version ) != MIDX_VERSION ) {
146
+ uint32_t version = ntohl (hdr -> midx_version );
144
147
munmap (midx_map , midx_size );
145
148
close (fd );
146
149
die ("midx version %X does not match version %X" ,
147
- ntohl ( hdr -> midx_version ) , MIDX_VERSION );
150
+ version , MIDX_VERSION );
148
151
}
149
152
150
153
/* Time to fill a midx struct */
@@ -193,16 +196,19 @@ static struct midxed_git *load_midxed_git_one(const char *midx_file, const char
193
196
midx -> chunk_large_offsets = data + chunk_offset ;
194
197
break ;
195
198
196
- case 0 :
197
- break ;
198
-
199
199
default :
200
- munmap (midx_map , midx_size );
201
- close (fd );
202
- die ("Unrecognized MIDX chunk id: %08x" , chunk_id );
200
+ /* We allow optional MIDX chunks, so ignore unrecognized chunk ids */
201
+ break ;
203
202
}
204
203
}
205
204
205
+ if (!midx -> chunk_oid_fanout )
206
+ die ("midx missing OID Fanout chunk" );
207
+ if (!midx -> chunk_pack_lookup )
208
+ die ("midx missing Packfile Name Lookup chunk" );
209
+ if (!midx -> chunk_pack_names )
210
+ die ("midx missing Packfile Name chunk" );
211
+
206
212
midx -> num_objects = ntohl (* ((uint32_t * )(midx -> chunk_oid_fanout + 255 * 4 )));
207
213
midx -> num_packs = ntohl (midx -> hdr -> num_packs );
208
214
@@ -215,6 +221,10 @@ static struct midxed_git *load_midxed_git_one(const char *midx_file, const char
215
221
216
222
for (i = 0 ; i < midx -> num_packs ; i ++ ) {
217
223
uint32_t name_offset = ntohl (* (uint32_t * )(midx -> chunk_pack_lookup + 4 * i ));
224
+
225
+ if (midx -> chunk_pack_names + name_offset >= midx -> data + midx -> data_len )
226
+ die ("invalid packfile name lookup" );
227
+
218
228
midx -> pack_names [i ] = (const char * )(midx -> chunk_pack_names + name_offset );
219
229
}
220
230
}
@@ -862,7 +872,8 @@ const char *write_midx_file(const char *pack_dir,
862
872
break ;
863
873
864
874
default :
865
- die ("unrecognized MIDX chunk id: %08x" , chunk_ids [chunk ]);
875
+ BUG ("midx tried to write an invalid chunk ID %08X" , chunk_ids [chunk ]);
876
+ break ;
866
877
}
867
878
}
868
879
@@ -928,3 +939,146 @@ void close_all_midx(void)
928
939
929
940
midxed_git = 0 ;
930
941
}
942
+
943
+ static int verify_midx_error = 0 ;
944
+
945
+ static void midx_report (const char * fmt , ...)
946
+ {
947
+ va_list ap ;
948
+ struct strbuf sb = STRBUF_INIT ;
949
+ verify_midx_error = 1 ;
950
+
951
+ va_start (ap , fmt );
952
+ strbuf_vaddf (& sb , fmt , ap );
953
+
954
+ fprintf (stderr , "%s\n" , sb .buf );
955
+ strbuf_release (& sb );
956
+ va_end (ap );
957
+ }
958
+
959
+ int midx_verify (const char * pack_dir , const char * midx_id )
960
+ {
961
+ uint32_t i , cur_fanout_pos = 0 ;
962
+ struct midxed_git * m ;
963
+ const char * midx_head_path ;
964
+ struct object_id cur_oid , prev_oid , checksum ;
965
+ struct hashfile * f ;
966
+ int devnull , checksum_fail = 0 ;
967
+
968
+ if (midx_id ) {
969
+ size_t sz ;
970
+ struct strbuf sb = STRBUF_INIT ;
971
+ strbuf_addf (& sb , "%s/midx-%s.midx" , pack_dir , midx_id );
972
+ midx_head_path = strbuf_detach (& sb , & sz );
973
+ } else {
974
+ midx_head_path = get_midx_head_filename_dir (pack_dir );
975
+ }
976
+
977
+ m = load_midxed_git_one (midx_head_path , pack_dir );
978
+
979
+ if (!m ) {
980
+ midx_report ("failed to find specified midx file" );
981
+ goto cleanup ;
982
+ }
983
+
984
+
985
+ devnull = open ("/dev/null" , O_WRONLY );
986
+ f = hashfd (devnull , NULL );
987
+ hashwrite (f , m -> data , m -> data_len - m -> hdr -> hash_len );
988
+ finalize_hashfile (f , checksum .hash , CSUM_CLOSE );
989
+ if (hashcmp (checksum .hash , m -> data + m -> data_len - m -> hdr -> hash_len )) {
990
+ midx_report (_ ("the midx file has incorrect checksum and is likely corrupt" ));
991
+ verify_midx_error = 0 ;
992
+ checksum_fail = 1 ;
993
+ }
994
+
995
+ if (m -> hdr -> hash_version != MIDX_OID_VERSION )
996
+ midx_report ("invalid hash version" );
997
+ if (m -> hdr -> hash_len != MIDX_OID_LEN )
998
+ midx_report ("invalid hash length" );
999
+
1000
+ if (verify_midx_error )
1001
+ goto cleanup ;
1002
+
1003
+ if (!m -> chunk_oid_lookup )
1004
+ midx_report ("missing OID Lookup chunk" );
1005
+ if (!m -> chunk_object_offsets )
1006
+ midx_report ("missing Object Offset chunk" );
1007
+
1008
+ if (verify_midx_error )
1009
+ goto cleanup ;
1010
+
1011
+ for (i = 0 ; i < m -> num_packs ; i ++ ) {
1012
+ if (prepare_midx_pack (m , i )) {
1013
+ midx_report ("failed to prepare pack %s" ,
1014
+ m -> pack_names [i ]);
1015
+ continue ;
1016
+ }
1017
+
1018
+ if (!m -> packs [i ]-> index_data &&
1019
+ open_pack_index (m -> packs [i ]))
1020
+ midx_report ("failed to open index for pack %s" ,
1021
+ m -> pack_names [i ]);
1022
+ }
1023
+
1024
+ if (verify_midx_error )
1025
+ goto cleanup ;
1026
+
1027
+ for (i = 0 ; i < m -> num_objects ; i ++ ) {
1028
+ struct pack_midx_details details ;
1029
+ uint32_t index_pos , pack_id ;
1030
+ struct packed_git * p ;
1031
+ off_t pack_offset ;
1032
+
1033
+ hashcpy (cur_oid .hash , m -> chunk_oid_lookup + m -> hdr -> hash_len * i );
1034
+
1035
+ while (cur_oid .hash [0 ] > cur_fanout_pos ) {
1036
+ uint32_t fanout_value = get_be32 (m -> chunk_oid_fanout + cur_fanout_pos * sizeof (uint32_t ));
1037
+ if (i != fanout_value )
1038
+ midx_report ("midx has incorrect fanout value: fanout[%d] = %u != %u" ,
1039
+ cur_fanout_pos , fanout_value , i );
1040
+
1041
+ cur_fanout_pos ++ ;
1042
+ }
1043
+
1044
+ if (i && oidcmp (& prev_oid , & cur_oid ) >= 0 )
1045
+ midx_report ("midx has incorrect OID order: %s then %s" ,
1046
+ oid_to_hex (& prev_oid ),
1047
+ oid_to_hex (& cur_oid ));
1048
+
1049
+ oidcpy (& prev_oid , & cur_oid );
1050
+
1051
+ if (!nth_midxed_object_details (m , i , & details )) {
1052
+ midx_report ("nth_midxed_object_details failed with n=%d" , i );
1053
+ continue ;
1054
+ }
1055
+
1056
+ pack_id = details .pack_int_id ;
1057
+ if (pack_id >= m -> num_packs ) {
1058
+ midx_report ("pack-int-id for object n=%d is invalid: %u" ,
1059
+ pack_id );
1060
+ continue ;
1061
+ }
1062
+
1063
+ p = m -> packs [pack_id ];
1064
+
1065
+ if (!find_pack_entry_pos (cur_oid .hash , p , & index_pos )) {
1066
+ midx_report ("midx contains object not present in packfile: %s" ,
1067
+ oid_to_hex (& cur_oid ));
1068
+ continue ;
1069
+ }
1070
+
1071
+ pack_offset = nth_packed_object_offset (p , index_pos );
1072
+ if (details .offset != pack_offset )
1073
+ midx_report ("midx has incorrect offset for %s : %" PRIx64 " != %" PRIx64 ,
1074
+ oid_to_hex (& cur_oid ),
1075
+ details .offset ,
1076
+ pack_offset );
1077
+ }
1078
+
1079
+ cleanup :
1080
+ if (m )
1081
+ close_midx (m );
1082
+ free (m );
1083
+ return verify_midx_error | checksum_fail ;
1084
+ }
0 commit comments