aboutsummaryrefslogtreecommitdiffstats
path: root/src/archive.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/archive.rs')
-rw-r--r--src/archive.rs135
1 files changed, 72 insertions, 63 deletions
diff --git a/src/archive.rs b/src/archive.rs
index 4703c0d..b5788f5 100644
--- a/src/archive.rs
+++ b/src/archive.rs
@@ -1,6 +1,5 @@
use actix_web::http::ContentEncoding;
use bytes::Bytes;
-use failure::ResultExt;
use libflate::gzip::Encoder;
use serde::Deserialize;
use std::io;
@@ -8,7 +7,7 @@ use std::path::PathBuf;
use strum_macros::{Display, EnumIter, EnumString};
use tar::Builder;
-use crate::errors;
+use crate::errors::{ContextualError, ContextualErrorKind};
/// Available compression methods
#[derive(Deserialize, Clone, EnumIter, EnumString, Display)]
@@ -47,49 +46,50 @@ pub fn create_archive(
method: &CompressionMethod,
dir: &PathBuf,
skip_symlinks: bool,
-) -> Result<(String, Bytes), errors::CompressionError> {
+) -> Result<(String, Bytes), ContextualError> {
match method {
CompressionMethod::TarGz => tgz_compress(&dir, skip_symlinks),
}
}
/// Compresses a given folder in .tar.gz format, and returns the result as a stream of bytes
-fn tgz_compress(
- dir: &PathBuf,
- skip_symlinks: bool,
-) -> Result<(String, Bytes), errors::CompressionError> {
+fn tgz_compress(dir: &PathBuf, skip_symlinks: bool) -> Result<(String, Bytes), ContextualError> {
let src_dir = dir.display().to_string();
- let inner_folder = match dir.file_name() {
- Some(directory_name) => match directory_name.to_str() {
- Some(directory) => directory,
- None => {
- return Err(errors::CompressionError::new(
- errors::CompressionErrorKind::InvalidUTF8DirectoryName,
+ if let Some(inner_folder) = dir.file_name() {
+ if let Some(directory) = inner_folder.to_str() {
+ let dst_filename = format!("{}.tar", directory);
+ let dst_tgz_filename = format!("{}.gz", dst_filename);
+ let mut tgz_data = Bytes::new();
+
+ let tar_data = tar(src_dir, directory.to_string(), skip_symlinks).map_err(|e| {
+ ContextualError::new(ContextualErrorKind::ArchiveCreationError(
+ "tarball".to_string(),
+ Box::new(e),
))
- }
- },
- None => {
- return Err(errors::CompressionError::new(
- errors::CompressionErrorKind::InvalidDirectoryName,
- ))
- }
- };
- let dst_filename = format!("{}.tar", inner_folder);
- let dst_tgz_filename = format!("{}.gz", dst_filename);
-
- let tar_content = tar(src_dir, inner_folder.to_string(), skip_symlinks).context(
- errors::CompressionErrorKind::TarBuildingError {
- message: "an error occured while writing the TAR archive".to_string(),
- },
- )?;
- let gz_data = gzip(&tar_content).context(errors::CompressionErrorKind::GZipBuildingError {
- message: "an error occured while writing the GZIP archive".to_string(),
- })?;
+ })?;
- let mut data = Bytes::new();
- data.extend_from_slice(&gz_data);
+ let gz_data = gzip(&tar_data).map_err(|e| {
+ ContextualError::new(ContextualErrorKind::ArchiveCreationError(
+ "GZIP archive".to_string(),
+ Box::new(e),
+ ))
+ })?;
- Ok((dst_tgz_filename, data))
+ tgz_data.extend_from_slice(&gz_data);
+
+ Ok((dst_tgz_filename, tgz_data))
+ } else {
+ // https://doc.rust-lang.org/std/ffi/struct.OsStr.html#method.to_str
+ Err(ContextualError::new(ContextualErrorKind::InvalidPathError(
+ "Directory name contains invalid UTF-8 characters".to_string(),
+ )))
+ }
+ } else {
+ // https://doc.rust-lang.org/std/path/struct.Path.html#method.file_name
+ Err(ContextualError::new(ContextualErrorKind::InvalidPathError(
+ "Directory name terminates in \"..\"".to_string(),
+ )))
+ }
}
/// Creates a TAR archive of a folder, and returns it as a stream of bytes
@@ -97,44 +97,53 @@ fn tar(
src_dir: String,
inner_folder: String,
skip_symlinks: bool,
-) -> Result<Vec<u8>, errors::CompressionError> {
+) -> Result<Vec<u8>, ContextualError> {
let mut tar_builder = Builder::new(Vec::new());
tar_builder.follow_symlinks(!skip_symlinks);
// Recursively adds the content of src_dir into the archive stream
- tar_builder.append_dir_all(inner_folder, &src_dir).context(
- errors::CompressionErrorKind::TarBuildingError {
- message: format!(
- "failed to append the content of {} to the TAR archive",
- &src_dir
- ),
- },
- )?;
-
- let tar_content =
- tar_builder
- .into_inner()
- .context(errors::CompressionErrorKind::TarBuildingError {
- message: "failed to finish writing the TAR archive".to_string(),
- })?;
+ tar_builder
+ .append_dir_all(inner_folder, &src_dir)
+ .map_err(|e| {
+ ContextualError::new(ContextualErrorKind::IOError(
+ format!(
+ "Failed to append the content of {} to the TAR archive",
+ &src_dir
+ ),
+ e,
+ ))
+ })?;
+
+ let tar_content = tar_builder.into_inner().map_err(|e| {
+ ContextualError::new(ContextualErrorKind::IOError(
+ "Failed to finish writing the TAR archive".to_string(),
+ e,
+ ))
+ })?;
Ok(tar_content)
}
/// Compresses a stream of bytes using the GZIP algorithm, and returns the resulting stream
-fn gzip(mut data: &[u8]) -> Result<Vec<u8>, errors::CompressionError> {
- let mut encoder =
- Encoder::new(Vec::new()).context(errors::CompressionErrorKind::GZipBuildingError {
- message: "failed to create GZIP encoder".to_string(),
- })?;
- io::copy(&mut data, &mut encoder).context(errors::CompressionErrorKind::GZipBuildingError {
- message: "failed to write GZIP data".to_string(),
+fn gzip(mut data: &[u8]) -> Result<Vec<u8>, ContextualError> {
+ let mut encoder = Encoder::new(Vec::new()).map_err(|e| {
+ ContextualError::new(ContextualErrorKind::IOError(
+ "Failed to create GZIP encoder".to_string(),
+ e,
+ ))
+ })?;
+ io::copy(&mut data, &mut encoder).map_err(|e| {
+ ContextualError::new(ContextualErrorKind::IOError(
+ "Failed to write GZIP data".to_string(),
+ e,
+ ))
+ })?;
+ let data = encoder.finish().into_result().map_err(|e| {
+ ContextualError::new(ContextualErrorKind::IOError(
+ "Failed to write GZIP trailer".to_string(),
+ e,
+ ))
})?;
- let data = encoder.finish().into_result().context(
- errors::CompressionErrorKind::GZipBuildingError {
- message: "failed to write GZIP trailer".to_string(),
- },
- )?;
Ok(data)
}