From f8acb617778557838877f358aac614800853a871 Mon Sep 17 00:00:00 2001 From: Crypto-Spartan Date: Tue, 7 Dec 2021 21:01:43 +0000 Subject: [PATCH 1/3] Fix inconsistent zip compression and decompression memory usage warnings --- src/commands.rs | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/src/commands.rs b/src/commands.rs index f403c8b..24a108d 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -347,14 +347,10 @@ fn compress_files(files: Vec, formats: Vec, output_file: fs: writer.flush()?; } Zip => { - eprintln!("{yellow}Warning:{reset}", yellow = *colors::YELLOW, reset = *colors::RESET); - eprintln!("\tCompressing .zip entirely in memory."); - eprintln!("\tIf the file is too big, your PC might freeze!"); - eprintln!( - "\tThis is a limitation for formats like '{}'.", - formats.iter().map(|format| format.to_string()).collect::() - ); - eprintln!("\tThe design of .zip makes it impossible to compress via stream."); + eprintln!("{orange}[WARNING]{reset}", orange = *colors::ORANGE, reset = *colors::RESET); + eprintln!("\tThere is a limitation for .zip archives with extra extensions. (e.g. .zip.gz)\ + \n\tThe design of .zip makes it impossible to compress via stream, so it must be done entirely in memory.\ + \n\tBy compressing .zip with extra compression formats, you can run out of RAM if the file is too large!"); let mut vec_buffer = io::Cursor::new(vec![]); @@ -505,12 +501,10 @@ fn decompress_file( }; } Zip => { - eprintln!("Compressing first into .zip."); - eprintln!("Warning: .zip archives with extra extensions have a downside."); - eprintln!( - "The only way is loading everything into the RAM while compressing, and then write everything down." - ); - eprintln!("this means that by compressing .zip with extra compression formats, you can run out of RAM if the file is too large!"); + eprintln!("{orange}[WARNING]{reset}", orange = *colors::ORANGE, reset = *colors::RESET); + eprintln!("\tThere is a limitation for .zip archives with extra extensions. (e.g. .zip.gz)\ + \n\tThe design of .zip makes it impossible to compress via stream, so it must be done entirely in memory.\ + \n\tBy compressing .zip with extra compression formats, you can run out of RAM if the file is too large!"); let mut vec = vec![]; io::copy(&mut reader, &mut vec)?; @@ -593,10 +587,10 @@ fn list_archive_contents( let files = match formats[0] { Tar => crate::archive::tar::list_archive(reader)?, Zip => { - eprintln!("Listing files from zip archive."); - eprintln!("Warning: .zip archives with extra extensions have a downside."); - eprintln!("The only way is loading everything into the RAM while compressing, and then reading the archive contents."); - eprintln!("this means that by compressing .zip with extra compression formats, you can run out of RAM if the file is too large!"); + eprintln!("{orange}[WARNING]{reset}", orange = *colors::ORANGE, reset = *colors::RESET); + eprintln!("\tThere is a limitation for .zip archives with extra extensions. (e.g. .zip.gz)\ + \n\tThe design of .zip makes it impossible to compress via stream, so it must be done entirely in memory.\ + \n\tBy compressing .zip with extra compression formats, you can run out of RAM if the file is too large!"); let mut vec = vec![]; io::copy(&mut reader, &mut vec)?; From 17d9f172779b69ac4e6cb63de21836a713fa49a6 Mon Sep 17 00:00:00 2001 From: Crypto-Spartan Date: Tue, 7 Dec 2021 21:40:03 +0000 Subject: [PATCH 2/3] Ask user to continue after .zip warning is shown --- src/commands.rs | 30 ++++++++++++++++++++++++++---- src/utils/mod.rs | 20 +++++++++++++++----- src/utils/question.rs | 14 ++++++++++++++ 3 files changed, 55 insertions(+), 9 deletions(-) diff --git a/src/commands.rs b/src/commands.rs index 24a108d..a4c5bd4 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -24,7 +24,7 @@ use crate::{ progress::Progress, utils::{ self, concatenate_os_str_list, dir_is_empty, nice_directory_display, to_utf, try_infer_extension, - user_wants_to_continue_decompressing, + user_wants_to_continue_compressing, user_wants_to_continue_decompressing, }, warning, Opts, QuestionPolicy, Subcommand, }; @@ -157,7 +157,7 @@ pub fn run(args: Opts, question_policy: QuestionPolicy) -> crate::Result<()> { formats = new_formats; } } - let compress_result = compress_files(files, formats, output_file); + let compress_result = compress_files(files, formats, output_file, &output_path, question_policy); // If any error occurred, delete incomplete file if compress_result.is_err() { @@ -268,7 +268,7 @@ pub fn run(args: Opts, question_policy: QuestionPolicy) -> crate::Result<()> { println!(); } let formats = formats.iter().flat_map(Extension::iter).map(Clone::clone).collect(); - list_archive_contents(archive_path, formats, list_options)?; + list_archive_contents(archive_path, formats, list_options, question_policy)?; } } } @@ -280,7 +280,13 @@ pub fn run(args: Opts, question_policy: QuestionPolicy) -> crate::Result<()> { // files are the list of paths to be compressed: ["dir/file1.txt", "dir/file2.txt"] // formats contains each format necessary for compression, example: [Tar, Gz] (in compression order) // output_file is the resulting compressed file name, example: "compressed.tar.gz" -fn compress_files(files: Vec, formats: Vec, output_file: fs::File) -> crate::Result<()> { +fn compress_files( + files: Vec, + formats: Vec, + output_file: fs::File, + output_dir: &Path, + question_policy: QuestionPolicy +) -> crate::Result<()> { // The next lines are for displaying the progress bar // If the input files contain a directory, then the total size will be underestimated let (total_input_size, precise) = files @@ -352,6 +358,11 @@ fn compress_files(files: Vec, formats: Vec, output_file: fs: \n\tThe design of .zip makes it impossible to compress via stream, so it must be done entirely in memory.\ \n\tBy compressing .zip with extra compression formats, you can run out of RAM if the file is too large!"); + // give user the option to continue compressing after warning is shown + if !user_wants_to_continue_compressing(output_dir, question_policy)? { + return Ok(()); + } + let mut vec_buffer = io::Cursor::new(vec![]); let current_position_fn = { @@ -506,6 +517,11 @@ fn decompress_file( \n\tThe design of .zip makes it impossible to compress via stream, so it must be done entirely in memory.\ \n\tBy compressing .zip with extra compression formats, you can run out of RAM if the file is too large!"); + // give user the option to continue decompressing after warning is shown + if !user_wants_to_continue_decompressing(input_file_path, question_policy)? { + return Ok(()); + } + let mut vec = vec![]; io::copy(&mut reader, &mut vec)?; let zip_archive = zip::ZipArchive::new(io::Cursor::new(vec))?; @@ -546,6 +562,7 @@ fn list_archive_contents( archive_path: &Path, formats: Vec, list_options: ListOptions, + question_policy: QuestionPolicy ) -> crate::Result<()> { let reader = fs::File::open(&archive_path)?; @@ -592,6 +609,11 @@ fn list_archive_contents( \n\tThe design of .zip makes it impossible to compress via stream, so it must be done entirely in memory.\ \n\tBy compressing .zip with extra compression formats, you can run out of RAM if the file is too large!"); + // give user the option to continue decompressing after warning is shown + if !user_wants_to_continue_decompressing(archive_path, question_policy)? { + return Ok(()); + } + let mut vec = vec![]; io::copy(&mut reader, &mut vec)?; let zip_archive = zip::ZipArchive::new(io::Cursor::new(vec))?; diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 4c09cd5..83f58b9 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -8,12 +8,22 @@ mod formatting; 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 question::{ - create_or_ask_overwrite, user_wants_to_continue_decompressing, user_wants_to_overwrite, QuestionPolicy, +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 question::{ + user_wants_to_continue_compressing, user_wants_to_continue_decompressing, + create_or_ask_overwrite, user_wants_to_overwrite, + QuestionPolicy +}; +pub use utf8::{ + get_invalid_utf8_paths, is_invalid_utf8 }; -pub use utf8::{get_invalid_utf8_paths, is_invalid_utf8}; mod utf8 { use std::{ffi::OsStr, path::PathBuf}; diff --git a/src/utils/question.rs b/src/utils/question.rs index 67094d5..e0d2cd5 100644 --- a/src/utils/question.rs +++ b/src/utils/question.rs @@ -63,6 +63,20 @@ pub fn create_or_ask_overwrite(path: &Path, question_policy: QuestionPolicy) -> } } +/// Check if QuestionPolicy flags were set, otherwise, ask the user if they want to continue compressing. +pub fn user_wants_to_continue_compressing(path: &Path, question_policy: QuestionPolicy) -> crate::Result { + match question_policy { + QuestionPolicy::AlwaysYes => Ok(true), + QuestionPolicy::AlwaysNo => Ok(false), + QuestionPolicy::Ask => { + let path = to_utf(strip_cur_dir(path)); + let path = Some(path.as_str()); + let placeholder = Some("FILE"); + Confirmation::new("Do you want to continue compressing 'FILE'?", placeholder).ask(path) + } + } +} + /// Check if QuestionPolicy flags were set, otherwise, ask the user if they want to continue decompressing. pub fn user_wants_to_continue_decompressing(path: &Path, question_policy: QuestionPolicy) -> crate::Result { match question_policy { From 250d2e231c65d1a2089d9856fd37b91465a0b5f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20M=2E=20Bezerra?= Date: Tue, 7 Dec 2021 23:25:21 -0300 Subject: [PATCH 3/3] Reformat code --- src/commands.rs | 22 ++++++++++++++-------- src/utils/mod.rs | 19 +++++-------------- 2 files changed, 19 insertions(+), 22 deletions(-) diff --git a/src/commands.rs b/src/commands.rs index a4c5bd4..20a4f45 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -285,7 +285,7 @@ fn compress_files( formats: Vec, output_file: fs::File, output_dir: &Path, - question_policy: QuestionPolicy + question_policy: QuestionPolicy, ) -> crate::Result<()> { // The next lines are for displaying the progress bar // If the input files contain a directory, then the total size will be underestimated @@ -354,9 +354,11 @@ fn compress_files( } Zip => { eprintln!("{orange}[WARNING]{reset}", orange = *colors::ORANGE, reset = *colors::RESET); - eprintln!("\tThere is a limitation for .zip archives with extra extensions. (e.g. .zip.gz)\ + eprintln!( + "\tThere is a limitation for .zip archives with extra extensions. (e.g. .zip.gz)\ \n\tThe design of .zip makes it impossible to compress via stream, so it must be done entirely in memory.\ - \n\tBy compressing .zip with extra compression formats, you can run out of RAM if the file is too large!"); + \n\tBy compressing .zip with extra compression formats, you can run out of RAM if the file is too large!" + ); // give user the option to continue compressing after warning is shown if !user_wants_to_continue_compressing(output_dir, question_policy)? { @@ -513,9 +515,11 @@ fn decompress_file( } Zip => { eprintln!("{orange}[WARNING]{reset}", orange = *colors::ORANGE, reset = *colors::RESET); - eprintln!("\tThere is a limitation for .zip archives with extra extensions. (e.g. .zip.gz)\ + eprintln!( + "\tThere is a limitation for .zip archives with extra extensions. (e.g. .zip.gz)\ \n\tThe design of .zip makes it impossible to compress via stream, so it must be done entirely in memory.\ - \n\tBy compressing .zip with extra compression formats, you can run out of RAM if the file is too large!"); + \n\tBy compressing .zip with extra compression formats, you can run out of RAM if the file is too large!" + ); // give user the option to continue decompressing after warning is shown if !user_wants_to_continue_decompressing(input_file_path, question_policy)? { @@ -562,7 +566,7 @@ fn list_archive_contents( archive_path: &Path, formats: Vec, list_options: ListOptions, - question_policy: QuestionPolicy + question_policy: QuestionPolicy, ) -> crate::Result<()> { let reader = fs::File::open(&archive_path)?; @@ -605,9 +609,11 @@ fn list_archive_contents( Tar => crate::archive::tar::list_archive(reader)?, Zip => { eprintln!("{orange}[WARNING]{reset}", orange = *colors::ORANGE, reset = *colors::RESET); - eprintln!("\tThere is a limitation for .zip archives with extra extensions. (e.g. .zip.gz)\ + eprintln!( + "\tThere is a limitation for .zip archives with extra extensions. (e.g. .zip.gz)\ \n\tThe design of .zip makes it impossible to compress via stream, so it must be done entirely in memory.\ - \n\tBy compressing .zip with extra compression formats, you can run out of RAM if the file is too large!"); + \n\tBy compressing .zip with extra compression formats, you can run out of RAM if the file is too large!" + ); // give user the option to continue decompressing after warning is shown if !user_wants_to_continue_decompressing(archive_path, question_policy)? { diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 83f58b9..d7b7aad 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -8,22 +8,13 @@ mod formatting; 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 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 question::{ - user_wants_to_continue_compressing, user_wants_to_continue_decompressing, - create_or_ask_overwrite, user_wants_to_overwrite, - QuestionPolicy -}; -pub use utf8::{ - get_invalid_utf8_paths, is_invalid_utf8 + create_or_ask_overwrite, user_wants_to_continue_compressing, user_wants_to_continue_decompressing, + user_wants_to_overwrite, QuestionPolicy, }; +pub use utf8::{get_invalid_utf8_paths, is_invalid_utf8}; mod utf8 { use std::{ffi::OsStr, path::PathBuf};