diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/bin/obnam.rs | 7 | ||||
-rw-r--r-- | src/chunk.rs | 6 | ||||
-rw-r--r-- | src/chunkid.rs | 8 | ||||
-rw-r--r-- | src/client.rs | 35 | ||||
-rw-r--r-- | src/cmd/get_chunk.rs | 15 | ||||
-rw-r--r-- | src/cmd/mod.rs | 3 | ||||
-rw-r--r-- | src/error.rs | 6 |
7 files changed, 63 insertions, 17 deletions
diff --git a/src/bin/obnam.rs b/src/bin/obnam.rs index f31884b..e5703ed 100644 --- a/src/bin/obnam.rs +++ b/src/bin/obnam.rs @@ -2,7 +2,7 @@ use log::{debug, error, info, LevelFilter}; use log4rs::append::file::FileAppender; use log4rs::config::{Appender, Config, Logger, Root}; use obnam::client::ClientConfig; -use obnam::cmd::{backup, list, list_files, restore}; +use obnam::cmd::{backup, get_chunk, list, list_files, restore}; use std::path::{Path, PathBuf}; use structopt::StructOpt; @@ -23,6 +23,7 @@ fn main() -> anyhow::Result<()> { Command::List => list(&config), Command::ListFiles { gen_id } => list_files(&config, &gen_id), Command::Restore { gen_id, to } => restore(&config, &gen_id, &to), + Command::GetChunk { chunk_id } => get_chunk(&config, &chunk_id), }; if let Err(ref e) = result { @@ -60,6 +61,10 @@ enum Command { #[structopt(parse(from_os_str))] to: PathBuf, }, + GetChunk { + #[structopt()] + chunk_id: String, + }, } fn setup_logging(filename: &Path) -> anyhow::Result<()> { diff --git a/src/chunk.rs b/src/chunk.rs index 7fdeccb..4917b60 100644 --- a/src/chunk.rs +++ b/src/chunk.rs @@ -35,6 +35,12 @@ impl GenerationChunk { Self { chunk_ids } } + pub fn from_data_chunk(chunk: &DataChunk) -> anyhow::Result<Self> { + let data = chunk.data(); + let data = std::str::from_utf8(data)?; + Ok(serde_json::from_str(data)?) + } + pub fn is_empty(&self) -> bool { self.chunk_ids.is_empty() } diff --git a/src/chunkid.rs b/src/chunkid.rs index 9eec41f..3933d4b 100644 --- a/src/chunkid.rs +++ b/src/chunkid.rs @@ -37,6 +37,10 @@ impl ChunkId { } } + pub fn from_str(s: &str) -> Self { + ChunkId { id: s.to_string() } + } + pub fn as_bytes(&self) -> &[u8] { self.id.as_bytes() } @@ -81,7 +85,7 @@ impl FromStr for ChunkId { type Err = (); fn from_str(s: &str) -> Result<Self, Self::Err> { - Ok(ChunkId { id: s.to_string() }) + Ok(ChunkId::from_str(s)) } } @@ -113,6 +117,6 @@ mod test { fn survives_round_trip() { let id = ChunkId::new(); let id_str = id.to_string(); - assert_eq!(id, id_str.parse().unwrap()); + assert_eq!(id, ChunkId::from_str(&id_str)) } } diff --git a/src/client.rs b/src/client.rs index 616ceef..1b507d3 100644 --- a/src/client.rs +++ b/src/client.rs @@ -4,6 +4,7 @@ use crate::chunk::GenerationChunk; use crate::chunker::Chunker; use crate::chunkid::ChunkId; use crate::chunkmeta::ChunkMeta; +use crate::error::ObnamError; use crate::fsentry::{FilesystemEntry, FilesystemKind}; use crate::generation::{FinishedGeneration, LocalGeneration}; use crate::genlist::GenerationList; @@ -212,24 +213,30 @@ impl BackupClient { return Err(ClientError::ChunkNotFound(chunk_id.to_string()).into()); } + let headers = res.headers(); + let meta = headers.get("chunk-meta"); + if meta.is_none() { + return Err(ObnamError::NoChunkMeta(chunk_id.to_string()).into()); + } + let meta = meta.unwrap().to_str()?; + let meta: ChunkMeta = serde_json::from_str(meta)?; + let body = res.bytes()?; - Ok(DataChunk::new(body.to_vec())) + let body = body.to_vec(); + let actual = sha256(&body); + if actual != meta.sha256() { + return Err(ObnamError::WrongChecksum(chunk_id.to_string()).into()); + } + + let chunk: DataChunk = DataChunk::new(body); + + Ok(chunk) } fn fetch_generation_chunk(&self, gen_id: &str) -> anyhow::Result<GenerationChunk> { - let url = format!("{}/{}", &self.chunks_url(), gen_id); - trace!("fetch_generation_chunk: url={:?}", url); - let req = self.client.get(&url).build()?; - let res = self.client.execute(req)?; - debug!("fetch_generation_chunk: status={}", res.status()); - if res.status() != 200 { - return Err(ClientError::GenerationNotFound(gen_id.to_string()).into()); - } - - let text = res.text()?; - debug!("fetch_generation_chunk: text={:?}", text); - let gen: GenerationChunk = serde_json::from_str(&text)?; - debug!("fetch_generation_chunk: {:?}", gen); + let chunk_id = ChunkId::from_str(gen_id); + let chunk = self.fetch_chunk(&chunk_id)?; + let gen = GenerationChunk::from_data_chunk(&chunk)?; Ok(gen) } diff --git a/src/cmd/get_chunk.rs b/src/cmd/get_chunk.rs new file mode 100644 index 0000000..bf653ff --- /dev/null +++ b/src/cmd/get_chunk.rs @@ -0,0 +1,15 @@ +use crate::chunkid::ChunkId; +use crate::client::BackupClient; +use crate::client::ClientConfig; +use std::io::{stdout, Write}; + +pub fn get_chunk(config: &ClientConfig, chunk_id: &str) -> anyhow::Result<()> { + let client = BackupClient::new(&config.server_url)?; + let chunk_id: ChunkId = chunk_id.parse().unwrap(); + let chunk = client.fetch_chunk(&chunk_id)?; + + let stdout = stdout(); + let mut handle = stdout.lock(); + handle.write_all(chunk.data())?; + Ok(()) +} diff --git a/src/cmd/mod.rs b/src/cmd/mod.rs index 2919d88..c3cebe2 100644 --- a/src/cmd/mod.rs +++ b/src/cmd/mod.rs @@ -9,3 +9,6 @@ pub use list_files::list_files; pub mod restore; pub use restore::restore; + +pub mod get_chunk; +pub use get_chunk::get_chunk; diff --git a/src/error.rs b/src/error.rs index 3b3f573..360e62d 100644 --- a/src/error.rs +++ b/src/error.rs @@ -9,4 +9,10 @@ pub enum ObnamError { #[error("Generation has more than one file with the name {0}")] TooManyFiles(PathBuf), + + #[error("Server response did not have a 'chunk-meta' header for chunk {0}")] + NoChunkMeta(String), + + #[error("Wrong checksum for chunk {0}")] + WrongChecksum(String), } |