mirror of
https://github.com/uutils/coreutils.git
synced 2025-07-07 21:45:01 +00:00
cksum: Fix file quoting on stderr (#8272)
Some checks are pending
CICD / Style/cargo-deny (push) Waiting to run
CICD / Build (push) Blocked by required conditions
CICD / Style/deps (push) Waiting to run
CICD / Documentation/warnings (push) Waiting to run
CICD / MinRustV (push) Waiting to run
CICD / Dependencies (push) Waiting to run
CICD / Build/Makefile (push) Blocked by required conditions
CICD / Build/stable (push) Blocked by required conditions
CICD / Build/nightly (push) Blocked by required conditions
CICD / Binary sizes (push) Blocked by required conditions
CICD / Tests/BusyBox test suite (push) Blocked by required conditions
CICD / Tests/Toybox test suite (push) Blocked by required conditions
CICD / Code Coverage (push) Waiting to run
CICD / Separate Builds (push) Waiting to run
CICD / Test all features separately (push) Blocked by required conditions
CICD / Build/SELinux (push) Blocked by required conditions
GnuTests / Run GNU tests (push) Waiting to run
Android / Test builds (push) Waiting to run
Code Quality / Style/format (push) Waiting to run
Code Quality / Style/lint (push) Waiting to run
Code Quality / Style/spelling (push) Waiting to run
Code Quality / Style/toml (push) Waiting to run
Code Quality / Style/Python (push) Waiting to run
Code Quality / Pre-commit hooks (push) Waiting to run
FreeBSD / Style and Lint (push) Waiting to run
FreeBSD / Tests (push) Waiting to run
Some checks are pending
CICD / Style/cargo-deny (push) Waiting to run
CICD / Build (push) Blocked by required conditions
CICD / Style/deps (push) Waiting to run
CICD / Documentation/warnings (push) Waiting to run
CICD / MinRustV (push) Waiting to run
CICD / Dependencies (push) Waiting to run
CICD / Build/Makefile (push) Blocked by required conditions
CICD / Build/stable (push) Blocked by required conditions
CICD / Build/nightly (push) Blocked by required conditions
CICD / Binary sizes (push) Blocked by required conditions
CICD / Tests/BusyBox test suite (push) Blocked by required conditions
CICD / Tests/Toybox test suite (push) Blocked by required conditions
CICD / Code Coverage (push) Waiting to run
CICD / Separate Builds (push) Waiting to run
CICD / Test all features separately (push) Blocked by required conditions
CICD / Build/SELinux (push) Blocked by required conditions
GnuTests / Run GNU tests (push) Waiting to run
Android / Test builds (push) Waiting to run
Code Quality / Style/format (push) Waiting to run
Code Quality / Style/lint (push) Waiting to run
Code Quality / Style/spelling (push) Waiting to run
Code Quality / Style/toml (push) Waiting to run
Code Quality / Style/Python (push) Waiting to run
Code Quality / Pre-commit hooks (push) Waiting to run
FreeBSD / Style and Lint (push) Waiting to run
FreeBSD / Tests (push) Waiting to run
* cksum: handle escaping in stderr for file errors * uutests: Minor fix and stdX_contains_bytes feature * test(cksum): add test for stderr escaping
This commit is contained in:
parent
c64adee068
commit
56ce0e28ad
5 changed files with 91 additions and 14 deletions
|
@ -93,7 +93,7 @@ default = []
|
||||||
# * non-default features
|
# * non-default features
|
||||||
backup-control = []
|
backup-control = []
|
||||||
colors = []
|
colors = []
|
||||||
checksum = ["data-encoding", "sum"]
|
checksum = ["data-encoding", "quoting-style", "sum"]
|
||||||
encoding = ["data-encoding", "data-encoding-macro", "z85"]
|
encoding = ["data-encoding", "data-encoding-macro", "z85"]
|
||||||
entries = ["libc"]
|
entries = ["libc"]
|
||||||
extendedbigdecimal = ["bigdecimal", "num-traits"]
|
extendedbigdecimal = ["bigdecimal", "num-traits"]
|
||||||
|
|
|
@ -18,7 +18,9 @@ use std::{
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
error::{FromIo, UError, UResult, USimpleError},
|
error::{FromIo, UError, UResult, USimpleError},
|
||||||
os_str_as_bytes, os_str_from_bytes, read_os_string_lines, show, show_error, show_warning_caps,
|
os_str_as_bytes, os_str_from_bytes,
|
||||||
|
quoting_style::{QuotingStyle, locale_aware_escape_name},
|
||||||
|
read_os_string_lines, show, show_error, show_warning_caps,
|
||||||
sum::{
|
sum::{
|
||||||
Blake2b, Blake3, Bsd, CRC32B, Crc, Digest, DigestWriter, Md5, Sha1, Sha3_224, Sha3_256,
|
Blake2b, Blake3, Bsd, CRC32B, Crc, Digest, DigestWriter, Md5, Sha1, Sha3_224, Sha3_256,
|
||||||
Sha3_384, Sha3_512, Sha224, Sha256, Sha384, Sha512, Shake128, Shake256, Sm3, SysV,
|
Sha3_384, Sha3_512, Sha224, Sha256, Sha384, Sha512, Shake128, Shake256, Sm3, SysV,
|
||||||
|
@ -734,7 +736,7 @@ fn get_file_to_check(
|
||||||
opts: ChecksumOptions,
|
opts: ChecksumOptions,
|
||||||
) -> Result<Box<dyn Read>, LineCheckError> {
|
) -> Result<Box<dyn Read>, LineCheckError> {
|
||||||
let filename_bytes = os_str_as_bytes(filename).expect("UTF-8 error");
|
let filename_bytes = os_str_as_bytes(filename).expect("UTF-8 error");
|
||||||
let filename_lossy = String::from_utf8_lossy(filename_bytes);
|
|
||||||
if filename == "-" {
|
if filename == "-" {
|
||||||
Ok(Box::new(stdin())) // Use stdin if "-" is specified in the checksum file
|
Ok(Box::new(stdin())) // Use stdin if "-" is specified in the checksum file
|
||||||
} else {
|
} else {
|
||||||
|
@ -747,15 +749,23 @@ fn get_file_to_check(
|
||||||
opts.verbose,
|
opts.verbose,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
let print_error = |err: io::Error| {
|
||||||
|
show!(err.map_err_context(|| {
|
||||||
|
locale_aware_escape_name(filename, QuotingStyle::SHELL_ESCAPE)
|
||||||
|
// This is non destructive thanks to the escaping
|
||||||
|
.to_string_lossy()
|
||||||
|
.to_string()
|
||||||
|
}));
|
||||||
|
};
|
||||||
match File::open(filename) {
|
match File::open(filename) {
|
||||||
Ok(f) => {
|
Ok(f) => {
|
||||||
if f.metadata()
|
if f.metadata()
|
||||||
.map_err(|_| LineCheckError::CantOpenFile)?
|
.map_err(|_| LineCheckError::CantOpenFile)?
|
||||||
.is_dir()
|
.is_dir()
|
||||||
{
|
{
|
||||||
show!(USimpleError::new(
|
print_error(io::Error::new(
|
||||||
1,
|
io::ErrorKind::IsADirectory,
|
||||||
format!("{filename_lossy}: Is a directory")
|
"Is a directory",
|
||||||
));
|
));
|
||||||
// also regarded as a failed open
|
// also regarded as a failed open
|
||||||
failed_open();
|
failed_open();
|
||||||
|
@ -767,7 +777,7 @@ fn get_file_to_check(
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
if !opts.ignore_missing {
|
if !opts.ignore_missing {
|
||||||
// yes, we have both stderr and stdout here
|
// yes, we have both stderr and stdout here
|
||||||
show!(err.map_err_context(|| filename_lossy.to_string()));
|
print_error(err);
|
||||||
failed_open();
|
failed_open();
|
||||||
}
|
}
|
||||||
// we could not open the file but we want to continue
|
// we could not open the file but we want to continue
|
||||||
|
|
|
@ -1453,7 +1453,7 @@ fn test_check_trailing_space_fails() {
|
||||||
/// in checksum files.
|
/// in checksum files.
|
||||||
/// These tests are excluded from Windows because it does not provide any safe
|
/// These tests are excluded from Windows because it does not provide any safe
|
||||||
/// conversion between `OsString` and byte sequences for non-utf-8 strings.
|
/// conversion between `OsString` and byte sequences for non-utf-8 strings.
|
||||||
mod check_utf8 {
|
mod check_encoding {
|
||||||
|
|
||||||
// This test should pass on linux and macos.
|
// This test should pass on linux and macos.
|
||||||
#[cfg(not(windows))]
|
#[cfg(not(windows))]
|
||||||
|
@ -1467,15 +1467,12 @@ mod check_utf8 {
|
||||||
BLAKE2b (empty) = eGoC90IBWQPGxv2FJVLScpEvR0DhWEdhiobiF/cfVBnSXhAxr+5YUxOJZESTTrBLkDpoWxRIt1XVb3Aa/pvizg==\n"
|
BLAKE2b (empty) = eGoC90IBWQPGxv2FJVLScpEvR0DhWEdhiobiF/cfVBnSXhAxr+5YUxOJZESTTrBLkDpoWxRIt1XVb3Aa/pvizg==\n"
|
||||||
;
|
;
|
||||||
|
|
||||||
let scene = TestScenario::new(util_name!());
|
let (at, mut cmd) = at_and_ucmd!();
|
||||||
let at = &scene.fixtures;
|
|
||||||
|
|
||||||
at.touch("empty");
|
at.touch("empty");
|
||||||
at.write_bytes("check", hashes);
|
at.write_bytes("check", hashes);
|
||||||
|
|
||||||
scene
|
cmd.arg("--check")
|
||||||
.ucmd()
|
|
||||||
.arg("--check")
|
|
||||||
.arg(at.subdir.join("check"))
|
.arg(at.subdir.join("check"))
|
||||||
.succeeds()
|
.succeeds()
|
||||||
.stdout_is("empty: OK\nempty: OK\nempty: OK\n")
|
.stdout_is("empty: OK\nempty: OK\nempty: OK\n")
|
||||||
|
@ -1528,6 +1525,29 @@ mod check_utf8 {
|
||||||
.stdout_is_bytes(b"flakey\xffname: FAILED open or read\n")
|
.stdout_is_bytes(b"flakey\xffname: FAILED open or read\n")
|
||||||
.stderr_contains("1 listed file could not be read");
|
.stderr_contains("1 listed file could not be read");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
#[test]
|
||||||
|
fn test_quoting_in_stderr() {
|
||||||
|
use super::*;
|
||||||
|
use std::{ffi::OsStr, os::unix::ffi::OsStrExt};
|
||||||
|
|
||||||
|
let (at, mut cmd) = at_and_ucmd!();
|
||||||
|
|
||||||
|
at.mkdir(<OsStr as OsStrExt>::from_bytes(b"FFF\xffDIR"));
|
||||||
|
at.write_bytes(
|
||||||
|
"check",
|
||||||
|
b"SHA256 (FFF\xffFFF) = 29953405eaa3dcc41c37d1621d55b6a47eee93e05613e439e73295029740b10c\nSHA256 (FFF\xffDIR) = 29953405eaa3dcc41c37d1621d55b6a47eee93e05613e439e73295029740b10c\n",
|
||||||
|
);
|
||||||
|
|
||||||
|
cmd.arg("-c")
|
||||||
|
.arg("check")
|
||||||
|
.fails_with_code(1)
|
||||||
|
.stdout_contains_bytes(b"FFF\xffFFF: FAILED open or read")
|
||||||
|
.stdout_contains_bytes(b"FFF\xffDIR: FAILED open or read")
|
||||||
|
.stderr_contains("'FFF'$'\\377''FFF': No such file or directory")
|
||||||
|
.stderr_contains("'FFF'$'\\377''DIR': Is a directory");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -71,7 +71,7 @@ macro_rules! new_ucmd {
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! at_and_ucmd {
|
macro_rules! at_and_ucmd {
|
||||||
() => {{
|
() => {{
|
||||||
let ts = TestScenario::new(util_name!());
|
let ts = ::uutests::util::TestScenario::new(::uutests::util_name!());
|
||||||
(ts.fixtures.clone(), ts.ucmd())
|
(ts.fixtures.clone(), ts.ucmd())
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
clippy::missing_errors_doc
|
clippy::missing_errors_doc
|
||||||
)]
|
)]
|
||||||
|
|
||||||
|
use core::str;
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
use libc::mode_t;
|
use libc::mode_t;
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
|
@ -758,6 +759,29 @@ impl CmdResult {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Verify if stdout contains a byte sequence
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust,ignore
|
||||||
|
/// new_ucmd!()
|
||||||
|
/// .arg("--help")
|
||||||
|
/// .succeeds()
|
||||||
|
/// .stdout_contains_bytes(b"hello \xff");
|
||||||
|
/// ```
|
||||||
|
#[track_caller]
|
||||||
|
pub fn stdout_contains_bytes<T: AsRef<[u8]>>(&self, cmp: T) -> &Self {
|
||||||
|
assert!(
|
||||||
|
self.stdout()
|
||||||
|
.windows(cmp.as_ref().len())
|
||||||
|
.any(|sub| sub == cmp.as_ref()),
|
||||||
|
"'{:?}'\ndoes not contain\n'{:?}'",
|
||||||
|
self.stdout(),
|
||||||
|
cmp.as_ref()
|
||||||
|
);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Verify if stderr contains a specific string
|
/// Verify if stderr contains a specific string
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
|
@ -780,6 +804,29 @@ impl CmdResult {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Verify if stderr contains a byte sequence
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust,ignore
|
||||||
|
/// new_ucmd!()
|
||||||
|
/// .arg("--help")
|
||||||
|
/// .succeeds()
|
||||||
|
/// .stdout_contains_bytes(b"hello \xff");
|
||||||
|
/// ```
|
||||||
|
#[track_caller]
|
||||||
|
pub fn stderr_contains_bytes<T: AsRef<[u8]>>(&self, cmp: T) -> &Self {
|
||||||
|
assert!(
|
||||||
|
self.stderr()
|
||||||
|
.windows(cmp.as_ref().len())
|
||||||
|
.any(|sub| sub == cmp.as_ref()),
|
||||||
|
"'{:?}'\ndoes not contain\n'{:?}'",
|
||||||
|
self.stderr(),
|
||||||
|
cmp.as_ref()
|
||||||
|
);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Verify if stdout does not contain a specific string
|
/// Verify if stdout does not contain a specific string
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue