diff --git a/src/archive/tar.rs b/src/archive/tar.rs index 6b7cd0c..3145bed 100644 --- a/src/archive/tar.rs +++ b/src/archive/tar.rs @@ -90,7 +90,17 @@ where if path.is_dir() { builder.append_dir(path, path)?; } else { - let mut file = fs::File::open(path)?; + let mut file = match fs::File::open(path) { + Ok(f) => f, + Err(e) => { + if e.kind() == std::io::ErrorKind::NotFound && utils::is_symlink(path) { + // This path is for a broken symlink + // We just ignore it + continue; + } + return Err(e.into()); + } + }; builder.append_file(path, file.file_mut()).map_err(|err| { FinalError::with_title("Could not create archive") .detail("Unexpected error while trying to read file") diff --git a/src/archive/zip.rs b/src/archive/zip.rs index 3d294eb..30dee2e 100644 --- a/src/archive/zip.rs +++ b/src/archive/zip.rs @@ -15,8 +15,8 @@ use crate::{ info, list::FileInArchive, utils::{ - cd_into_same_dir_as, concatenate_os_str_list, dir_is_empty, get_invalid_utf8_paths, strip_cur_dir, to_utf, - Bytes, + self, cd_into_same_dir_as, concatenate_os_str_list, dir_is_empty, get_invalid_utf8_paths, strip_cur_dir, + to_utf, Bytes, }, }; @@ -142,7 +142,17 @@ where // If a dir has files, the files are responsible for creating them. } else { writer.start_file(path.to_str().unwrap().to_owned(), options)?; - let file_bytes = fs::read(entry.path())?; + let file_bytes = match fs::read(entry.path()) { + Ok(b) => b, + Err(e) => { + if e.kind() == std::io::ErrorKind::NotFound && utils::is_symlink(path) { + // This path is for a broken symlink + // We just ignore it + continue; + } + return Err(e.into()); + } + }; writer.write_all(&*file_bytes)?; } } diff --git a/src/utils/fs.rs b/src/utils/fs.rs index 9adc946..ae94097 100644 --- a/src/utils/fs.rs +++ b/src/utils/fs.rs @@ -124,3 +124,10 @@ pub fn try_infer_extension(path: &Path) -> Option { None } } + +/// Returns true if a path is a symlink. +/// This is the same as the nightly https://doc.rust-lang.org/std/path/struct.Path.html#method.is_symlink +// Useful to detect broken symlinks when compressing. (So we can safely ignore them) +pub fn is_symlink(path: &Path) -> bool { + fs::symlink_metadata(path).map(|m| m.file_type().is_symlink()).unwrap_or(false) +} diff --git a/src/utils/mod.rs b/src/utils/mod.rs index d7b7aad..b863186 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -9,7 +9,9 @@ mod fs; mod question; pub use formatting::{concatenate_os_str_list, nice_directory_display, strip_cur_dir, to_utf, Bytes}; -pub use fs::{cd_into_same_dir_as, clear_path, create_dir_if_non_existent, dir_is_empty, try_infer_extension}; +pub use fs::{ + cd_into_same_dir_as, clear_path, create_dir_if_non_existent, dir_is_empty, is_symlink, try_infer_extension, +}; pub use question::{ create_or_ask_overwrite, user_wants_to_continue_compressing, user_wants_to_continue_decompressing, user_wants_to_overwrite, QuestionPolicy,