diff options
-rw-r--r-- | tvix/nix-compat/src/derivation/mod.rs | 8 | ||||
-rw-r--r-- | tvix/nix-compat/src/derivation/tests/mod.rs | 21 | ||||
-rw-r--r-- | tvix/nix-compat/src/nixhash/mod.rs | 24 | ||||
-rw-r--r-- | tvix/nix-compat/src/nixhash/with_mode.rs | 56 | ||||
-rw-r--r-- | tvix/nix-compat/src/store_path/utils.rs | 16 | ||||
-rw-r--r-- | tvix/store/src/store_io.rs | 17 |
6 files changed, 99 insertions, 43 deletions
diff --git a/tvix/nix-compat/src/derivation/mod.rs b/tvix/nix-compat/src/derivation/mod.rs index 318f2cc1ae99..0e98e24f43dd 100644 --- a/tvix/nix-compat/src/derivation/mod.rs +++ b/tvix/nix-compat/src/derivation/mod.rs @@ -185,7 +185,13 @@ impl Derivation { hasher.finalize().to_vec() }); - NixHash::new(crate::nixhash::HashAlgo::Sha256, digest.to_vec()) + + // We populate the struct directly, as we know the sha256 digest has the + // right size. + NixHash { + algo: crate::nixhash::HashAlgo::Sha256, + digest: digest.to_vec(), + } } /// This calculates all output paths of a Derivation and updates the struct. diff --git a/tvix/nix-compat/src/derivation/tests/mod.rs b/tvix/nix-compat/src/derivation/tests/mod.rs index 1818a08c9bc3..de4ebb6cb20e 100644 --- a/tvix/nix-compat/src/derivation/tests/mod.rs +++ b/tvix/nix-compat/src/derivation/tests/mod.rs @@ -1,6 +1,5 @@ use crate::derivation::output::Output; use crate::derivation::Derivation; -use crate::nixhash::NixHash; use crate::store_path::StorePath; use bstr::{BStr, BString}; use std::collections::{BTreeMap, BTreeSet}; @@ -238,15 +237,19 @@ fn output_path_construction() { "out".to_string(), Output { path: "".to_string(), // will be calculated - hash_with_mode: Some(crate::nixhash::NixHashWithMode::Recursive(NixHash { - digest: data_encoding::HEXLOWER - .decode( - "08813cbee9903c62be4c5027726a418a300da4500b2d369d3af9286f4815ceba" - .as_bytes(), - ) + hash_with_mode: Some(crate::nixhash::NixHashWithMode::Recursive( + ( + crate::nixhash::HashAlgo::Sha256, + data_encoding::HEXLOWER + .decode( + "08813cbee9903c62be4c5027726a418a300da4500b2d369d3af9286f4815ceba" + .as_bytes(), + ) + .unwrap(), + ) + .try_into() .unwrap(), - algo: crate::nixhash::HashAlgo::Sha256, - })), + )), }, ); diff --git a/tvix/nix-compat/src/nixhash/mod.rs b/tvix/nix-compat/src/nixhash/mod.rs index 77a9035901d9..2bd24d4ed3db 100644 --- a/tvix/nix-compat/src/nixhash/mod.rs +++ b/tvix/nix-compat/src/nixhash/mod.rs @@ -1,6 +1,6 @@ use crate::nixbase32; use data_encoding::{BASE64, BASE64_NOPAD, HEXLOWER}; -use thiserror::Error; +use thiserror; mod algos; mod with_mode; @@ -18,11 +18,6 @@ pub struct NixHash { } impl NixHash { - /// Constructs a new [NixHash] by specifying [HashAlgo] and digest. - pub fn new(algo: HashAlgo, digest: Vec<u8>) -> Self { - Self { algo, digest } - } - /// Formats a [NixHash] in the Nix default hash format, /// which is the algo, followed by a colon, then the lower hex encoded digest. pub fn to_nix_hash_string(&self) -> String { @@ -30,8 +25,23 @@ impl NixHash { } } +impl TryFrom<(HashAlgo, Vec<u8>)> for NixHash { + type Error = Error; + + /// Constructs a new [NixHash] by specifying [HashAlgo] and digest. + // It can fail if the passed digest length doesn't match what's expected for + // the passed algo. + fn try_from(value: (HashAlgo, Vec<u8>)) -> Result<Self, Self::Error> { + let (algo, digest) = value; + if digest.len() != hash_algo_length(&algo) { + return Err(Error::InvalidEncodedDigestLength(digest.len(), algo)); + } + Ok(Self { algo, digest }) + } +} + /// Errors related to NixHash construction. -#[derive(Debug, Error)] +#[derive(Debug, thiserror::Error)] pub enum Error { #[error("invalid hash algo: {0}")] InvalidAlgo(String), diff --git a/tvix/nix-compat/src/nixhash/with_mode.rs b/tvix/nix-compat/src/nixhash/with_mode.rs index 344322046614..caf14331426a 100644 --- a/tvix/nix-compat/src/nixhash/with_mode.rs +++ b/tvix/nix-compat/src/nixhash/with_mode.rs @@ -1,5 +1,5 @@ use crate::nixbase32; -use crate::nixhash::{HashAlgo, NixHash}; +use crate::nixhash::{self, HashAlgo, NixHash}; use serde::de::Unexpected; use serde::ser::SerializeMap; use serde::{Deserialize, Deserializer, Serialize, Serializer}; @@ -102,24 +102,42 @@ impl NixHashWithMode { if let Some(v) = map.get("hashAlgo") { if let Some(s) = v.as_str() { match s.strip_prefix("r:") { - Some(rest) => Ok(Some(Self::Recursive(NixHash::new( - HashAlgo::try_from(rest).map_err(|e| { - serde::de::Error::invalid_value( - Unexpected::Other(&e.to_string()), - &format!("one of {}", SUPPORTED_ALGOS.join(",")).as_str(), - ) - })?, - digest, - )))), - None => Ok(Some(Self::Flat(NixHash::new( - HashAlgo::try_from(s).map_err(|e| { - serde::de::Error::invalid_value( - Unexpected::Other(&e.to_string()), - &format!("one of {}", SUPPORTED_ALGOS.join(",")).as_str(), - ) - })?, - digest, - )))), + Some(rest) => Ok(Some(Self::Recursive( + ( + HashAlgo::try_from(rest).map_err(|e| { + serde::de::Error::invalid_value( + Unexpected::Other(&e.to_string()), + &format!("one of {}", SUPPORTED_ALGOS.join(",")).as_str(), + ) + })?, + digest, + ) + .try_into() + .map_err(|e: nixhash::Error| { + serde::de::Error::invalid_value( + Unexpected::Other(&e.to_string()), + &"a digest with right length", + ) + })?, + ))), + None => Ok(Some(Self::Flat( + ( + HashAlgo::try_from(s).map_err(|e| { + serde::de::Error::invalid_value( + Unexpected::Other(&e.to_string()), + &format!("one of {}", SUPPORTED_ALGOS.join(",")).as_str(), + ) + })?, + digest, + ) + .try_into() + .map_err(|e: nixhash::Error| { + serde::de::Error::invalid_value( + Unexpected::Other(&e.to_string()), + &"a digest with right length", + ) + })?, + ))), } } else { Err(serde::de::Error::invalid_type( diff --git a/tvix/nix-compat/src/store_path/utils.rs b/tvix/nix-compat/src/store_path/utils.rs index 26f6e0085c9d..201d98cce460 100644 --- a/tvix/nix-compat/src/store_path/utils.rs +++ b/tvix/nix-compat/src/store_path/utils.rs @@ -54,7 +54,13 @@ pub fn build_text_path<S: AsRef<str>, I: IntoIterator<Item = S>, C: AsRef<[u8]>> let hasher = Sha256::new_with_prefix(content); hasher.finalize() }; - NixHash::new(crate::nixhash::HashAlgo::Sha256, content_digest.to_vec()) + + // We populate the struct directly, as we know the sha256 digest has the + // right size. + NixHash { + algo: crate::nixhash::HashAlgo::Sha256, + digest: content_digest.to_vec(), + } }, name, ) @@ -100,7 +106,13 @@ pub fn build_regular_ca_path<S: AsRef<str>, I: IntoIterator<Item = S>>( hasher.update(":"); hasher.finalize() }; - NixHash::new(crate::nixhash::HashAlgo::Sha256, content_digest.to_vec()) + + // We don't use [NixHash::from_algo_and_digest], as we know [Sha256] has + // the right digest size. + NixHash { + algo: crate::nixhash::HashAlgo::Sha256, + digest: content_digest.to_vec(), + } }, name, ) diff --git a/tvix/store/src/store_io.rs b/tvix/store/src/store_io.rs index 1030bbdd337f..615d1f50f4a3 100644 --- a/tvix/store/src/store_io.rs +++ b/tvix/store/src/store_io.rs @@ -114,9 +114,12 @@ impl TvixStoreIO { ) .expect("error during nar calculation"); // TODO: handle error - // For given NAR sha256 digest and name, return the new [StorePath] this would have. - let nar_hash_with_mode = - NixHashWithMode::Recursive(NixHash::new(HashAlgo::Sha256, nar_sha256.to_vec())); + // We populate the struct directly, as we know the sha256 digest has the + // right size. + let nar_hash_with_mode = NixHashWithMode::Recursive(NixHash { + algo: HashAlgo::Sha256, + digest: nar_sha256.to_vec(), + }); let name = path .file_name() @@ -172,8 +175,12 @@ impl TvixStoreIO { /// For given NAR sha256 digest and name, return the new [StorePath] this would have. #[instrument(skip(nar_sha256_digest), ret, fields(nar_sha256_digest=BASE64.encode(nar_sha256_digest)))] fn calculate_nar_based_store_path(nar_sha256_digest: &[u8; 32], name: &str) -> StorePath { - let nar_hash_with_mode = - NixHashWithMode::Recursive(NixHash::new(HashAlgo::Sha256, nar_sha256_digest.to_vec())); + // We populate the struct directly, as we know the sha256 digest has the + // right size. + let nar_hash_with_mode = NixHashWithMode::Recursive(NixHash { + algo: HashAlgo::Sha256, + digest: nar_sha256_digest.to_vec(), + }); build_regular_ca_path(name, &nar_hash_with_mode, Vec::<String>::new(), false).unwrap() } |