diff options
-rw-r--r-- | crates/runner/src/task.rs | 41 |
1 files changed, 36 insertions, 5 deletions
diff --git a/crates/runner/src/task.rs b/crates/runner/src/task.rs index a6fbd25..08b9cb4 100644 --- a/crates/runner/src/task.rs +++ b/crates/runner/src/task.rs @@ -1,6 +1,6 @@ use std::{ collections::HashMap, - io::BufWriter, + io::{self, BufWriter}, os::unix::prelude::CommandExt, path::Path, process::{self, Command, Stdio}, @@ -15,7 +15,7 @@ use nix::{ unistd::{self, Gid, Uid}, }; use serde::Serialize; -use tee_readwrite::TeeWriter; +use tee_readwrite::{TeeReader, TeeWriter}; use common::{error::*, string_hash::*, types::*}; @@ -156,9 +156,39 @@ fn cleanup_task(input_hash: &InputHash) -> Result<()> { Ok(()) } -fn unpack_dependency<P1: AsRef<Path>, P2: AsRef<Path>>(filename: P1, dest: P2) -> Result<()> { - let file = fs::open(filename.as_ref())?; - tar::unpack(file, dest.as_ref()).with_context(|| { +fn unpack_dependency<P1: AsRef<Path>, P2: AsRef<Path>>( + filename: P1, + dest: P2, + expected_hash: &ArchiveHash, +) -> Result<()> { + (|| -> Result<()> { + let file = fs::open(filename.as_ref())?; + let hasher = ArchiveHasher::new(); + let buffered_hasher = BufWriter::with_capacity(16 * 1024 * 1024, hasher); + let mut reader = TeeReader::new(file, buffered_hasher, false); + + tar::unpack(&mut reader, dest.as_ref())?; + + // Read file to end to get the correct hash + io::copy(&mut reader, &mut io::sink())?; + + let (_, buffered_hasher) = reader.into_inner(); + let hasher = buffered_hasher.into_inner()?; + + let actual_hash = ArchiveHash(StringHash(hasher.finalize().into())); + + if &actual_hash != expected_hash { + return Err(Error::new(format!( + "Incorrect file hash for {:?} (expected: {}, actual: {})", + filename.as_ref(), + expected_hash, + actual_hash + ))); + } + + Ok(()) + })() + .with_context(|| { format!( "Failed to unpack {:?} to {:?}", filename.as_ref(), @@ -189,6 +219,7 @@ fn unpack_dependencies(input_hash: &InputHash, task: &Task) -> Result<()> { unpack_dependency( paths::archive_filename(output), paths::join(&[&depends_dir, path]), + output, )?; } } |