@@ -22,6 +22,9 @@ use cargo_util::Sha256;
22
22
use crate :: CargoResult ;
23
23
use crate :: CARGO_ENV ;
24
24
25
+ /// The current format version of [`EncodedDepInfo`].
26
+ const CURRENT_ENCODED_DEP_INFO_VERSION : u8 = 1 ;
27
+
25
28
/// The representation of the `.d` dep-info file generated by rustc
26
29
#[ derive( Default ) ]
27
30
pub struct RustcDepInfo {
@@ -61,20 +64,35 @@ pub enum DepInfoPathType {
61
64
/// Currently the format looks like:
62
65
///
63
66
/// ```text
64
- /// +------------+------------+---------------+---------------+
65
- /// | # of files | file paths | # of env vars | env var pairs |
66
- /// +------------+------------+---------------+---------------+
67
+ /// +--------+---------+-------- ----+------------+---------------+---------------+
68
+ /// | marker | version | # of files | file paths | # of env vars | env var pairs |
69
+ /// +--------+---------+-------- ----+------------+---------------+---------------+
67
70
/// ```
68
71
///
69
72
/// Each field represents
70
73
///
74
+ /// * _Marker_ --- A magic marker to ensure older Cargoes that only recognize
75
+ /// format v0 (prior to checksum support in [`f4ca7390`]) not go further
76
+ /// parsing newer formats. Since [`EncodedDepInfo`] is just an optimization,
77
+ /// to avoid adding any complexity, Cargo recognizes only one version of
78
+ /// [`CURRENT_ENCODED_DEP_INFO_VERSION`].
79
+ /// The current layout looks like
80
+ /// ```text
81
+ /// +----------------------------+
82
+ /// | [0x01 0x00 0x00 0x00 0xff] |
83
+ /// +----------------------------+
84
+ /// ```
85
+ /// These bytes will be interpreted as "one file tracked and invalid
86
+ /// [`DepInfoPathType`] variant with 255" by older Cargoes, so they will just
87
+ /// stop parsing. This could prevent some bad parsing in rust-lang/cargo#14712.
88
+ /// * _Version_ --- The current format version.
71
89
/// * _Number of files/envs_ --- A `u32` representing the number of things.
72
90
/// * _File paths_ --- Zero or more paths of files the dep-info file depends on.
73
91
/// Each path is encoded as the following:
74
92
///
75
93
/// ```text
76
94
/// +-----------+-------------+------------+---------------+-----------+-------+
77
- /// | Path type | len of path | path bytes | cksum exists? | file size | cksum |
95
+ /// | path type | len of path | path bytes | cksum exists? | file size | cksum |
78
96
/// +-----------+-------------+------------+---------------+-----------+-------+
79
97
/// ```
80
98
/// * _Env var pairs_ --- Zero or more env vars the dep-info file depends on.
@@ -84,6 +102,8 @@ pub enum DepInfoPathType {
84
102
/// | len of key | key bytes | value exists? | len of value | value bytes |
85
103
/// +------------+-----------+---------------+--------------+-------------+
86
104
/// ```
105
+ ///
106
+ /// [`f4ca7390`]: https://github.com/rust-lang/cargo/commit/f4ca739073185ea5e1148ff100bb4a06d3bf721d
87
107
#[ derive( Default , Debug , PartialEq , Eq ) ]
88
108
pub struct EncodedDepInfo {
89
109
pub files : Vec < ( DepInfoPathType , PathBuf , Option < ( u64 , String ) > ) > ,
@@ -93,6 +113,12 @@ pub struct EncodedDepInfo {
93
113
impl EncodedDepInfo {
94
114
pub fn parse ( mut bytes : & [ u8 ] ) -> Option < EncodedDepInfo > {
95
115
let bytes = & mut bytes;
116
+ read_magic_marker ( bytes) ?;
117
+ let version = read_u8 ( bytes) ?;
118
+ if version != CURRENT_ENCODED_DEP_INFO_VERSION {
119
+ return None ;
120
+ }
121
+
96
122
let nfiles = read_usize ( bytes) ?;
97
123
let mut files = Vec :: with_capacity ( nfiles) ;
98
124
for _ in 0 ..nfiles {
@@ -129,6 +155,18 @@ impl EncodedDepInfo {
129
155
}
130
156
return Some ( EncodedDepInfo { files, env } ) ;
131
157
158
+ /// See [`EncodedDepInfo`] for why a magic marker exists.
159
+ fn read_magic_marker ( bytes : & mut & [ u8 ] ) -> Option < ( ) > {
160
+ let _size = read_usize ( bytes) ?;
161
+ let path_type = read_u8 ( bytes) ?;
162
+ if path_type != u8:: MAX {
163
+ // Old depinfo. Give up parsing it.
164
+ return None ;
165
+ } else {
166
+ Some ( ( ) )
167
+ }
168
+ }
169
+
132
170
fn read_usize ( bytes : & mut & [ u8 ] ) -> Option < usize > {
133
171
let ret = bytes. get ( ..4 ) ?;
134
172
* bytes = & bytes[ 4 ..] ;
@@ -162,6 +200,10 @@ impl EncodedDepInfo {
162
200
pub fn serialize ( & self ) -> CargoResult < Vec < u8 > > {
163
201
let mut ret = Vec :: new ( ) ;
164
202
let dst = & mut ret;
203
+
204
+ write_magic_marker ( dst) ;
205
+ dst. push ( CURRENT_ENCODED_DEP_INFO_VERSION ) ;
206
+
165
207
write_usize ( dst, self . files . len ( ) ) ;
166
208
for ( ty, file, checksum_info) in self . files . iter ( ) {
167
209
match ty {
@@ -189,6 +231,14 @@ impl EncodedDepInfo {
189
231
}
190
232
return Ok ( ret) ;
191
233
234
+ /// See [`EncodedDepInfo`] for why a magic marker exists.
235
+ ///
236
+ /// There is an assumption that there is always at least a file.
237
+ fn write_magic_marker ( dst : & mut Vec < u8 > ) {
238
+ write_usize ( dst, 1 ) ;
239
+ dst. push ( u8:: MAX ) ;
240
+ }
241
+
192
242
fn write_bytes ( dst : & mut Vec < u8 > , val : impl AsRef < [ u8 ] > ) {
193
243
let val = val. as_ref ( ) ;
194
244
write_usize ( dst, val. len ( ) ) ;
@@ -673,7 +723,7 @@ mod encoded_dep_info {
673
723
#[ rustfmt:: skip]
674
724
let data = [
675
725
0x01 , 0x00 , 0x00 , 0x00 , 0xff , // magic marker
676
- 0x01 , // version
726
+ CURRENT_ENCODED_DEP_INFO_VERSION , // version
677
727
0x01 , 0x00 , 0x00 , 0x00 , // # of files
678
728
0x00 , // path type
679
729
0x04 , 0x00 , 0x00 , 0x00 , // len of path
@@ -682,7 +732,13 @@ mod encoded_dep_info {
682
732
0x00 , 0x00 , 0x00 , 0x00 , // # of env vars
683
733
] ;
684
734
// The current cargo doesn't recognize the magic marker.
685
- assert ! ( EncodedDepInfo :: parse( & data) . is_none( ) ) ;
735
+ assert_eq ! (
736
+ EncodedDepInfo :: parse( & data) . unwrap( ) ,
737
+ EncodedDepInfo {
738
+ files: vec![ ( DepInfoPathType :: PackageRootRelative , "rust" . into( ) , None ) ] ,
739
+ env: Vec :: new( ) ,
740
+ }
741
+ ) ;
686
742
}
687
743
688
744
#[ test]
0 commit comments