11use std:: collections:: { HashMap , HashSet } ;
22use std:: ffi:: OsString ;
3+ use std:: fmt;
34use std:: io:: Read ;
45use std:: path:: { Path , PathBuf } ;
56
@@ -18,9 +19,20 @@ struct Config {
1819 log_level : LevelFilter ,
1920}
2021
22+ struct AssetWriteError {
23+ error : io:: Error ,
24+ path : String ,
25+ }
26+
27+ impl fmt:: Display for AssetWriteError {
28+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
29+ write ! ( f, "{:?}: {}" , self . path, self . error)
30+ }
31+ }
32+
2133type AssetMap = HashMap < PathBuf , Vec < u8 > > ;
2234type FolderSet = HashSet < OsString > ;
23- type ExtractTask = Vec < JoinHandle < Result < ( ) , io :: Error > > > ;
35+ type ExtractTask = Vec < JoinHandle < Result < ( ) , AssetWriteError > > > ;
2436
2537fn parse_arguments ( ) -> Config {
2638 let mut verbose = 0 ;
@@ -102,11 +114,9 @@ fn read_destination_path_and_write<R: Read>(
102114
103115 let asset_path = path. parent ( ) . unwrap ( ) . join ( "asset" ) ;
104116 if let Some ( asset_data) = assets. remove ( & asset_path) {
105- tasks. push ( tokio:: spawn ( write_asset_to_pathname (
106- asset_data,
107- path. to_string_lossy ( ) . to_string ( ) ,
108- path_name,
109- ) ) ) ;
117+ tasks. push ( tokio:: spawn ( async move {
118+ write_asset_to_pathname ( asset_data, path. to_string_lossy ( ) . to_string ( ) , path_name) . await
119+ } ) ) ;
110120 } else {
111121 let path_string = path. into_os_string ( ) ;
112122 if folders. contains ( & path_string) {
@@ -120,8 +130,12 @@ async fn write_asset_to_pathname(
120130 asset_data : Vec < u8 > ,
121131 entry_hash : String ,
122132 path_name : String ,
123- ) -> Result < ( ) , io:: Error > {
124- let target_path = sanitize_path:: sanitize_path ( & path_name) ?;
133+ ) -> Result < ( ) , AssetWriteError > {
134+ let to_asset_error = |error : io:: Error | AssetWriteError {
135+ error,
136+ path : path_name. clone ( ) ,
137+ } ;
138+ let target_path = sanitize_path:: sanitize_path ( & path_name) . map_err ( to_asset_error) ?;
125139 let asset_hash: & str ;
126140
127141 match entry_hash. find ( '/' ) {
@@ -134,18 +148,23 @@ async fn write_asset_to_pathname(
134148 }
135149
136150 if path_name != target_path {
137- debug ! ( "sanitizing path {:?} => {:?}" , path_name, target_path, ) ;
151+ debug ! ( "sanitizing path {:?} => {:?}" , path_name, target_path) ;
138152 }
139153
140154 if let Some ( parent) = Path :: new ( & target_path) . parent ( ) {
141- fs:: create_dir_all ( parent) . await ?;
155+ fs:: create_dir_all ( parent) . await . map_err ( to_asset_error ) ?;
142156 }
143157
144158 info ! ( "extracting {} to {:?}" , asset_hash, target_path) ;
145- let file = fs:: File :: create ( & target_path) . await ?;
159+ let file = fs:: File :: create ( & target_path)
160+ . await
161+ . map_err ( to_asset_error) ?;
146162 let mut file_writer = io:: BufWriter :: new ( file) ;
147- file_writer. write_all ( & asset_data) . await ?;
148- file_writer. flush ( ) . await ?;
163+ file_writer
164+ . write_all ( & asset_data)
165+ . await
166+ . map_err ( to_asset_error) ?;
167+ file_writer. flush ( ) . await . map_err ( to_asset_error) ?;
149168 trace ! ( "{} is written to disk" , asset_hash) ;
150169 Ok ( ( ) )
151170}
@@ -201,8 +220,14 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
201220
202221 debug ! ( "end of archive" ) ;
203222 for task in tasks {
204- if let Err ( e) = task. await {
205- warn ! ( "an extraction task has failed: {}" , e) ;
223+ match task. await {
224+ Ok ( Ok ( ( ) ) ) => { }
225+ Ok ( Err ( e) ) => {
226+ warn ! ( "failed to write asset: {}" , e) ;
227+ }
228+ Err ( e) => {
229+ warn ! ( "an extraction task has failed: {}" , e) ;
230+ }
206231 }
207232 }
208233 info ! ( "done" ) ;
0 commit comments