@@ -78,6 +78,9 @@ pub enum ManifestValidationError {
78
78
manifest_version : StateSyncVersion ,
79
79
max_supported_version : StateSyncVersion ,
80
80
} ,
81
+ InconsistentManifest {
82
+ reason : String ,
83
+ } ,
81
84
}
82
85
83
86
impl fmt:: Display for ManifestValidationError {
@@ -111,6 +114,7 @@ impl fmt::Display for ManifestValidationError {
111
114
"manifest version {} not supported, maximum supported version {}" ,
112
115
manifest_version, max_supported_version,
113
116
) ,
117
+ Self :: InconsistentManifest { reason } => write ! ( f, "inconsistent manifest: {}" , reason) ,
114
118
}
115
119
}
116
120
}
@@ -912,6 +916,16 @@ pub fn compute_manifest(
912
916
) ;
913
917
metrics. chunk_id_usage_nearing_limits_critical . inc ( ) ;
914
918
}
919
+
920
+ // Sanity check: ensure that we have produced a valid manifest.
921
+ debug_assert_eq ! (
922
+ Ok ( ( ) ) ,
923
+ validate_manifest(
924
+ & manifest,
925
+ & CryptoHash ( manifest_hash( & manifest) . to_vec( ) ) . into( )
926
+ )
927
+ ) ;
928
+
915
929
Ok ( manifest)
916
930
}
917
931
@@ -931,6 +945,12 @@ pub fn validate_manifest(
931
945
let mut chunk_start: usize = 0 ;
932
946
933
947
for ( file_index, f) in manifest. file_table . iter ( ) . enumerate ( ) {
948
+ if f. relative_path . is_absolute ( ) {
949
+ return Err ( ManifestValidationError :: InconsistentManifest {
950
+ reason : format ! ( "absolute file path: {}," , f. relative_path. display( ) , ) ,
951
+ } ) ;
952
+ }
953
+
934
954
let mut hasher = file_hasher ( ) ;
935
955
936
956
let chunk_count: usize = manifest. chunk_table [ chunk_start..]
@@ -940,10 +960,34 @@ pub fn validate_manifest(
940
960
941
961
( chunk_count as u32 ) . update_hash ( & mut hasher) ;
942
962
943
- for chunk_info in manifest. chunk_table [ chunk_start..chunk_start + chunk_count] . iter ( ) {
963
+ let mut file_offset = 0 ;
964
+ for i in chunk_start..chunk_start + chunk_count {
965
+ let chunk_info = manifest. chunk_table . get ( i) . unwrap ( ) ;
944
966
assert_eq ! ( chunk_info. file_index, file_index as u32 ) ;
967
+ if chunk_info. offset != file_offset {
968
+ return Err ( ManifestValidationError :: InconsistentManifest {
969
+ reason : format ! (
970
+ "unexpected offset for chunk {} of file {}: was {}, expected {}" ,
971
+ i,
972
+ f. relative_path. display( ) ,
973
+ chunk_info. offset,
974
+ file_offset
975
+ ) ,
976
+ } ) ;
977
+ }
978
+ file_offset += chunk_info. size_bytes as u64 ;
945
979
write_chunk_hash ( & mut hasher, chunk_info, manifest. version ) ;
946
980
}
981
+ if f. size_bytes != file_offset {
982
+ return Err ( ManifestValidationError :: InconsistentManifest {
983
+ reason : format ! (
984
+ "mismatching file size and total chunk size for {}: {} vs {}" ,
985
+ f. relative_path. display( ) ,
986
+ f. size_bytes,
987
+ file_offset
988
+ ) ,
989
+ } ) ;
990
+ }
947
991
948
992
chunk_start += chunk_count;
949
993
@@ -957,6 +1001,15 @@ pub fn validate_manifest(
957
1001
} ) ;
958
1002
}
959
1003
}
1004
+ if manifest. chunk_table . len ( ) != chunk_start {
1005
+ return Err ( ManifestValidationError :: InconsistentManifest {
1006
+ reason : format ! (
1007
+ "extra chunks in manifest: actual {}, expected {}" ,
1008
+ manifest. chunk_table. len( ) ,
1009
+ chunk_start
1010
+ ) ,
1011
+ } ) ;
1012
+ }
960
1013
961
1014
let hash = manifest_hash ( manifest) ;
962
1015
0 commit comments