1
+ use std:: io:: Read ;
1
2
use std:: {
2
3
collections:: BTreeMap ,
3
4
path:: { Path , PathBuf } ,
@@ -186,12 +187,12 @@ fn create_archive_if_not_on_ci(source_dir: &Path, archive: &Path, script_identit
186
187
res
187
188
}
188
189
189
- const META_NAME : & str = "__gitoxide_meta__" ;
190
+ const META_DIR_NAME : & str = "__gitoxide_meta__" ;
190
191
const META_IDENTITY : & str = "identity" ;
191
192
const META_GIT_VERSION : & str = "git-version" ;
192
193
193
194
fn populate_meta_dir ( destination_dir : & Path , script_identity : u32 ) -> std:: io:: Result < PathBuf > {
194
- let meta_dir = destination_dir. join ( META_NAME ) ;
195
+ let meta_dir = destination_dir. join ( META_DIR_NAME ) ;
195
196
std:: fs:: create_dir_all ( & meta_dir) ?;
196
197
std:: fs:: write ( meta_dir. join ( META_IDENTITY ) , format ! ( "{}" , script_identity) . as_bytes ( ) ) ?;
197
198
std:: fs:: write (
@@ -203,10 +204,46 @@ fn populate_meta_dir(destination_dir: &Path, script_identity: u32) -> std::io::R
203
204
204
205
/// `required_script_identity` is the identity of the script that generated the state that is contained in `archive`.
205
206
/// If this is not the case, the arvhive will be ignored.
206
- fn extract_archive ( _archive : & Path , destination_dir : & Path , _required_script_identity : u32 ) -> std:: io:: Result < ( ) > {
207
+ fn extract_archive ( archive : & Path , destination_dir : & Path , required_script_identity : u32 ) -> std:: io:: Result < ( ) > {
207
208
std:: fs:: create_dir_all ( destination_dir) ?;
208
- // TODO
209
- Err ( std:: io:: ErrorKind :: NotFound . into ( ) )
209
+
210
+ let mut archive_buf = Vec :: < u8 > :: new ( ) ;
211
+ let mut decoder = xz2:: bufread:: XzDecoder :: new ( std:: io:: BufReader :: new ( std:: fs:: File :: open ( archive) ?) ) ;
212
+ std:: io:: copy ( & mut decoder, & mut archive_buf) ?;
213
+
214
+ let mut entry_buf = Vec :: < u8 > :: new ( ) ;
215
+ let archive_identity: u32 = tar:: Archive :: new ( std:: io:: Cursor :: new ( & mut & * archive_buf) )
216
+ . entries_with_seek ( ) ?
217
+ . filter_map ( |e| e. ok ( ) )
218
+ . find_map ( |mut e : tar:: Entry < ' _ , _ > | {
219
+ let path = e. path ( ) . ok ( ) ?;
220
+ if path. parent ( ) ?. file_name ( ) ? == META_DIR_NAME && path. file_name ( ) ? == META_IDENTITY {
221
+ entry_buf. clear ( ) ;
222
+ e. read_to_end ( & mut entry_buf) . ok ( ) ?;
223
+ entry_buf. to_str ( ) . ok ( ) ?. trim ( ) . parse ( ) . ok ( )
224
+ } else {
225
+ None
226
+ }
227
+ } )
228
+ . ok_or_else ( || {
229
+ std:: io:: Error :: new (
230
+ std:: io:: ErrorKind :: Other ,
231
+ "BUG: Could not find meta directory in our own archive" ,
232
+ )
233
+ } ) ?;
234
+ if archive_identity != required_script_identity {
235
+ return Err ( std:: io:: ErrorKind :: NotFound . into ( ) ) ;
236
+ }
237
+
238
+ for entry in tar:: Archive :: new ( & mut & * archive_buf) . entries ( ) ? {
239
+ let mut entry = entry?;
240
+ let path = entry. path ( ) ?;
241
+ if path. to_str ( ) == Some ( META_DIR_NAME ) || path. parent ( ) . and_then ( |p| p. to_str ( ) ) == Some ( META_DIR_NAME ) {
242
+ continue ;
243
+ }
244
+ entry. unpack_in ( & destination_dir) ?;
245
+ }
246
+ Ok ( ( ) )
210
247
}
211
248
212
249
pub fn to_bstr_err ( err : nom:: Err < VerboseError < & [ u8 ] > > ) -> VerboseError < & BStr > {
0 commit comments