diff --git a/src/archive/tar.rs b/src/archive/tar.rs index 5aadb462d..c71cdbbfc 100644 --- a/src/archive/tar.rs +++ b/src/archive/tar.rs @@ -34,6 +34,13 @@ pub fn unpack_archive( continue; } + if file_path.is_dir() { + // ToDo: Maybe we should emphasise that `file_path` is a directory and everything inside it will be gone? + fs::remove_dir_all(&file_path)?; + } else if file_path.is_file() { + fs::remove_file(&file_path)?; + } + file.unpack_in(output_folder)?; info!("{:?} extracted. ({})", output_folder.join(file.path()?), Bytes::new(file.size())); diff --git a/src/archive/zip.rs b/src/archive/zip.rs index b62afd777..908512938 100644 --- a/src/archive/zip.rs +++ b/src/archive/zip.rs @@ -41,6 +41,13 @@ where continue; } + if file_path.is_dir() { + // ToDo: Maybe we should emphasise that `file_path` is a directory and everything inside it will be gone? + fs::remove_dir_all(&file_path)?; + } else if file_path.is_file() { + fs::remove_file(&file_path)?; + } + check_for_comments(&file); match (&*file.name()).ends_with('/') { diff --git a/src/commands.rs b/src/commands.rs index 7467772d6..c07015c03 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -326,8 +326,12 @@ fn decompress_file( Gzip | Bzip | Lzma | Zstd => { reader = chain_reader_decoder(&formats[0].compression_formats[0], reader)?; - // TODO: improve error treatment - let mut writer = fs::File::create(&output_path)?; + let writer = utils::create_or_ask_overwrite(&output_path, question_policy)?; + if writer.is_none() { + // Means that the user doesn't want to overwrite + return Ok(()); + } + let mut writer = writer.unwrap(); io::copy(&mut reader, &mut writer)?; files_unpacked = vec![output_path]; diff --git a/src/utils.rs b/src/utils.rs index e8aaf524b..e571bf8e4 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -3,13 +3,35 @@ use std::{ cmp, env, ffi::OsStr, + io, path::Component, path::{Path, PathBuf}, }; use fs_err as fs; -use crate::{dialogs::Confirmation, info}; +use crate::{dialogs::Confirmation, info, Error}; + +/// Create the file if it doesn't exist and if it does then ask to overwrite it. +/// If the user doesn't want to overwrite then we return [`Ok(None)`] +pub fn create_or_ask_overwrite(path: &Path, question_policy: QuestionPolicy) -> Result, Error> { + match fs::OpenOptions::new().write(true).create_new(true).open(path) { + Ok(w) => Ok(Some(w)), + Err(e) if e.kind() == io::ErrorKind::AlreadyExists => { + if user_wants_to_overwrite(path, question_policy)? { + if path.is_dir() { + // We can't just use `fs::File::create(&path)` because it would return io::ErrorKind::IsADirectory + // ToDo: Maybe we should emphasise that `path` is a directory and everything inside it will be gone? + fs::remove_dir_all(path)?; + } + Ok(Some(fs::File::create(path)?)) + } else { + Ok(None) + } + } + Err(e) => Err(Error::from(e)), + } +} /// Checks if the given path represents an empty directory. pub fn dir_is_empty(dir_path: &Path) -> bool {