@@ -191,8 +191,59 @@ pub async fn unencapsulate(repo: &ostree::Repo, imgref: &OstreeImageReference) -
191191 importer. unencapsulate ( ) . await
192192}
193193
194+ trait Decompressable : Read + Send + ' static {
195+ fn get_inner_mut ( & mut self ) -> & mut ( dyn Read ) ;
196+ }
197+
198+ // TransparentDecompressor
199+
200+ struct TransparentDecompressor < R : Read + Send + ' static > ( R ) ;
201+
202+ impl < R : Read + Send + ' static > Read for TransparentDecompressor < R > {
203+ fn read ( & mut self , buf : & mut [ u8 ] ) -> std:: io:: Result < usize > {
204+ self . 0 . read ( buf)
205+ }
206+ }
207+
208+ impl < R : Read + Send + ' static > Decompressable for TransparentDecompressor < R > {
209+ fn get_inner_mut ( & mut self ) -> & mut ( dyn Read ) {
210+ & mut self . 0
211+ }
212+ }
213+
214+ // GzipDecompressor
215+
216+ struct GzipDecompressor < R : std:: io:: BufRead > ( flate2:: bufread:: GzDecoder < R > ) ;
217+
218+ impl < R : std:: io:: BufRead + Send + ' static > Read for GzipDecompressor < R > {
219+ fn read ( & mut self , buf : & mut [ u8 ] ) -> std:: io:: Result < usize > {
220+ self . 0 . read ( buf)
221+ }
222+ }
223+
224+ impl < R : std:: io:: BufRead + Send + ' static > Decompressable for GzipDecompressor < R > {
225+ fn get_inner_mut ( & mut self ) -> & mut ( dyn Read ) {
226+ self . 0 . get_mut ( )
227+ }
228+ }
229+
230+ // ZstdDecompressor
231+ struct ZstdDecompressor < ' a , R : std:: io:: BufRead > ( zstd:: stream:: read:: Decoder < ' a , R > ) ;
232+
233+ impl < ' a : ' static , R : std:: io:: BufRead + Send + ' static > Read for ZstdDecompressor < ' a , R > {
234+ fn read ( & mut self , buf : & mut [ u8 ] ) -> std:: io:: Result < usize > {
235+ self . 0 . read ( buf)
236+ }
237+ }
238+
239+ impl < ' a : ' static , R : std:: io:: BufRead + Send + ' static > Decompressable for ZstdDecompressor < ' a , R > {
240+ fn get_inner_mut ( & mut self ) -> & mut ( dyn Read ) {
241+ self . 0 . get_mut ( )
242+ }
243+ }
244+
194245pub ( crate ) struct Decompressor {
195- inner : Box < dyn Read + Send + ' static > ,
246+ inner : Box < dyn Decompressable > ,
196247 finished : bool ,
197248}
198249
@@ -224,15 +275,17 @@ impl Decompressor {
224275 media_type : & oci_image:: MediaType ,
225276 src : impl Read + Send + ' static ,
226277 ) -> Result < Self > {
227- let r: Box < dyn std :: io :: Read + Send + ' static > = match media_type {
278+ let r: Box < dyn Decompressable > = match media_type {
228279 oci_image:: MediaType :: ImageLayerZstd => {
229- Box :: new ( zstd:: stream:: read:: Decoder :: new ( src) ?)
280+ Box :: new ( ZstdDecompressor ( zstd:: stream:: read:: Decoder :: new ( src) ?) )
230281 }
231- oci_image:: MediaType :: ImageLayerGzip => Box :: new ( flate2 :: bufread :: GzDecoder :: new (
232- std:: io:: BufReader :: new ( src) ,
282+ oci_image:: MediaType :: ImageLayerGzip => Box :: new ( GzipDecompressor (
283+ flate2 :: bufread :: GzDecoder :: new ( std:: io:: BufReader :: new ( src) ) ,
233284 ) ) ,
234- oci_image:: MediaType :: ImageLayer => Box :: new ( src) ,
235- oci_image:: MediaType :: Other ( t) if t. as_str ( ) == DOCKER_TYPE_LAYER_TAR => Box :: new ( src) ,
285+ oci_image:: MediaType :: ImageLayer => Box :: new ( TransparentDecompressor ( src) ) ,
286+ oci_image:: MediaType :: Other ( t) if t. as_str ( ) == DOCKER_TYPE_LAYER_TAR => {
287+ Box :: new ( TransparentDecompressor ( src) )
288+ }
236289 o => anyhow:: bail!( "Unhandled layer type: {}" , o) ,
237290 } ;
238291 Ok ( Self {
@@ -264,7 +317,7 @@ impl Decompressor {
264317 // https://github.com/bootc-dev/bootc/issues/1204
265318
266319 let mut sink = std:: io:: sink ( ) ;
267- let n = std:: io:: copy ( & mut self . inner , & mut sink) ?;
320+ let n = std:: io:: copy ( self . inner . get_inner_mut ( ) , & mut sink) ?;
268321
269322 if n > 0 {
270323 tracing:: debug!( "Read extra {n} bytes at end of decompressor stream" ) ;
@@ -362,4 +415,18 @@ mod tests {
362415 let d = Decompressor :: new ( & oci_image:: MediaType :: ImageLayer , empty) . unwrap ( ) ;
363416 drop ( d)
364417 }
418+
419+ #[ test]
420+ fn test_drop_decompressor_with_incomplete_gzip_data ( ) {
421+ let empty = std:: io:: empty ( ) ;
422+ let d = Decompressor :: new ( & oci_image:: MediaType :: ImageLayerGzip , empty) . unwrap ( ) ;
423+ drop ( d)
424+ }
425+
426+ #[ test]
427+ fn test_drop_decompressor_with_incomplete_zstd_data ( ) {
428+ let empty = std:: io:: empty ( ) ;
429+ let d = Decompressor :: new ( & oci_image:: MediaType :: ImageLayerZstd , empty) . unwrap ( ) ;
430+ drop ( d)
431+ }
365432}
0 commit comments