mirror of
https://github.com/uutils/coreutils.git
synced 2026-05-06 07:26:38 -04:00
cksum: stop checksum computation from panicking over write error
This commit is contained in:
committed by
Sylvestre Ledru
parent
2b6ba09c4a
commit
dac86df588
@@ -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};
|
||||
@@ -213,7 +214,7 @@ pub fn checksum_main(
|
||||
line_ending,
|
||||
};
|
||||
|
||||
perform_checksum_computation(opts, files)?;
|
||||
perform_checksum_computation(io::stdout(), opts, files)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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é
|
||||
|
||||
@@ -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::{
|
||||
@@ -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(_)));
|
||||
|
||||
@@ -148,32 +149,40 @@ 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 {
|
||||
@@ -181,21 +190,22 @@ fn print_tagged_checksum(options: &ChecksumComputeOptions, filename: &OsStr, sum
|
||||
};
|
||||
|
||||
// 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 {
|
||||
@@ -203,10 +213,10 @@ fn print_untagged_checksum(
|
||||
};
|
||||
|
||||
// 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
|
||||
@@ -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();
|
||||
@@ -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,
|
||||
@@ -252,7 +267,7 @@ where
|
||||
continue;
|
||||
}
|
||||
};
|
||||
Box::new(file_buf) as Box<dyn Read>
|
||||
Box::new(file_buf) as Box<dyn io::Read>
|
||||
},
|
||||
);
|
||||
|
||||
@@ -275,30 +290,37 @@ 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 {
|
||||
w.flush().map_err(ChecksumError::Write)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user