1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 03:27:44 +00:00

Merge branch 'main' into fix-printf-hex-alternate-zero

This commit is contained in:
Sylvestre Ledru 2024-01-15 10:41:09 +01:00 committed by GitHub
commit 4557821adf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
34 changed files with 401 additions and 103 deletions

View file

@ -612,9 +612,23 @@ jobs:
run: |
## Install/setup prerequisites
case '${{ matrix.job.target }}' in
arm-unknown-linux-gnueabihf) sudo apt-get -y update ; sudo apt-get -y install gcc-arm-linux-gnueabihf ;;
aarch64-unknown-linux-*) sudo apt-get -y update ; sudo apt-get -y install gcc-aarch64-linux-gnu ;;
*-redox*) sudo apt-get -y update ; sudo apt-get -y install fuse3 libfuse-dev ;;
arm-unknown-linux-gnueabihf)
sudo apt-get -y update
sudo apt-get -y install gcc-arm-linux-gnueabihf
;;
aarch64-unknown-linux-*)
sudo apt-get -y update
sudo apt-get -y install gcc-aarch64-linux-gnu
;;
*-redox*)
sudo apt-get -y update
sudo apt-get -y install fuse3 libfuse-dev
;;
# Update binutils if MinGW due to https://github.com/rust-lang/rust/issues/112368
x86_64-pc-windows-gnu)
C:/msys64/usr/bin/pacman.exe -Syu --needed mingw-w64-x86_64-gcc --noconfirm
echo "C:\msys64\mingw64\bin" >> $GITHUB_PATH
;;
esac
case '${{ matrix.job.os }}' in
macos-latest) brew install coreutils ;; # needed for testing
@ -984,6 +998,10 @@ jobs:
echo "foo" > /home/runner/.plan
;;
esac
case '${{ matrix.job.os }}' in
# Update binutils if MinGW due to https://github.com/rust-lang/rust/issues/112368
windows-latest) C:/msys64/usr/bin/pacman.exe -Syu --needed mingw-w64-x86_64-gcc --noconfirm ; echo "C:\msys64\mingw64\bin" >> $GITHUB_PATH ;;
esac
- name: Initialize toolchain-dependent workflow variables
id: dep_vars
shell: bash

70
Cargo.lock generated
View file

@ -320,15 +320,15 @@ checksum = "120133d4db2ec47efe2e26502ee984747630c67f51974fca0b6c1340cf2368d3"
[[package]]
name = "console"
version = "0.15.7"
version = "0.15.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8"
checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb"
dependencies = [
"encode_unicode",
"lazy_static",
"libc",
"unicode-width",
"windows-sys 0.45.0",
"windows-sys 0.52.0",
]
[[package]]
@ -813,14 +813,14 @@ checksum = "31a7a908b8f32538a2143e59a6e4e2508988832d5d4d6f7c156b3cbc762643a5"
[[package]]
name = "filetime"
version = "0.2.22"
version = "0.2.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4029edd3e734da6fe05b6cd7bd2960760a616bd2ddd0d59a0124746d6272af0"
checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd"
dependencies = [
"cfg-if",
"libc",
"redox_syscall 0.3.5",
"windows-sys 0.48.0",
"redox_syscall",
"windows-sys 0.52.0",
]
[[package]]
@ -1293,14 +1293,14 @@ dependencies = [
[[package]]
name = "mio"
version = "0.8.6"
version = "0.8.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9"
checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09"
dependencies = [
"libc",
"log",
"wasi",
"windows-sys 0.45.0",
"windows-sys 0.48.0",
]
[[package]]
@ -1455,13 +1455,13 @@ dependencies = [
[[package]]
name = "parking_lot_core"
version = "0.9.8"
version = "0.9.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447"
checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e"
dependencies = [
"cfg-if",
"libc",
"redox_syscall 0.3.5",
"redox_syscall",
"smallvec",
"windows-targets 0.48.0",
]
@ -1589,7 +1589,7 @@ dependencies = [
"hex",
"lazy_static",
"procfs-core",
"rustix 0.38.28",
"rustix 0.38.30",
]
[[package]]
@ -1689,18 +1689,9 @@ dependencies = [
[[package]]
name = "redox_syscall"
version = "0.3.5"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
dependencies = [
"bitflags 1.3.2",
]
[[package]]
name = "redox_syscall"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ded0bce2d41cc3c57aefa284708ced249a64acb01745dbbe72bd78610bfd644c"
checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
dependencies = [
"bitflags 1.3.2",
]
@ -1831,9 +1822,9 @@ dependencies = [
[[package]]
name = "rustix"
version = "0.38.28"
version = "0.38.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316"
checksum = "322394588aaf33c24007e8bb3238ee3e4c5c09c084ab32bc73890b99ff326bca"
dependencies = [
"bitflags 2.4.0",
"errno",
@ -1995,9 +1986,9 @@ dependencies = [
[[package]]
name = "smallvec"
version = "1.11.0"
version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9"
checksum = "2593d31f82ead8df961d8bd23a64c2ccf2eb5dd34b0a34bfb4dd54011c72009e"
[[package]]
name = "smawk"
@ -2045,15 +2036,15 @@ dependencies = [
[[package]]
name = "tempfile"
version = "3.8.1"
version = "3.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5"
checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa"
dependencies = [
"cfg-if",
"fastrand",
"redox_syscall 0.4.0",
"rustix 0.38.28",
"windows-sys 0.48.0",
"redox_syscall",
"rustix 0.38.30",
"windows-sys 0.52.0",
]
[[package]]
@ -2072,7 +2063,7 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7"
dependencies = [
"rustix 0.38.28",
"rustix 0.38.30",
"windows-sys 0.48.0",
]
@ -2616,6 +2607,7 @@ dependencies = [
"unicode-width",
"uucore",
"uutils_term_grid",
"xattr",
]
[[package]]
@ -3014,7 +3006,7 @@ version = "0.0.23"
dependencies = [
"clap",
"libc",
"redox_syscall 0.4.0",
"redox_syscall",
"uucore",
]
@ -3574,13 +3566,13 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
[[package]]
name = "xattr"
version = "1.2.0"
version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "914566e6413e7fa959cc394fb30e563ba80f3541fbd40816d4c05a0fc3f2a0f1"
checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f"
dependencies = [
"libc",
"linux-raw-sys 0.4.12",
"rustix 0.38.28",
"rustix 0.38.30",
]
[[package]]

View file

@ -318,8 +318,8 @@ same-file = "1.0.6"
self_cell = "1.0.3"
selinux = "0.4"
signal-hook = "0.3.17"
smallvec = { version = "1.11", features = ["union"] }
tempfile = "3.8.1"
smallvec = { version = "1.12", features = ["union"] }
tempfile = "3.9.0"
uutils_term_grid = "0.3"
terminal_size = "0.3.0"
textwrap = { version = "0.16.0", features = ["terminal_size"] }
@ -331,7 +331,7 @@ utf-8 = "0.7.6"
walkdir = "2.4"
winapi-util = "0.1.6"
windows-sys = { version = "0.48.0", default-features = false }
xattr = "1.2.0"
xattr = "1.3.1"
zip = { version = "0.6.6", default-features = false, features = ["deflate"] }
hex = "0.4.3"

View file

@ -62,7 +62,7 @@ skip = [
{ name = "linux-raw-sys", version = "0.3.8" },
# terminal_size
{ name = "rustix", version = "0.37.26" },
# various crates
# notify
{ name = "windows-sys", version = "0.45.0" },
# various crates
{ name = "windows-sys", version = "0.48.0" },
@ -102,8 +102,6 @@ skip = [
{ name = "syn", version = "1.0.109" },
# various crates
{ name = "bitflags", version = "1.3.2" },
# various crates
{ name = "redox_syscall", version = "0.3.5" },
# clap_builder, textwrap
{ name = "terminal_size", version = "0.2.6" },
]

View file

@ -232,7 +232,10 @@ pub fn run_gnu_cmd(
let output = if let Some(input_str) = pipe_input {
// We have an pipe input
command.stdin(Stdio::piped()).stdout(Stdio::piped());
command
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped());
let mut child = command.spawn().expect("Failed to execute command");
let child_stdin = child.stdin.as_mut().unwrap();

View file

@ -5,15 +5,18 @@
// spell-checker:ignore (ToDO) fname, algo
use clap::{crate_version, value_parser, Arg, ArgAction, Command};
use hex::decode;
use hex::encode;
use std::error::Error;
use std::ffi::OsStr;
use std::fmt::Display;
use std::fs::File;
use std::io::{self, stdin, BufReader, Read};
use std::io::{self, stdin, stdout, BufReader, Read, Write};
use std::iter;
use std::path::Path;
use uucore::{
error::{FromIo, UResult},
format_usage, help_about, help_section, help_usage,
error::{FromIo, UError, UResult, USimpleError},
format_usage, help_about, help_section, help_usage, show,
sum::{
div_ceil, Blake2b, Digest, DigestWriter, Md5, Sha1, Sha224, Sha256, Sha384, Sha512, Sm3,
BSD, CRC, SYSV,
@ -36,6 +39,31 @@ const ALGORITHM_OPTIONS_SHA512: &str = "sha512";
const ALGORITHM_OPTIONS_BLAKE2B: &str = "blake2b";
const ALGORITHM_OPTIONS_SM3: &str = "sm3";
#[derive(Debug)]
enum CkSumError {
RawMultipleFiles,
}
impl UError for CkSumError {
fn code(&self) -> i32 {
match self {
Self::RawMultipleFiles => 1,
}
}
}
impl Error for CkSumError {}
impl Display for CkSumError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::RawMultipleFiles => {
write!(f, "the --raw option is not supported with multiple files")
}
}
}
}
fn detect_algo(
program: &str,
length: Option<usize>,
@ -110,6 +138,7 @@ struct Options {
output_bits: usize,
untagged: bool,
length: Option<usize>,
raw: bool,
}
/// Calculate checksum
@ -123,6 +152,11 @@ fn cksum<'a, I>(mut options: Options, files: I) -> UResult<()>
where
I: Iterator<Item = &'a OsStr>,
{
let files: Vec<_> = files.collect();
if options.raw && files.len() > 1 {
return Err(Box::new(CkSumError::RawMultipleFiles));
}
for filename in files {
let filename = Path::new(filename);
let stdin_buf;
@ -134,13 +168,35 @@ where
} else if filename.is_dir() {
Box::new(BufReader::new(io::empty())) as Box<dyn Read>
} else {
file_buf =
File::open(filename).map_err_context(|| filename.to_str().unwrap().to_string())?;
file_buf = match File::open(filename) {
Ok(file) => file,
Err(err) => {
show!(err.map_err_context(|| filename.to_string_lossy().to_string()));
continue;
}
};
Box::new(file_buf) as Box<dyn Read>
});
let (sum, sz) = digest_read(&mut options.digest, &mut file, options.output_bits)
.map_err_context(|| "failed to read input".to_string())?;
if filename.is_dir() {
show!(USimpleError::new(
1,
format!("{}: Is a directory", filename.display())
));
continue;
}
if options.raw {
let bytes = match options.algo_name {
ALGORITHM_OPTIONS_CRC => sum.parse::<u32>().unwrap().to_be_bytes().to_vec(),
ALGORITHM_OPTIONS_SYSV | ALGORITHM_OPTIONS_BSD => {
sum.parse::<u16>().unwrap().to_be_bytes().to_vec()
}
_ => decode(sum).unwrap(),
};
stdout().write_all(&bytes)?;
return Ok(());
}
// The BSD checksum output is 5 digit integer
let bsd_width = 5;
match (options.algo_name, not_file) {
@ -169,13 +225,6 @@ where
(ALGORITHM_OPTIONS_CRC, true) => println!("{sum} {sz}"),
(ALGORITHM_OPTIONS_CRC, false) => println!("{sum} {sz} {}", filename.display()),
(ALGORITHM_OPTIONS_BLAKE2B, _) if !options.untagged => {
if filename.is_dir() {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
format!("{}: Is a directory", filename.display()),
)
.into());
}
if let Some(length) = options.length {
// Multiply by 8 here, as we want to print the length in bits.
println!("BLAKE2b-{} ({}) = {sum}", length * 8, filename.display());
@ -238,6 +287,7 @@ mod options {
pub const FILE: &str = "file";
pub const UNTAGGED: &str = "untagged";
pub const LENGTH: &str = "length";
pub const RAW: &str = "raw";
}
#[uucore::main]
@ -298,6 +348,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
output_bits: bits,
length,
untagged: matches.get_flag(options::UNTAGGED),
raw: matches.get_flag(options::RAW),
};
match matches.get_many::<String>(options::FILE) {
@ -354,5 +405,11 @@ pub fn uu_app() -> Command {
.help("digest length in bits; must not exceed the max for the blake2 algorithm and must be a multiple of 8")
.action(ArgAction::Set),
)
.arg(
Arg::new(options::RAW)
.long(options::RAW)
.help("emit a raw binary digest, not hexadecimal")
.action(ArgAction::SetTrue),
)
.after_help(AFTER_HELP)
}

View file

@ -150,6 +150,7 @@ pub enum TargetType {
}
/// Copy action to perform
#[derive(PartialEq)]
pub enum CopyMode {
Link,
SymLink,
@ -1509,7 +1510,7 @@ fn backup_dest(dest: &Path, backup_path: &Path) -> CopyResult<PathBuf> {
///
/// Copying to the same file is only allowed if both `--backup` and
/// `--force` are specified and the file is a regular file.
fn is_forbidden_copy_to_same_file(
fn is_forbidden_to_copy_to_same_file(
source: &Path,
dest: &Path,
options: &Options,
@ -1521,6 +1522,7 @@ fn is_forbidden_copy_to_same_file(
options.dereference(source_in_command_line) || !source.is_symlink();
paths_refer_to_same_file(source, dest, dereference_to_compare)
&& !(options.force() && options.backup != BackupMode::NoBackup)
&& !(dest.is_symlink() && options.backup != BackupMode::NoBackup)
}
/// Back up, remove, or leave intact the destination file, depending on the options.
@ -1532,7 +1534,7 @@ fn handle_existing_dest(
) -> CopyResult<()> {
// Disallow copying a file to itself, unless `--force` and
// `--backup` are both specified.
if is_forbidden_copy_to_same_file(source, dest, options, source_in_command_line) {
if is_forbidden_to_copy_to_same_file(source, dest, options, source_in_command_line) {
return Err(format!("{} and {} are the same file", source.quote(), dest.quote()).into());
}
@ -1714,6 +1716,7 @@ fn copy_file(
&& !options.force()
&& options.backup == BackupMode::NoBackup
&& source != dest
|| (source == dest && options.copy_mode == CopyMode::Link)
{
return Ok(());
}

View file

@ -510,6 +510,7 @@ pub fn uu_app() -> Command {
.about(ABOUT)
.after_help(AFTER_HELP)
.infer_long_args(true)
.args_override_self(true)
.arg(
Arg::new(options::BYTES)
.short('b')

View file

@ -34,6 +34,9 @@ once_cell = { workspace = true }
selinux = { workspace = true, optional = true }
hostname = { workspace = true }
[target.'cfg(unix)'.dependencies]
xattr = { workspace = true }
[[bin]]
name = "ls"
path = "src/main.rs"

View file

@ -3,7 +3,7 @@
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
// spell-checker:ignore (ToDO) somegroup nlink tabsize dired subdired dtype colorterm
// spell-checker:ignore (ToDO) somegroup nlink tabsize dired subdired dtype colorterm getxattr
use clap::{
builder::{NonEmptyStringValueParser, ValueParser},
@ -36,6 +36,7 @@ use std::{
};
use term_grid::{Cell, Direction, Filling, Grid, GridOptions};
use unicode_width::UnicodeWidthStr;
#[cfg(any(
target_os = "linux",
target_os = "macos",
@ -2620,6 +2621,18 @@ fn display_grid(
Ok(())
}
#[cfg(all(unix, not(any(target_os = "android", target_os = "macos"))))]
fn file_has_acl<P: AsRef<Path>>(file: P) -> bool {
// don't use exacl here, it is doing more getxattr call then needed
match xattr::list(file) {
Ok(acl) => {
// if we have extra attributes, we have an acl
acl.count() > 0
}
Err(_) => false,
}
}
/// This writes to the BufWriter out a single string of the output of `ls -l`.
///
/// It writes the following keys, in order:
@ -2663,9 +2676,14 @@ fn display_item_long(
output_display += " ";
}
if let Some(md) = item.get_metadata(out) {
#[cfg(any(not(unix), target_os = "android", target_os = "macos"))]
// TODO: See how Mac should work here
let is_acl_set = false;
#[cfg(all(unix, not(any(target_os = "android", target_os = "macos"))))]
let is_acl_set = file_has_acl(item.display_name.as_os_str());
write!(
output_display,
"{}{} {}",
"{}{}{} {}",
display_permissions(md, true),
if item.security_context.len() > 1 {
// GNU `ls` uses a "." character to indicate a file with a security context,
@ -2674,6 +2692,12 @@ fn display_item_long(
} else {
""
},
if is_acl_set {
// if acl has been set, we display a "+" at the end of the file permissions
"+"
} else {
""
},
pad_left(&display_symlink_count(md), padding.link_count)
)
.unwrap();

View file

@ -7,8 +7,8 @@ use clap::{crate_version, Arg, ArgAction, Command};
use std::fs::File;
use std::io::{stdin, BufRead, BufReader, Read};
use std::path::Path;
use uucore::error::{FromIo, UResult, USimpleError};
use uucore::{format_usage, help_about, help_section, help_usage};
use uucore::error::{set_exit_code, FromIo, UResult, USimpleError};
use uucore::{format_usage, help_about, help_section, help_usage, show_error};
mod helper;
@ -205,11 +205,17 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
nl(&mut buffer, &mut stats, &settings)?;
} else {
let path = Path::new(file);
if path.is_dir() {
show_error!("{}: Is a directory", path.display());
set_exit_code(1);
} else {
let reader = File::open(path).map_err_context(|| file.to_string())?;
let mut buffer = BufReader::new(reader);
nl(&mut buffer, &mut stats, &settings)?;
}
}
}
Ok(())
}

View file

@ -11,7 +11,7 @@ use std::ops::ControlFlow;
use clap::{crate_version, Arg, ArgAction, Command};
use uucore::error::{UResult, UUsageError};
use uucore::format::{parse_spec_and_escape, FormatArgument};
use uucore::format::{parse_spec_and_escape, FormatArgument, FormatItem};
use uucore::{format_usage, help_about, help_section, help_usage};
const VERSION: &str = "version";
@ -38,14 +38,24 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
None => vec![],
};
let mut format_seen = false;
let mut args = values.iter().peekable();
for item in parse_spec_and_escape(format_string.as_ref()) {
if let Ok(FormatItem::Spec(_)) = item {
format_seen = true;
}
match item?.write(stdout(), &mut args)? {
ControlFlow::Continue(()) => {}
ControlFlow::Break(()) => return Ok(()),
};
}
// Without format specs in the string, the iter would not consume any args,
// leading to an infinite loop. Thus, we exit early.
if !format_seen {
return Ok(());
}
while args.peek().is_some() {
for item in parse_spec_and_escape(format_string.as_ref()) {
match item?.write(stdout(), &mut args)? {

View file

@ -45,7 +45,7 @@ impl<'a, T: Iterator<Item = &'a FormatArgument>> ArgumentIter<'a> for T {
};
match next {
FormatArgument::Char(c) => *c,
FormatArgument::Unparsed(s) => s.chars().next().unwrap_or('\0'),
FormatArgument::Unparsed(s) => s.bytes().next().map_or('\0', char::from),
_ => '\0',
}
}

View file

@ -108,6 +108,7 @@ pub fn parse_escape_code(rest: &mut &[u8]) -> EscapedChar {
*rest = new_rest;
match c {
b'\\' => EscapedChar::Byte(b'\\'),
b'"' => EscapedChar::Byte(b'"'),
b'a' => EscapedChar::Byte(b'\x07'),
b'b' => EscapedChar::Byte(b'\x08'),
b'c' => EscapedChar::End,

View file

@ -146,10 +146,10 @@ impl Formatter for UnsignedInt {
// We also need to take into account that 0 should not be 00
// Since this is an unsigned int, we do not need to take the minus
// sign into account.
if x != 0 {
format!("0{x:o}")
} else {
if x == 0 {
format!("{x:o}")
} else {
format!("0{x:o}")
}
}
UnsignedIntVariant::Hexadecimal(Case::Lowercase, Prefix::No) => {

View file

@ -81,15 +81,19 @@ fn test_nonexisting_file() {
}
#[test]
fn test_folder() {
fn test_one_nonexisting_file() {
let (at, mut ucmd) = at_and_ucmd!();
let folder_name = "a_folder";
at.mkdir(folder_name);
at.touch("abc.txt");
at.touch("xyz.txt");
ucmd.arg(folder_name)
.succeeds()
.stdout_only(format!("4294967295 0 {folder_name}\n"));
ucmd.arg("abc.txt")
.arg("asdf.txt")
.arg("xyz.txt")
.fails()
.stdout_contains_line("4294967295 0 xyz.txt")
.stderr_contains("asdf.txt: No such file or directory")
.stdout_contains_line("4294967295 0 abc.txt");
}
// Make sure crc is correct for files larger than 32 bytes
@ -288,15 +292,76 @@ fn test_length_is_zero() {
}
#[test]
fn test_blake2b_fail_on_directory() {
fn test_raw_single_file() {
for algo in ALGOS {
new_ucmd!()
.arg("--raw")
.arg("lorem_ipsum.txt")
.arg(format!("--algorithm={algo}"))
.succeeds()
.no_stderr()
.stdout_is_fixture_bytes(format!("raw/{algo}_single_file.expected"));
}
}
#[test]
fn test_raw_multiple_files() {
new_ucmd!()
.arg("--raw")
.arg("lorem_ipsum.txt")
.arg("alice_in_wonderland.txt")
.fails()
.no_stdout()
.stderr_contains("cksum: the --raw option is not supported with multiple files")
.code_is(1);
}
#[test]
fn test_fail_on_folder() {
let (at, mut ucmd) = at_and_ucmd!();
let folder_name = "a_folder";
at.mkdir(folder_name);
ucmd.arg("--algorithm=blake2b")
.arg(folder_name)
ucmd.arg(folder_name)
.fails()
.no_stdout()
.stderr_contains(format!("cksum: {folder_name}: Is a directory"));
}
#[test]
fn test_all_algorithms_fail_on_folder() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
let folder_name = "a_folder";
at.mkdir(folder_name);
for algo in ALGOS {
scene
.ucmd()
.arg(format!("--algorithm={algo}"))
.arg(folder_name)
.fails()
.no_stdout()
.stderr_contains(format!("cksum: {folder_name}: Is a directory"));
}
}
#[test]
fn test_folder_and_file() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
let folder_name = "a_folder";
at.mkdir(folder_name);
scene
.ucmd()
.arg(folder_name)
.arg("lorem_ipsum.txt")
.fails()
.stderr_contains(format!("cksum: {folder_name}: Is a directory"))
.stdout_is_fixture("crc_single_file.expected");
}

View file

@ -566,6 +566,22 @@ fn test_cp_arg_link_with_dest_hardlink_to_source() {
assert!(at.file_exists(hardlink));
}
#[test]
#[cfg(target_os = "linux")]
fn test_cp_arg_link_with_same_file() {
use std::os::linux::fs::MetadataExt;
let (at, mut ucmd) = at_and_ucmd!();
let file = "file";
at.touch(file);
ucmd.args(&["--link", file, file]).succeeds();
assert_eq!(at.metadata(file).st_nlink(), 1);
assert!(at.file_exists(file));
}
#[test]
fn test_cp_arg_symlink() {
let (at, mut ucmd) = at_and_ucmd!();
@ -715,6 +731,25 @@ fn test_cp_arg_backup_with_dest_a_symlink() {
assert_eq!(original, at.resolve_link(backup));
}
#[test]
fn test_cp_arg_backup_with_dest_a_symlink_to_source() {
let (at, mut ucmd) = at_and_ucmd!();
let source = "source";
let source_content = "content";
let symlink = "symlink";
let backup = "symlink~";
at.write(source, source_content);
at.symlink_file(source, symlink);
ucmd.arg("-b").arg(source).arg(symlink).succeeds();
assert!(!at.symlink_exists(symlink));
assert_eq!(source_content, at.read(symlink));
assert!(at.symlink_exists(backup));
assert_eq!(source, at.resolve_link(backup));
}
#[test]
fn test_cp_arg_backup_with_other_args() {
let (at, mut ucmd) = at_and_ucmd!();

View file

@ -255,3 +255,13 @@ fn test_equal_as_delimiter3() {
.succeeds()
.stdout_only_bytes("abZcd\n");
}
#[test]
fn test_multiple() {
let result = new_ucmd!()
.args(&["-f2", "-d:", "-d="])
.pipe_in("a=b\n")
.succeeds();
assert_eq!(result.stdout_str(), "b\n");
assert_eq!(result.stderr_str(), "");
}

View file

@ -391,7 +391,7 @@ fn test_read_backwards_bytes_proc_fs_version() {
let args = ["-c", "-1", "/proc/version"];
let result = ts.ucmd().args(&args).succeeds();
assert!(result.stdout().len() > 0);
assert!(!result.stdout().is_empty());
}
#[cfg(all(
@ -406,7 +406,7 @@ fn test_read_backwards_bytes_proc_fs_modules() {
let args = ["-c", "-1", "/proc/modules"];
let result = ts.ucmd().args(&args).succeeds();
assert!(result.stdout().len() > 0);
assert!(!result.stdout().is_empty());
}
#[cfg(all(
@ -421,7 +421,7 @@ fn test_read_backwards_lines_proc_fs_modules() {
let args = ["--lines", "-1", "/proc/modules"];
let result = ts.ucmd().args(&args).succeeds();
assert!(result.stdout().len() > 0);
assert!(!result.stdout().is_empty());
}
#[cfg(all(

View file

@ -4293,3 +4293,39 @@ fn test_term_colorterm() {
"exe"
);
}
#[cfg(all(unix, not(target_os = "macos")))]
#[test]
fn test_acl_display() {
use std::process::Command;
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
let path = "a42";
at.mkdir(path);
let path = at.plus_as_string(path);
// calling the command directly. xattr requires some dev packages to be installed
// and it adds a complex dependency just for a test
match Command::new("setfacl")
.args(["-d", "-m", "group::rwx", &path])
.status()
.map(|status| status.code())
{
Ok(Some(0)) => {}
Ok(_) => {
println!("test skipped: setfacl failed");
return;
}
Err(e) => {
println!("test skipped: setfacl failed with {}", e);
return;
}
}
scene
.ucmd()
.args(&["-lda", &path])
.succeeds()
.stdout_contains("+");
}

View file

@ -634,3 +634,20 @@ fn test_empty_section_delimiter() {
.stdout_is(" 1\ta\n \n 2\tb\n");
}
}
#[test]
fn test_directory_as_input() {
let (at, mut ucmd) = at_and_ucmd!();
let dir = "dir";
let file = "file";
let content = "aaa";
at.mkdir(dir);
at.write(file, content);
ucmd.arg(dir)
.arg(file)
.fails()
.stderr_is(format!("nl: {dir}: Is a directory\n"))
.stdout_contains(content);
}

View file

@ -4,6 +4,14 @@
// file that was distributed with this source code.
use crate::common::util::TestScenario;
#[test]
fn test_no_args() {
new_ucmd!()
.fails()
.no_stdout()
.stderr_contains("pathchk: missing operand");
}
#[test]
fn test_invalid_arg() {
new_ucmd!().arg("--definitely-invalid").fails().code_is(1);
@ -11,8 +19,6 @@ fn test_invalid_arg() {
#[test]
fn test_default_mode() {
// test the default mode
// accept some reasonable default
new_ucmd!().args(&["dir/file"]).succeeds().no_stdout();
@ -48,8 +54,6 @@ fn test_default_mode() {
#[test]
fn test_posix_mode() {
// test the posix mode
// accept some reasonable default
new_ucmd!().args(&["-p", "dir/file"]).succeeds().no_stdout();
@ -74,8 +78,6 @@ fn test_posix_mode() {
#[test]
fn test_posix_special() {
// test the posix special mode
// accept some reasonable default
new_ucmd!().args(&["-P", "dir/file"]).succeeds().no_stdout();
@ -115,8 +117,6 @@ fn test_posix_special() {
#[test]
fn test_posix_all() {
// test the posix special mode
// accept some reasonable default
new_ucmd!()
.args(&["-p", "-P", "dir/file"])
@ -164,10 +164,3 @@ fn test_posix_all() {
// fail on empty path
new_ucmd!().args(&["-p", "-P", ""]).fails().no_stdout();
}
#[test]
fn test_args_parsing() {
// fail on no args
let empty_args: [String; 0] = [];
new_ucmd!().args(&empty_args).fails().no_stdout();
}

View file

@ -36,6 +36,11 @@ fn escaped_slash() {
.stdout_only("hello\\ world");
}
#[test]
fn unescaped_double_quote() {
new_ucmd!().args(&["\\\""]).succeeds().stdout_only("\"");
}
#[test]
fn escaped_hex() {
new_ucmd!().args(&["\\x41"]).succeeds().stdout_only("A");
@ -665,3 +670,13 @@ fn sub_alternative_upper_hex() {
.succeeds()
.stdout_only("0x2A");
}
#[test]
fn char_as_byte() {
new_ucmd!().args(&["%c", "🙃"]).succeeds().stdout_only("ð");
}
#[test]
fn no_infinite_loop() {
new_ucmd!().args(&["a", "b"]).succeeds().stdout_only("a");
}

View file

@ -0,0 +1 @@
— ‘‰å`Ãxœ ÿf†øWÑûþEtÞBãÀl«¹W^Jö0šaX´ÓÀ8Á´<C381>5<15>BÍÀ9m•Ã

View file

@ -0,0 +1 @@
<1F>

View file

@ -0,0 +1 @@
訓h

Binary file not shown.

View file

@ -0,0 +1 @@
<EFBFBD>к<>؈:=<18>m毽(%,<2C><>

Binary file not shown.

View file

@ -0,0 +1 @@
÷Ä P 0P gê^ <09>SkEþœC[Ù+?

View file

@ -0,0 +1,3 @@
K荵
2吠鋳<19><EFBFBD>マクアト/g胤€コ囹LZ{WZ3Sゥ
H

View file

@ -0,0 +1 @@
Td«%VªÕ޼sØšÒ!åYyu)ì¯ÀôfÁ•ÏöÖâÆ |T,ýBn^Oऊ¡VgºD k!=Í<03>ú

View file

@ -0,0 +1 @@
m)k€] þÒ(ß0<C39F>»CyMÔíg@¡iÂ

View file

@ -0,0 +1 @@
I