6
6
use std:: io:: { BufReader , Read , Write } ;
7
7
8
8
use anyhow:: { bail, Result } ;
9
- use sha2:: { Digest , Sha256 } ;
10
- use zstd:: stream:: { read:: Decoder , write :: Encoder } ;
9
+ use sha2:: Sha256 ;
10
+ use zstd:: stream:: read:: Decoder ;
11
11
12
12
use crate :: {
13
13
fsverity:: { FsVerityHashValue , Sha256HashValue } ,
14
14
repository:: Repository ,
15
15
util:: read_exactish,
16
+ zstd_encoder:: ZstdWriter ,
16
17
} ;
17
18
18
19
#[ derive( Debug ) ]
@@ -60,9 +61,8 @@ impl DigestMap {
60
61
61
62
pub struct SplitStreamWriter < ' a > {
62
63
repo : & ' a Repository ,
63
- inline_content : Vec < u8 > ,
64
- writer : Encoder < ' a , Vec < u8 > > ,
65
- pub sha256 : Option < ( Sha256 , Sha256HashValue ) > ,
64
+ pub ( crate ) inline_content : Vec < u8 > ,
65
+ writer : ZstdWriter ,
66
66
}
67
67
68
68
impl std:: fmt:: Debug for SplitStreamWriter < ' _ > {
@@ -71,7 +71,6 @@ impl std::fmt::Debug for SplitStreamWriter<'_> {
71
71
f. debug_struct ( "SplitStreamWriter" )
72
72
. field ( "repo" , & self . repo )
73
73
. field ( "inline_content" , & self . inline_content )
74
- . field ( "sha256" , & self . sha256 )
75
74
. finish ( )
76
75
}
77
76
}
@@ -82,85 +81,46 @@ impl SplitStreamWriter<'_> {
82
81
refs : Option < DigestMap > ,
83
82
sha256 : Option < Sha256HashValue > ,
84
83
) -> SplitStreamWriter {
85
- // SAFETY: we surely can't get an error writing the header to a Vec<u8>
86
- let mut writer = Encoder :: new ( vec ! [ ] , 0 ) . unwrap ( ) ;
87
-
88
- match refs {
89
- Some ( DigestMap { map } ) => {
90
- writer. write_all ( & ( map. len ( ) as u64 ) . to_le_bytes ( ) ) . unwrap ( ) ;
91
- for ref entry in map {
92
- writer. write_all ( & entry. body ) . unwrap ( ) ;
93
- writer. write_all ( & entry. verity ) . unwrap ( ) ;
94
- }
95
- }
96
- None => {
97
- writer. write_all ( & 0u64 . to_le_bytes ( ) ) . unwrap ( ) ;
98
- }
99
- }
100
-
101
84
SplitStreamWriter {
102
85
repo,
103
86
inline_content : vec ! [ ] ,
104
- writer,
105
- sha256 : sha256. map ( |x| ( Sha256 :: new ( ) , x) ) ,
87
+ writer : ZstdWriter :: new ( sha256, refs) ,
106
88
}
107
89
}
108
90
109
- fn write_fragment ( writer : & mut impl Write , size : usize , data : & [ u8 ] ) -> Result < ( ) > {
110
- writer. write_all ( & ( size as u64 ) . to_le_bytes ( ) ) ?;
111
- Ok ( writer. write_all ( data) ?)
91
+ pub fn get_sha_builder ( & self ) -> & Option < ( Sha256 , Sha256HashValue ) > {
92
+ & self . writer . sha256_builder
112
93
}
113
94
114
95
/// flush any buffered inline data, taking new_value as the new value of the buffer
115
96
fn flush_inline ( & mut self , new_value : Vec < u8 > ) -> Result < ( ) > {
116
- if !self . inline_content . is_empty ( ) {
117
- SplitStreamWriter :: write_fragment (
118
- & mut self . writer ,
119
- self . inline_content . len ( ) ,
120
- & self . inline_content ,
121
- ) ?;
122
- self . inline_content = new_value;
123
- }
97
+ self . writer . flush_inline ( & self . inline_content ) ?;
98
+ self . inline_content = new_value;
124
99
Ok ( ( ) )
125
100
}
126
101
127
102
/// really, "add inline content to the buffer"
128
103
/// you need to call .flush_inline() later
129
104
pub fn write_inline ( & mut self , data : & [ u8 ] ) {
130
- if let Some ( ( ref mut sha256, ..) ) = self . sha256 {
131
- sha256. update ( data) ;
132
- }
105
+ self . writer . update_sha ( data) ;
133
106
self . inline_content . extend ( data) ;
134
107
}
135
108
136
- /// write a reference to external data to the stream. If the external data had padding in the
137
- /// stream which is not stored in the object then pass it here as well and it will be stored
138
- /// inline after the reference.
139
- fn write_reference ( & mut self , reference : Sha256HashValue , padding : Vec < u8 > ) -> Result < ( ) > {
140
- // Flush the inline data before we store the external reference. Any padding from the
141
- // external data becomes the start of a new inline block.
142
- self . flush_inline ( padding) ?;
109
+ pub fn write_external ( & mut self , data : & [ u8 ] , padding : Vec < u8 > ) -> Result < ( ) > {
110
+ let id = self . repo . ensure_object ( & data) ?;
143
111
144
- SplitStreamWriter :: write_fragment ( & mut self . writer , 0 , & reference)
145
- }
112
+ self . writer . update_sha ( data) ;
113
+ self . writer . update_sha ( & padding) ;
114
+ self . writer . flush_inline ( & padding) ?;
146
115
147
- pub fn write_external ( & mut self , data : & [ u8 ] , padding : Vec < u8 > ) -> Result < ( ) > {
148
- if let Some ( ( ref mut sha256, ..) ) = self . sha256 {
149
- sha256. update ( data) ;
150
- sha256. update ( & padding) ;
151
- }
152
- let id = self . repo . ensure_object ( data) ?;
153
- self . write_reference ( id, padding)
116
+ self . writer . write_fragment ( 0 , & id) ?;
117
+ Ok ( ( ) )
154
118
}
155
119
156
120
pub fn done ( mut self ) -> Result < Sha256HashValue > {
157
121
self . flush_inline ( vec ! [ ] ) ?;
158
122
159
- if let Some ( ( context, expected) ) = self . sha256 {
160
- if Into :: < Sha256HashValue > :: into ( context. finalize ( ) ) != expected {
161
- bail ! ( "Content doesn't have expected SHA256 hash value!" ) ;
162
- }
163
- }
123
+ self . writer . finalize_sha256_builder ( ) ?;
164
124
165
125
self . repo . ensure_object ( & self . writer . finish ( ) ?)
166
126
}
0 commit comments