Skip to content

Commit 07c1f07

Browse files
committed
extraction of tar archives with identity check (#384)
1 parent c30bebf commit 07c1f07

File tree

1 file changed

+42
-5
lines changed

1 file changed

+42
-5
lines changed

tests/tools/src/lib.rs

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std::io::Read;
12
use std::{
23
collections::BTreeMap,
34
path::{Path, PathBuf},
@@ -186,12 +187,12 @@ fn create_archive_if_not_on_ci(source_dir: &Path, archive: &Path, script_identit
186187
res
187188
}
188189

189-
const META_NAME: &str = "__gitoxide_meta__";
190+
const META_DIR_NAME: &str = "__gitoxide_meta__";
190191
const META_IDENTITY: &str = "identity";
191192
const META_GIT_VERSION: &str = "git-version";
192193

193194
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);
195196
std::fs::create_dir_all(&meta_dir)?;
196197
std::fs::write(meta_dir.join(META_IDENTITY), format!("{}", script_identity).as_bytes())?;
197198
std::fs::write(
@@ -203,10 +204,46 @@ fn populate_meta_dir(destination_dir: &Path, script_identity: u32) -> std::io::R
203204

204205
/// `required_script_identity` is the identity of the script that generated the state that is contained in `archive`.
205206
/// 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<()> {
207208
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(())
210247
}
211248

212249
pub fn to_bstr_err(err: nom::Err<VerboseError<&[u8]>>) -> VerboseError<&BStr> {

0 commit comments

Comments
 (0)