History

extraction of tar archives with identity check (#384)

Sebastian Thiel committed 4 years ago

Commit 07c1f071 parent c30bebf1 file · +42 −5Browse files

Unified · Split

tests/tools/src/lib.rs+42−5
@@ -1,3 +1,4 @@
1use std::io::Read;
1use std::{2use std::{
2 collections::BTreeMap,3 collections::BTreeMap,
3 path::{Path, PathBuf},4 path::{Path, PathBuf},
@@ -186,12 +187,12 @@ fn create_archive_if_not_on_ci(source_dir: &Path, archive: &Path, script_identit · 182 unmodified lines
186 res187 res
187}188}
188 189
189const META_NAME: &str = "__gitoxide_meta__";190const META_DIR_NAME: &str = "__gitoxide_meta__";
190const META_IDENTITY: &str = "identity";191const META_IDENTITY: &str = "identity";
191const META_GIT_VERSION: &str = "git-version";192const META_GIT_VERSION: &str = "git-version";
192 193
193fn populate_meta_dir(destination_dir: &Path, script_identity: u32) -> std::io::Result<PathBuf> {194fn 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 std::fs::create_dir_all(&meta_dir)?;196 std::fs::create_dir_all(&meta_dir)?;
196 std::fs::write(meta_dir.join(META_IDENTITY), format!("{}", script_identity).as_bytes())?;197 std::fs::write(meta_dir.join(META_IDENTITY), format!("{}", script_identity).as_bytes())?;
197 std::fs::write(198 std::fs::write(
@@ -203,10 +204,46 @@ fn populate_meta_dir(destination_dir: &Path, script_identity: u32) -> std::io::R · 5 unmodified lines
203 204
204/// `required_script_identity` is the identity of the script that generated the state that is contained in `archive`.205/// `required_script_identity` is the identity of the script that generated the state that is contained in `archive`.
205/// If this is not the case, the arvhive will be ignored.206/// If this is not the case, the arvhive will be ignored.
206fn extract_archive(_archive: &Path, destination_dir: &Path, _required_script_identity: u32) -> std::io::Result<()> {207fn extract_archive(archive: &Path, destination_dir: &Path, required_script_identity: u32) -> std::io::Result<()> {
207 std::fs::create_dir_all(destination_dir)?;208 std::fs::create_dir_all(destination_dir)?;
208 // TODO209
209 Err(std::io::ErrorKind::NotFound.into())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
212pub fn to_bstr_err(err: nom::Err<VerboseError<&[u8]>>) -> VerboseError<&BStr> {249pub fn to_bstr_err(err: nom::Err<VerboseError<&[u8]>>) -> VerboseError<&BStr> {