11//! Contains types that abstract over the various archive formats.
22
33use crate :: TmcError ;
4+ use blake3:: { Hash , Hasher } ;
45use serde:: Deserialize ;
56use std:: {
67 fmt:: Display ,
78 io:: { BufReader , Cursor , Read , Seek , Write } ,
89 ops:: ControlFlow :: { self , Break } ,
10+ os:: unix:: ffi:: OsStrExt ,
911 path:: { Path , PathBuf } ,
1012 str:: FromStr ,
1113} ;
@@ -92,9 +94,9 @@ impl<T: Read + Seek> Archive<T> {
9294 return Ok ( Entry :: Tar ( entry) ) ;
9395 }
9496 }
95- Err ( TmcError :: TarRead ( std:: io:: Error :: other (
96- format ! ( "Could not find {path} in tar" ) ,
97- ) ) )
97+ Err ( TmcError :: TarRead ( std:: io:: Error :: other ( format ! (
98+ "Could not find {path} in tar"
99+ ) ) ) )
98100 }
99101 Self ( ArchiveInner :: TarZstd ( archive) ) => {
100102 for entry in archive. entries ( ) . map_err ( TmcError :: TarRead ) ? {
@@ -103,9 +105,9 @@ impl<T: Read + Seek> Archive<T> {
103105 return Ok ( Entry :: TarZstd ( entry) ) ;
104106 }
105107 }
106- Err ( TmcError :: TarRead ( std:: io:: Error :: other (
107- format ! ( "Could not find {path} in tar" ) ,
108- ) ) )
108+ Err ( TmcError :: TarRead ( std:: io:: Error :: other ( format ! (
109+ "Could not find {path} in tar"
110+ ) ) ) )
109111 }
110112 Self ( ArchiveInner :: Zip ( archive) ) => {
111113 archive. by_name ( path) . map ( Entry :: Zip ) . map_err ( Into :: into)
@@ -292,17 +294,23 @@ pub enum Compression {
292294}
293295
294296impl Compression {
295- pub fn compress ( self , path : & Path ) -> Result < Vec < u8 > , TmcError > {
297+ pub fn compress ( self , path : & Path , hash : bool ) -> Result < ( Vec < u8 > , Option < Hash > ) , TmcError > {
298+ let mut hasher = if hash { Some ( Hasher :: new ( ) ) } else { None } ;
296299 let buf = match self {
297300 Self :: Tar => {
298301 let buf = Cursor :: new ( Vec :: new ( ) ) ;
299302 let mut builder = tar:: Builder :: new ( buf) ;
300303 walk_dir_for_compression ( path, |entry, relative_path| {
301304 if entry. path ( ) . is_dir ( ) {
305+ hasher. as_mut ( ) . map ( |h| h. update ( relative_path. as_bytes ( ) ) ) ;
302306 builder
303307 . append_dir ( relative_path, entry. path ( ) )
304308 . map_err ( TmcError :: TarWrite ) ?;
305309 } else if entry. path ( ) . is_file ( ) {
310+ if let Some ( h) = & mut hasher {
311+ let file = file_util:: read_file ( entry. path ( ) ) ?;
312+ h. update ( & file) ;
313+ }
306314 builder
307315 . append_path_with_name ( entry. path ( ) , relative_path)
308316 . map_err ( TmcError :: TarWrite ) ?;
@@ -319,10 +327,12 @@ impl Compression {
319327 let mut writer = zip:: ZipWriter :: new ( buf) ;
320328 walk_dir_for_compression ( path, |entry, relative_path| {
321329 if entry. path ( ) . is_dir ( ) {
330+ hasher. as_mut ( ) . map ( |h| h. update ( relative_path. as_bytes ( ) ) ) ;
322331 writer. add_directory ( relative_path, SimpleFileOptions :: default ( ) ) ?;
323332 } else if entry. path ( ) . is_file ( ) {
324- writer. start_file ( relative_path, SimpleFileOptions :: default ( ) ) ?;
325333 let contents = file_util:: read_file ( entry. path ( ) ) ?;
334+ hasher. as_mut ( ) . map ( |h| h. update ( & contents) ) ;
335+ writer. start_file ( relative_path, SimpleFileOptions :: default ( ) ) ?;
326336 writer
327337 . write_all ( & contents)
328338 . map_err ( |err| TmcError :: ZipWrite ( path. to_path_buf ( ) , err) ) ?;
@@ -336,10 +346,15 @@ impl Compression {
336346 let mut builder = tar:: Builder :: new ( tar_buf) ;
337347 walk_dir_for_compression ( path, |entry, relative_path| {
338348 if entry. path ( ) . is_dir ( ) {
349+ hasher. as_mut ( ) . map ( |h| h. update ( relative_path. as_bytes ( ) ) ) ;
339350 builder
340351 . append_dir ( relative_path, entry. path ( ) )
341352 . map_err ( TmcError :: TarWrite ) ?;
342353 } else if entry. path ( ) . is_file ( ) {
354+ if let Some ( h) = & mut hasher {
355+ let file = file_util:: read_file ( entry. path ( ) ) ?;
356+ h. update ( & file) ;
357+ }
343358 builder
344359 . append_path_with_name ( entry. path ( ) , relative_path)
345360 . map_err ( TmcError :: TarWrite ) ?;
@@ -350,7 +365,8 @@ impl Compression {
350365 zstd:: stream:: encode_all ( tar_buf. as_slice ( ) , 0 ) . map_err ( TmcError :: ZstdWrite ) ?
351366 }
352367 } ;
353- Ok ( buf)
368+ let hash = hasher. map ( |h| h. finalize ( ) ) ;
369+ Ok ( ( buf, hash) )
354370 }
355371}
356372
0 commit comments