ic_backup/ops/artifacts/
mod.rs1#[cfg(test)]
4mod regressions;
5#[cfg(test)]
6mod tests;
7
8use crate::model::artifacts::ArtifactChecksumRecord;
9use ic_host_artifacts::artifact::tree::DirectoryChecksumError;
10use std::{
11 io,
12 path::{Path, PathBuf},
13};
14use thiserror::Error;
15
16pub(crate) fn checksum_directory(path: &Path) -> Result<ArtifactChecksumRecord, ArtifactError> {
17 #[cfg(unix)]
18 {
19 use ic_host_fs::read::tree::checksum::{TreeChecksumError, checksum_directory};
20 let digest = checksum_directory(path, u64::MAX).map_err(|error| match error {
21 TreeChecksumError::Io(error) => ArtifactError::Io(error),
22 TreeChecksumError::Input(error) => ArtifactError::Io(error.into()),
23 TreeChecksumError::Declaration(error) => ArtifactError::from(error),
24 TreeChecksumError::NonUtf8Path { path } => ArtifactError::NonUtf8Path { path },
25 TreeChecksumError::InvalidPath { path } => ArtifactError::UnsupportedEntry {
26 path: path.display().to_string(),
27 kind: "Unknown".into(),
28 },
29 TreeChecksumError::UnsupportedEntry { path, kind } => ArtifactError::UnsupportedEntry {
30 path: path.display().to_string(),
31 kind: format!("{kind:?}"),
32 },
33 })?;
34 Ok(ArtifactChecksumRecord::from_digest(*digest.as_bytes()))
35 }
36 #[cfg(not(unix))]
37 {
38 let _ = path;
39 Err(ArtifactError::UnsupportedPlatform(std::env::consts::OS))
40 }
41}
42
43pub(crate) fn checksum_relative_files(
44 files: Vec<(PathBuf, ArtifactChecksumRecord)>,
45) -> Result<ArtifactChecksumRecord, DirectoryChecksumError> {
46 let digest = ic_host_artifacts::artifact::tree::checksum_relative_files(
47 files
48 .into_iter()
49 .map(|(path, record)| (path, record.sha256()))
50 .collect(),
51 )?;
52 Ok(ArtifactChecksumRecord::from_digest(*digest.as_bytes()))
53}
54
55impl From<DirectoryChecksumError> for ArtifactError {
56 fn from(error: DirectoryChecksumError) -> Self {
57 match error {
58 DirectoryChecksumError::NonUtf8Path { path } => Self::NonUtf8Path { path },
59 error => Self::Io(io::Error::new(io::ErrorKind::InvalidData, error)),
60 }
61 }
62}
63
64#[derive(Debug, Error)]
66pub enum ArtifactError {
67 #[error("artifact path is not UTF-8: {path:?}")]
69 NonUtf8Path {
70 path: PathBuf,
72 },
73 #[error(transparent)]
75 Io(#[from] io::Error),
76 #[error("unsupported artifact entry at {path}: {kind}")]
78 UnsupportedEntry {
79 path: String,
81 kind: String,
83 },
84 #[error("secure artifact traversal is unsupported on platform {0}")]
86 UnsupportedPlatform(&'static str),
87}