From f06b820ac0a42d06af3d080ffb6c8b8dd633d97b Mon Sep 17 00:00:00 2001 From: Dietmar Maurer Date: Sun, 13 Oct 2019 10:09:12 +0200 Subject: [PATCH] src/backup/manifest.rs: add verify_file --- src/backup/manifest.rs | 53 +++++++++++++++++++++------- src/bin/proxmox-backup-client.rs | 60 +++++--------------------------- src/client/backup_reader.rs | 9 +++-- 3 files changed, 55 insertions(+), 67 deletions(-) diff --git a/src/backup/manifest.rs b/src/backup/manifest.rs index 64e7fdac..80bd7661 100644 --- a/src/backup/manifest.rs +++ b/src/backup/manifest.rs @@ -28,6 +28,31 @@ impl BackupManifest { self.files.push(FileInfo { filename, size, csum }); } + fn lookup_file_info(&self, name: &str) -> Result<&FileInfo, Error> { + + let info = self.files.iter().find(|item| item.filename == name); + + match info { + None => bail!("manifest does not contain file '{}'", name), + Some(info) => Ok(info), + } + } + + pub fn verify_file(&self, name: &str, csum: &[u8; 32], size: u64) -> Result<(), Error> { + + let info = self.lookup_file_info(name)?; + + if size != info.size { + bail!("wrong size for file '{}' ({} != {}", name, info.size, size); + } + + if csum != &info.csum { + bail!("wrong checksum for file '{}'", name); + } + + Ok(()) + } + pub fn into_json(self) -> Value { json!({ "backup-type": self.snapshot.group().backup_type(), @@ -54,21 +79,23 @@ impl TryFrom for BackupManifest { use crate::tools::{required_string_property, required_integer_property, required_array_property}; - let backup_type = required_string_property(&data, "backup_type")?; - let backup_id = required_string_property(&data, "backup_id")?; - let backup_time = required_integer_property(&data, "backup_time")?; + proxmox::tools::try_block!({ + let backup_type = required_string_property(&data, "backup_type")?; + let backup_id = required_string_property(&data, "backup_id")?; + let backup_time = required_integer_property(&data, "backup_time")?; - let snapshot = BackupDir::new(backup_type, backup_id, backup_time); + let snapshot = BackupDir::new(backup_type, backup_id, backup_time); - let mut files = Vec::new(); - for item in required_array_property(&data, "files")?.iter() { - let filename = required_string_property(item, "filename")?.to_owned(); - let csum = required_string_property(item, "csum")?; - let csum = proxmox::tools::hex_to_digest(csum)?; - let size = required_integer_property(item, "size")? as u64; - files.push(FileInfo { filename, size, csum }); - } + let mut files = Vec::new(); + for item in required_array_property(&data, "files")?.iter() { + let filename = required_string_property(item, "filename")?.to_owned(); + let csum = required_string_property(item, "csum")?; + let csum = proxmox::tools::hex_to_digest(csum)?; + let size = required_integer_property(item, "size")? as u64; + files.push(FileInfo { filename, size, csum }); + } + Ok(Self { files, snapshot }) + }).map_err(|err: Error| format_err!("unable to parse backup manifest - {}", err)) - Ok(Self { files, snapshot }) } } diff --git a/src/bin/proxmox-backup-client.rs b/src/bin/proxmox-backup-client.rs index a669de2a..1cc123d8 100644 --- a/src/bin/proxmox-backup-client.rs +++ b/src/bin/proxmox-backup-client.rs @@ -489,7 +489,7 @@ fn dump_catalog( true, ).await?; - let backup_index = client.download_manifest().await?; + let manifest = client.download_manifest().await?; let blob_file = std::fs::OpenOptions::new() .read(true) @@ -500,7 +500,7 @@ fn dump_catalog( let mut blob_file = client.download(CATALOG_BLOB_NAME, blob_file).await?; let (csum, size) = compute_file_csum(&mut blob_file)?; - verify_index_file(&backup_index, CATALOG_BLOB_NAME, &csum, size)?; + manifest.verify_file(CATALOG_BLOB_NAME, &csum, size)?; blob_file.seek(SeekFrom::Start(0))?; @@ -877,46 +877,6 @@ fn restore( async_main(restore_do(param)) } -fn verify_index_file(backup_index: &Value, name: &str, csum: &[u8; 32], size: u64) -> Result<(), Error> { - - let files = backup_index["files"] - .as_array() - .ok_or_else(|| format_err!("mailformed index - missing 'files' property"))?; - - let info = files.iter().find(|v| { - match v["filename"].as_str() { - Some(filename) => filename == name, - None => false, - } - }); - - let info = match info { - None => bail!("index does not contain file '{}'", name), - Some(info) => info, - }; - - match info["size"].as_u64() { - None => bail!("index does not contain property 'size' for file '{}'", name), - Some(expected_size) => { - if expected_size != size { - bail!("verify index failed - wrong size for file '{}' ({} != {}", name, expected_size, size); - } - } - }; - - match info["csum"].as_str() { - None => bail!("index does not contain property 'csum' for file '{}'", name), - Some(expected_csum) => { - let expected_csum = &proxmox::tools::hex_to_digest(expected_csum)?; - if expected_csum != csum { - bail!("verify index failed - wrong checksum for file '{}'", name); - } - } - }; - - Ok(()) -} - fn dump_image( client: Arc, crypt_config: Option>, @@ -1036,10 +996,10 @@ async fn restore_do(param: Value) -> Result { .custom_flags(libc::O_TMPFILE) .open("/tmp")?; - let backup_index = client.download_manifest().await?; + let manifest = client.download_manifest().await?; if server_archive_name == MANIFEST_BLOB_NAME { - let backup_index_data = backup_index.to_string(); + let backup_index_data = manifest.into_json().to_string(); if let Some(target) = target { file_set_contents(target, backup_index_data.as_bytes(), None)?; } else { @@ -1053,7 +1013,7 @@ async fn restore_do(param: Value) -> Result { let mut tmpfile = client.download(&server_archive_name, tmpfile).await?; let (csum, size) = compute_file_csum(&mut tmpfile)?; - verify_index_file(&backup_index, &server_archive_name, &csum, size)?; + manifest.verify_file(&server_archive_name, &csum, size)?; tmpfile.seek(SeekFrom::Start(0))?; let mut reader = DataBlobReader::new(tmpfile, crypt_config)?; @@ -1081,8 +1041,7 @@ async fn restore_do(param: Value) -> Result { // Note: do not use values stored in index (not trusted) - instead, computed them again let (csum, size) = index.compute_csum(); - - verify_index_file(&backup_index, &server_archive_name, &csum, size)?; + manifest.verify_file(&server_archive_name, &csum, size)?; let most_used = index.find_most_used_chunks(8); @@ -1119,8 +1078,7 @@ async fn restore_do(param: Value) -> Result { // Note: do not use values stored in index (not trusted) - instead, computed them again let (csum, size) = index.compute_csum(); - - verify_index_file(&backup_index, &server_archive_name, &csum, size)?; + manifest.verify_file(&server_archive_name, &csum, size)?; let mut writer = if let Some(target) = target { std::fs::OpenOptions::new() @@ -1760,7 +1718,7 @@ async fn mount_do(param: Value, pipe: Option) -> Result { .custom_flags(libc::O_TMPFILE) .open("/tmp")?; - let backup_index = client.download_manifest().await?; + let manifest = client.download_manifest().await?; if server_archive_name.ends_with(".didx") { let tmpfile = client.download(&server_archive_name, tmpfile).await?; @@ -1769,7 +1727,7 @@ async fn mount_do(param: Value, pipe: Option) -> Result { // Note: do not use values stored in index (not trusted) - instead, computed them again let (csum, size) = index.compute_csum(); - verify_index_file(&backup_index, &server_archive_name, &csum, size)?; + manifest.verify_file(&server_archive_name, &csum, size)?; let most_used = index.find_most_used_chunks(8); let chunk_reader = RemoteChunkReader::new(client.clone(), crypt_config, most_used); diff --git a/src/client/backup_reader.rs b/src/client/backup_reader.rs index 893c3790..3c30a2f9 100644 --- a/src/client/backup_reader.rs +++ b/src/client/backup_reader.rs @@ -121,13 +121,16 @@ impl BackupReader { } /// Download backup manifest (index.json) - pub async fn download_manifest(&self) -> Result { + pub async fn download_manifest(&self) -> Result { + + use std::convert::TryFrom; let raw_data = self.download(MANIFEST_BLOB_NAME, Vec::with_capacity(64*1024)).await?; let blob = DataBlob::from_raw(raw_data)?; blob.verify_crc()?; let data = blob.decode(self.crypt_config.as_ref().map(Arc::as_ref))?; - let result: Value = serde_json::from_slice(&data[..])?; - Ok(result) + let json: Value = serde_json::from_slice(&data[..])?; + + BackupManifest::try_from(json) } } -- 2.39.5