Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/uu/checksum_common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

use std::borrow::Borrow;
use std::ffi::OsString;
use std::io;

use clap::builder::ValueParser;
use clap::{Arg, ArgAction, ArgMatches, Command, ValueHint};
Expand Down Expand Up @@ -213,7 +214,7 @@ pub fn checksum_main(
line_ending,
};

perform_checksum_computation(opts, files)?;
perform_checksum_computation(io::stdout(), opts, files)?;

Ok(())
}
2 changes: 1 addition & 1 deletion src/uu/cksum/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.uucore::bin!(uu_cksum);

uucore::bin!(uu_cksum);
uucore::bin!(uu_cksum, no_flush);
1 change: 1 addition & 0 deletions src/uucore/locales/en-US.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ common-tip = tip
common-usage = Usage
common-help = help
common-version = version
common-write-error = write error

# Common clap error messages
clap-error-unexpected-argument = { $error_word }: unexpected argument '{ $arg }' found
Expand Down
1 change: 1 addition & 0 deletions src/uucore/locales/fr-FR.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ common-tip = conseil
common-usage = Utilisation
common-help = aide
common-version = version
common-write-error = erreur d'écriture

# Messages d'erreur clap communs
clap-error-unexpected-argument = { $error_word } : argument inattendu '{ $arg }' trouvé
Expand Down
103 changes: 63 additions & 40 deletions src/uucore/src/lib/features/checksum/compute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

use std::ffi::OsStr;
use std::fs::File;
use std::io::{self, BufReader, Read, Write};
use std::io;
use std::path::Path;

use crate::checksum::{
Expand Down Expand Up @@ -131,12 +131,13 @@ impl OutputFormat {
}
}

fn print_legacy_checksum(
fn write_legacy_checksum(
mut w: impl io::Write,
options: &ChecksumComputeOptions,
filename: &OsStr,
sum: &DigestOutput,
size: usize,
) {
) -> io::Result<()> {
debug_assert!(options.algo_kind.is_legacy());
debug_assert!(matches!(sum, DigestOutput::U16(_) | DigestOutput::Crc(_)));

Expand All @@ -148,65 +149,74 @@ fn print_legacy_checksum(

// Print the sum
match (options.algo_kind, sum) {
(SizedAlgoKind::Sysv, DigestOutput::U16(sum)) => print!(
(SizedAlgoKind::Sysv, DigestOutput::U16(sum)) => write!(
w,
"{prefix}{sum} {}",
size.div_ceil(options.algo_kind.bitlen()),
),
)?,
(SizedAlgoKind::Bsd, DigestOutput::U16(sum)) => {
// The BSD checksum output is 5 digit integer
let bsd_width = 5;
print!(
write!(
w,
"{prefix}{sum:0bsd_width$} {:bsd_width$}",
size.div_ceil(options.algo_kind.bitlen()),
);
)?;
}
(SizedAlgoKind::Crc | SizedAlgoKind::Crc32b, DigestOutput::Crc(sum)) => {
print!("{prefix}{sum} {size}");
write!(w, "{prefix}{sum} {size}")?;
}
(algo, output) => unreachable!("Bug: Invalid legacy checksum ({algo:?}, {output:?})"),
}

// Print the filename after a space if not stdin
if escaped_filename != "-" {
print!(" ");
let _dropped_result = io::stdout().write_all(escaped_filename.as_bytes());
write!(w, " ")?;
w.write_all(escaped_filename.as_bytes())?;
}
Ok(())
}

fn print_tagged_checksum(options: &ChecksumComputeOptions, filename: &OsStr, sum: &String) {
fn write_tagged_checksum(
mut w: impl io::Write,
options: &ChecksumComputeOptions,
filename: &OsStr,
sum: &String,
) -> io::Result<()> {
let (escaped_filename, prefix) = if options.line_ending == LineEnding::Nul {
(filename.to_string_lossy().to_string(), "")
} else {
escape_filename(filename)
};

// Print algo name and opening parenthesis.
print!("{prefix}{} (", options.algo_kind.to_tag());
write!(w, "{prefix}{} (", options.algo_kind.to_tag())?;

// Print filename
let _dropped_result = io::stdout().write_all(escaped_filename.as_bytes());
w.write_all(escaped_filename.as_bytes())?;

// Print closing parenthesis and sum
print!(") = {sum}");
write!(w, ") = {sum}")
}

fn print_untagged_checksum(
fn write_untagged_checksum(
mut w: impl io::Write,
options: &ChecksumComputeOptions,
filename: &OsStr,
sum: &String,
reading_mode: ReadingMode,
) {
) -> io::Result<()> {
let (escaped_filename, prefix) = if options.line_ending == LineEnding::Nul {
(filename.to_string_lossy().to_string(), "")
} else {
escape_filename(filename)
};

// Print checksum and reading mode flag
print!("{prefix}{sum} {}", reading_mode.as_char());
write!(w, "{prefix}{sum} {}", reading_mode.as_char())?;

// Print filename
let _dropped_result = io::stdout().write_all(escaped_filename.as_bytes());
w.write_all(escaped_filename.as_bytes())
}

/// Calculate checksum
Expand All @@ -215,8 +225,13 @@ fn print_untagged_checksum(
///
/// * `options` - CLI options for the assigning checksum algorithm
/// * `files` - A iterator of [`OsStr`] which is a bunch of files that are using for calculating checksum
pub fn perform_checksum_computation<'a, I>(options: ChecksumComputeOptions, files: I) -> UResult<()>
pub fn perform_checksum_computation<'a, W, I>(
mut w: W,
options: ChecksumComputeOptions,
files: I,
) -> UResult<()>
where
W: io::Write,
I: Iterator<Item = &'a OsStr>,
{
let mut files = files.peekable();
Expand All @@ -239,11 +254,11 @@ where
}

// Handle the file input
let mut file = BufReader::with_capacity(
let mut file = io::BufReader::with_capacity(
READ_BUFFER_SIZE,
if filename == "-" {
stdin_buf = io::stdin();
Box::new(stdin_buf) as Box<dyn Read>
Box::new(stdin_buf) as Box<dyn io::Read>
} else {
file_buf = match File::open(filepath) {
Ok(file) => file,
Expand All @@ -252,7 +267,7 @@ where
continue;
}
};
Box::new(file_buf) as Box<dyn Read>
Box::new(file_buf) as Box<dyn io::Read>
},
);

Expand All @@ -275,30 +290,38 @@ where
match options.output_format {
OutputFormat::Raw => {
// Cannot handle multiple files anyway, output immediately.
digest_output.write_raw(io::stdout())?;
digest_output
.write_raw(&mut w)
.map_err(ChecksumError::Write)?;
return Ok(());
}
OutputFormat::Legacy => {
print_legacy_checksum(&options, filename, &digest_output, sz);
}
OutputFormat::Tagged(digest_format) => {
print_tagged_checksum(
&options,
filename,
&encode_sum(digest_output, digest_format)?,
);
}
OutputFormat::Untagged(digest_format, reading_mode) => {
print_untagged_checksum(
&options,
filename,
&encode_sum(digest_output, digest_format)?,
reading_mode,
);
write_legacy_checksum(&mut w, &options, filename, &digest_output, sz)
.map_err(ChecksumError::Write)?;
}
OutputFormat::Tagged(digest_format) => write_tagged_checksum(
&mut w,
&options,
filename,
&encode_sum(digest_output, digest_format)?,
)
.map_err(ChecksumError::Write)?,
OutputFormat::Untagged(digest_format, reading_mode) => write_untagged_checksum(
&mut w,
&options,
filename,
&encode_sum(digest_output, digest_format)?,
reading_mode,
)
.map_err(ChecksumError::Write)?,
}

print!("{}", options.line_ending);
write!(w, "{}", options.line_ending).map_err(ChecksumError::Write)?;
}

if options.line_ending != LineEnding::Newline {
// Flush the writer if we didn't write newlines.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess the comment is redundant now

w.flush().map_err(ChecksumError::Write)?;
}
Ok(())
}
8 changes: 4 additions & 4 deletions src/uucore/src/lib/features/checksum/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ use std::num::IntErrorKind;
use os_display::Quotable;
use thiserror::Error;

use crate::error::{UError, UResult};
use crate::show_error;
use crate::error::{UError, UResult, strip_errno};
use crate::sum::{
Blake2b, Blake3, Bsd, CRC32B, Crc, Digest, DigestOutput, DigestWriter, Md5, Sha1, Sha3_224,
Sha3_256, Sha3_384, Sha3_512, Sha224, Sha256, Sha384, Sha512, Shake128, Shake256, Sm3, SysV,
};
use crate::{show_error, translate};

pub mod compute;
pub mod validate;
Expand Down Expand Up @@ -432,8 +432,8 @@ pub enum ChecksumError {
NeedAlgorithmToHash,
#[error("unknown algorithm: {0}: clap should have prevented this case")]
UnknownAlgorithm(String),
#[error("")]
Io(#[from] io::Error),
#[error("{}: {}", translate!("common-write-error"), strip_errno(.0))]
Write(io::Error),
}

impl UError for ChecksumError {
Expand Down
29 changes: 20 additions & 9 deletions src/uucore/src/lib/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,13 +181,9 @@ pub fn get_canonical_util_name(util_name: &str) -> &str {
}
}

/// Execute utility code for `util`.
///
/// This macro expands to a main function that invokes the `uumain` function in `util`
/// Exits with code returned by `uumain`.
#[macro_export]
macro_rules! bin {
($util:ident) => {
macro_rules! bin_inner {
($util:ident, $post:expr) => {
pub fn main() {
use std::io::Write;
use uucore::locale;
Expand All @@ -211,13 +207,28 @@ macro_rules! bin {

// execute utility code
let code = $util::uumain(uucore::args_os());
$post

std::process::exit(code);
}
};
}
/// Execute utility code for `util`.
///
/// This macro expands to a main function that invokes the `uumain` function in `util`
/// Exits with code returned by `uumain`.
#[macro_export]
macro_rules! bin {
($util:ident, no_flush) => {
::uucore::bin_inner! {$util, {}}
};
($util:ident) => {
::uucore::bin_inner! {$util, {
// (defensively) flush stdout for utility prior to exit; see <https://github.com/rust-lang/rust/issues/23818>
if let Err(e) = std::io::stdout().flush() {
eprintln!("Error flushing stdout: {e}");
}

std::process::exit(code);
}
}}
};
}

Expand Down
Loading