Skip to content

Commit

Permalink
fix STDIN syncrhonization problems
Browse files Browse the repository at this point in the history
  • Loading branch information
marcospb19 committed Mar 16, 2024
1 parent eefa9bd commit 4d42ca3
Show file tree
Hide file tree
Showing 7 changed files with 61 additions and 30 deletions.
12 changes: 9 additions & 3 deletions src/commands/compress.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::{
archive,
commands::warn_user_about_loading_zip_in_memory,
extension::{split_first_compression_format, CompressionFormat::*, Extension},
utils::{user_wants_to_continue, FileVisibilityPolicy},
utils::{io::lock_and_flush_output_stdio, user_wants_to_continue, FileVisibilityPolicy},
QuestionAction, QuestionPolicy, BUFFER_CAPACITY,
};

Expand Down Expand Up @@ -104,8 +104,11 @@ pub fn compress_files(
}
Zip => {
if !formats.is_empty() {
warn_user_about_loading_zip_in_memory();
// Locking necessary to guarantee that warning and question
// messages stay adjacent
let _locks = lock_and_flush_output_stdio();

warn_user_about_loading_zip_in_memory();
if !user_wants_to_continue(output_path, question_policy, QuestionAction::Compression)? {
return Ok(false);
}
Expand All @@ -132,8 +135,11 @@ pub fn compress_files(
}
SevenZip => {
if !formats.is_empty() {
warn_user_about_loading_sevenz_in_memory();
// Locking necessary to guarantee that warning and question
// messages stay adjacent
let _locks = lock_and_flush_output_stdio();

warn_user_about_loading_sevenz_in_memory();
if !user_wants_to_continue(output_path, question_policy, QuestionAction::Compression)? {
return Ok(false);
}
Expand Down
14 changes: 11 additions & 3 deletions src/commands/decompress.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ use crate::{
CompressionFormat::{self, *},
Extension,
},
utils::{self, logger::info_accessible, nice_directory_display, user_wants_to_continue},
utils::{
self, io::lock_and_flush_output_stdio, logger::info_accessible, nice_directory_display, user_wants_to_continue,
},
QuestionAction, QuestionPolicy, BUFFER_CAPACITY,
};

Expand Down Expand Up @@ -122,8 +124,11 @@ pub fn decompress_file(
}
Zip => {
if formats.len() > 1 {
warn_user_about_loading_zip_in_memory();
// Locking necessary to guarantee that warning and question
// messages stay adjacent
let _locks = lock_and_flush_output_stdio();

warn_user_about_loading_zip_in_memory();
if !user_wants_to_continue(input_file_path, question_policy, QuestionAction::Decompression)? {
return Ok(());
}
Expand Down Expand Up @@ -169,8 +174,11 @@ pub fn decompress_file(
}
SevenZip => {
if formats.len() > 1 {
warn_user_about_loading_sevenz_in_memory();
// Locking necessary to guarantee that warning and question
// messages stay adjacent
let _locks = lock_and_flush_output_stdio();

warn_user_about_loading_sevenz_in_memory();
if !user_wants_to_continue(input_file_path, question_policy, QuestionAction::Decompression)? {
return Ok(());
}
Expand Down
11 changes: 9 additions & 2 deletions src/commands/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::{
commands::warn_user_about_loading_zip_in_memory,
extension::CompressionFormat::{self, *},
list::{self, FileInArchive, ListOptions},
utils::user_wants_to_continue,
utils::{io::lock_and_flush_output_stdio, user_wants_to_continue},
QuestionAction, QuestionPolicy, BUFFER_CAPACITY,
};

Expand Down Expand Up @@ -65,8 +65,11 @@ pub fn list_archive_contents(
Tar => Box::new(crate::archive::tar::list_archive(tar::Archive::new(reader))),
Zip => {
if formats.len() > 1 {
warn_user_about_loading_zip_in_memory();
// Locking necessary to guarantee that warning and question
// messages stay adjacent
let _locks = lock_and_flush_output_stdio();

warn_user_about_loading_zip_in_memory();
if !user_wants_to_continue(archive_path, question_policy, QuestionAction::Decompression)? {
return Ok(());
}
Expand Down Expand Up @@ -94,6 +97,10 @@ pub fn list_archive_contents(
}
SevenZip => {
if formats.len() > 1 {
// Locking necessary to guarantee that warning and question
// messages stay adjacent
let _locks = lock_and_flush_output_stdio();

warn_user_about_loading_zip_in_memory();
if !user_wants_to_continue(archive_path, question_policy, QuestionAction::Decompression)? {
return Ok(());
Expand Down
26 changes: 11 additions & 15 deletions src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,32 +16,28 @@ use crate::{
error::{Error, FinalError},
extension::{self, parse_format},
list::ListOptions,
utils::{
self,
logger::{info_accessible, warning},
to_utf, EscapedPathDisplay, FileVisibilityPolicy,
},
utils::{self, colors::*, logger::info_accessible, to_utf, EscapedPathDisplay, FileVisibilityPolicy},
CliArgs, QuestionPolicy,
};

/// Warn the user that (de)compressing this .zip archive might freeze their system.
fn warn_user_about_loading_zip_in_memory() {
const ZIP_IN_MEMORY_LIMITATION_WARNING: &str = "\n\
\tThe format '.zip' is limited and cannot be (de)compressed using encoding streams.\n\
\tWhen using '.zip' with other formats, (de)compression must be done in-memory\n\
\tCareful, you might run out of RAM if the archive is too large!";
const ZIP_IN_MEMORY_LIMITATION_WARNING: &str = "\n \
The format '.zip' is limited by design and cannot be (de)compressed with encoding streams.\n \
When chaining '.zip' with other formats, all (de)compression needs to be done in-memory\n \
Careful, you might run out of RAM if the archive is too large!";

warning(ZIP_IN_MEMORY_LIMITATION_WARNING.to_string());
eprintln!("{}[WARNING]{}: {ZIP_IN_MEMORY_LIMITATION_WARNING}", *ORANGE, *RESET);
}

/// Warn the user that (de)compressing this .7z archive might freeze their system.
fn warn_user_about_loading_sevenz_in_memory() {
const SEVENZ_IN_MEMORY_LIMITATION_WARNING: &str = "\n\
\tThe format '.7z' is limited and cannot be (de)compressed using encoding streams.\n\
\tWhen using '.7z' with other formats, (de)compression must be done in-memory\n\
\tCareful, you might run out of RAM if the archive is too large!";
const SEVENZ_IN_MEMORY_LIMITATION_WARNING: &str = "\n \
The format '.7z' is limited by design and cannot be (de)compressed with encoding streams.\n \
When chaining '.7z' with other formats, all (de)compression needs to be done in-memory\n \
Careful, you might run out of RAM if the archive is too large!";

warning(SEVENZ_IN_MEMORY_LIMITATION_WARNING.to_string());
eprintln!("{}[WARNING]{}: {SEVENZ_IN_MEMORY_LIMITATION_WARNING}", *ORANGE, *RESET);
}

/// This function checks what command needs to be run and performs A LOT of ahead-of-time checks
Expand Down
12 changes: 12 additions & 0 deletions src/utils/io.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
use std::io::{self, stderr, stdout, StderrLock, StdoutLock, Write};

type StdioOutputLocks = (StdoutLock<'static>, StderrLock<'static>);

pub fn lock_and_flush_output_stdio() -> io::Result<StdioOutputLocks> {
let mut stdout = stdout().lock();
stdout.flush()?;
let mut stderr = stderr().lock();
stderr.flush()?;

Ok((stdout, stderr))
}
1 change: 1 addition & 0 deletions src/utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pub mod colors;
mod file_visibility;
mod formatting;
mod fs;
pub mod io;
pub mod logger;
mod question;

Expand Down
15 changes: 8 additions & 7 deletions src/utils/question.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
use std::{
borrow::Cow,
io::{self, Write},
io::{stdin, BufRead},
path::Path,
};

Expand All @@ -15,7 +15,7 @@ use super::{strip_cur_dir, to_utf};
use crate::{
accessible::is_running_in_accessible_mode,
error::{Error, FinalError, Result},
utils::{self, colors},
utils::{self, colors, io::lock_and_flush_output_stdio},
};

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
Expand Down Expand Up @@ -121,10 +121,13 @@ impl<'a> Confirmation<'a> {
(Some(placeholder), Some(subs)) => Cow::Owned(self.prompt.replace(placeholder, subs)),
};

let _locks = lock_and_flush_output_stdio()?;
let mut stdin_lock = stdin().lock();

// Ask the same question to end while no valid answers are given
loop {
if is_running_in_accessible_mode() {
print!(
eprintln!(
"{} {}yes{}/{}no{}: ",
message,
*colors::GREEN,
Expand All @@ -133,7 +136,7 @@ impl<'a> Confirmation<'a> {
*colors::RESET
);
} else {
print!(
eprintln!(
"{} [{}Y{}/{}n{}] ",
message,
*colors::GREEN,
Expand All @@ -142,11 +145,9 @@ impl<'a> Confirmation<'a> {
*colors::RESET
);
}
let _stdout_lock = io::stdout().lock();
io::stdout().flush()?;

let mut answer = String::new();
let bytes_read = io::stdin().read_line(&mut answer)?;
let bytes_read = stdin_lock.read_line(&mut answer)?;

if bytes_read == 0 {
let error = FinalError::with_title("Unexpected EOF when asking question.")
Expand Down

0 comments on commit 4d42ca3

Please sign in to comment.