diff --git a/pbs-tools/Cargo.toml b/pbs-tools/Cargo.toml index a041da09..17ef9112 100644 --- a/pbs-tools/Cargo.toml +++ b/pbs-tools/Cargo.toml @@ -11,6 +11,7 @@ anyhow = "1.0" libc = "0.2" nix = "0.19.1" nom = "5.1" +openssl = "0.10" regex = "1.2" serde = "1.0" serde_json = "1.0" diff --git a/pbs-tools/src/lib.rs b/pbs-tools/src/lib.rs index 48fc738c..533ec1f1 100644 --- a/pbs-tools/src/lib.rs +++ b/pbs-tools/src/lib.rs @@ -5,6 +5,7 @@ pub mod json; pub mod nom; pub mod process_locker; pub mod str; +pub mod sha; mod command; pub use command::{command_output, command_output_as_string, run_command}; diff --git a/pbs-tools/src/sha.rs b/pbs-tools/src/sha.rs new file mode 100644 index 00000000..56cdc683 --- /dev/null +++ b/pbs-tools/src/sha.rs @@ -0,0 +1,29 @@ +//! SHA helpers. + +use std::io::Read; + +use anyhow::Error; + +/// Calculate the sha256sum from a readable object. +pub fn sha256(file: &mut dyn Read) -> Result<([u8; 32], u64), Error> { + let mut hasher = openssl::sha::Sha256::new(); + let mut buffer = proxmox::tools::vec::undefined(256 * 1024); + let mut size: u64 = 0; + + loop { + let count = match file.read(&mut buffer) { + Ok(0) => break, + Ok(count) => count, + Err(ref err) if err.kind() == std::io::ErrorKind::Interrupted => { + continue; + } + Err(err) => return Err(err.into()), + }; + size += count as u64; + hasher.update(&buffer[..count]); + } + + let csum = hasher.finish(); + + Ok((csum, size)) +} diff --git a/src/client/backup_reader.rs b/src/client/backup_reader.rs index ca546f39..e04494d1 100644 --- a/src/client/backup_reader.rs +++ b/src/client/backup_reader.rs @@ -16,8 +16,7 @@ use pbs_datastore::dynamic_index::DynamicIndexReader; use pbs_datastore::fixed_index::FixedIndexReader; use pbs_datastore::index::IndexFile; use pbs_datastore::manifest::MANIFEST_BLOB_NAME; - -use crate::tools::compute_file_csum; +use pbs_tools::sha::sha256; use super::{HttpClient, H2Client}; @@ -163,7 +162,8 @@ impl BackupReader { self.download(name, &mut tmpfile).await?; - let (csum, size) = compute_file_csum(&mut tmpfile)?; + tmpfile.seek(SeekFrom::Start(0))?; + let (csum, size) = sha256(&mut tmpfile)?; manifest.verify_file(name, &csum, size)?; tmpfile.seek(SeekFrom::Start(0))?; diff --git a/src/client/pull.rs b/src/client/pull.rs index 8db43f90..42b94bc4 100644 --- a/src/client/pull.rs +++ b/src/client/pull.rs @@ -13,13 +13,14 @@ use serde_json::json; use proxmox::api::error::{HttpError, StatusCode}; use pbs_datastore::task_log; +use pbs_tools::sha::sha256; use crate::{ api2::types::*, backup::*, client::*, server::WorkerTask, - tools::{compute_file_csum, ParallelHandler}, + tools::ParallelHandler, }; // fixme: implement filters @@ -215,7 +216,8 @@ async fn pull_single_archive( .await?; } ArchiveType::Blob => { - let (csum, size) = compute_file_csum(&mut tmpfile)?; + tmpfile.seek(SeekFrom::Start(0))?; + let (csum, size) = sha256(&mut tmpfile)?; verify_archive(archive_info, &csum, size)?; } } @@ -357,7 +359,7 @@ async fn pull_snapshot( } ArchiveType::Blob => { let mut tmpfile = std::fs::File::open(&path)?; - let (csum, size) = compute_file_csum(&mut tmpfile)?; + let (csum, size) = sha256(&mut tmpfile)?; match manifest.verify_file(&item.filename, &csum, size) { Ok(_) => continue, Err(err) => { diff --git a/src/tools/mod.rs b/src/tools/mod.rs index 03d7baf0..16f21091 100644 --- a/src/tools/mod.rs +++ b/src/tools/mod.rs @@ -5,7 +5,7 @@ use std::any::Any; use std::collections::HashMap; use std::hash::BuildHasher; use std::fs::File; -use std::io::{self, BufRead, Read, Seek, SeekFrom}; +use std::io::{self, BufRead}; use std::os::unix::io::RawFd; use std::path::Path; @@ -457,33 +457,6 @@ pub fn strip_ascii_whitespace(line: &[u8]) -> &[u8] { } } -/// Seeks to start of file and computes the SHA256 hash -pub fn compute_file_csum(file: &mut File) -> Result<([u8; 32], u64), Error> { - - file.seek(SeekFrom::Start(0))?; - - let mut hasher = openssl::sha::Sha256::new(); - let mut buffer = proxmox::tools::vec::undefined(256*1024); - let mut size: u64 = 0; - - loop { - let count = match file.read(&mut buffer) { - Ok(0) => break, - Ok(count) => count, - Err(ref err) if err.kind() == std::io::ErrorKind::Interrupted => { - continue; - } - Err(err) => return Err(err.into()), - }; - size += count as u64; - hasher.update(&buffer[..count]); - } - - let csum = hasher.finish(); - - Ok((csum, size)) -} - /// Create the base run-directory. /// /// This exists to fixate the permissions for the run *base* directory while allowing intermediate