mirror of
https://github.com/uutils/coreutils.git
synced 2026-06-10 15:48:22 -07:00
chmod/readlink/du: improve non-UTF-8 filename handling and code style
This commit is contained in:
+18
-5
@@ -7,9 +7,14 @@ use clap::{Arg, ArgAction, ArgMatches, Command, builder::PossibleValue};
|
||||
use glob::Pattern;
|
||||
use std::collections::HashSet;
|
||||
use std::env;
|
||||
#[cfg(unix)]
|
||||
use std::ffi::OsStr;
|
||||
use std::ffi::OsString;
|
||||
use std::fs::Metadata;
|
||||
use std::fs::{self, DirEntry, File};
|
||||
use std::io::{BufRead, BufReader, stdout};
|
||||
#[cfg(unix)]
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
#[cfg(not(windows))]
|
||||
use std::os::unix::fs::MetadataExt;
|
||||
#[cfg(windows)]
|
||||
@@ -568,6 +573,9 @@ fn read_files_from(file_name: &str) -> Result<Vec<PathBuf>, std::io::Error> {
|
||||
);
|
||||
set_exit_code(1);
|
||||
} else {
|
||||
#[cfg(unix)]
|
||||
let p = PathBuf::from(OsStr::from_bytes(&path));
|
||||
#[cfg(windows)]
|
||||
let p = PathBuf::from(String::from_utf8_lossy(&path).to_string());
|
||||
if !paths.contains(&p) {
|
||||
paths.push(p);
|
||||
@@ -594,21 +602,24 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||
summarize,
|
||||
)?;
|
||||
|
||||
let files = if let Some(file_from) = matches.get_one::<String>(options::FILES0_FROM) {
|
||||
if file_from == "-" && matches.get_one::<String>(options::FILE).is_some() {
|
||||
let files = if let Some(file_from) = matches.get_one::<OsString>(options::FILES0_FROM) {
|
||||
if file_from.to_string_lossy() == "-"
|
||||
&& matches.get_one::<OsString>(options::FILE).is_some()
|
||||
{
|
||||
return Err(std::io::Error::other(
|
||||
translate!("du-error-extra-operand-with-files0-from",
|
||||
"file" => matches
|
||||
.get_one::<String>(options::FILE)
|
||||
.get_one::<OsString>(options::FILE)
|
||||
.unwrap()
|
||||
.to_string_lossy()
|
||||
.quote()
|
||||
),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
|
||||
read_files_from(file_from)?
|
||||
} else if let Some(files) = matches.get_many::<String>(options::FILE) {
|
||||
read_files_from(&file_from.to_string_lossy())?
|
||||
} else if let Some(files) = matches.get_many::<OsString>(options::FILE) {
|
||||
let files = files.map(PathBuf::from);
|
||||
if count_links {
|
||||
files.collect()
|
||||
@@ -984,6 +995,7 @@ pub fn uu_app() -> Command {
|
||||
.long("files0-from")
|
||||
.value_name("FILE")
|
||||
.value_hint(clap::ValueHint::FilePath)
|
||||
.value_parser(clap::value_parser!(OsString))
|
||||
.help(translate!("du-help-files0-from"))
|
||||
.action(ArgAction::Append),
|
||||
)
|
||||
@@ -1010,6 +1022,7 @@ pub fn uu_app() -> Command {
|
||||
Arg::new(options::FILE)
|
||||
.hide(true)
|
||||
.value_hint(clap::ValueHint::AnyPath)
|
||||
.value_parser(clap::value_parser!(OsString))
|
||||
.action(ArgAction::Append),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -81,9 +81,9 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||
for f in &files {
|
||||
let p = f;
|
||||
let path_result = if res_mode == ResolveMode::None {
|
||||
fs::read_link(&p)
|
||||
fs::read_link(p)
|
||||
} else {
|
||||
canonicalize(&p, can_mode, res_mode)
|
||||
canonicalize(p, can_mode, res_mode)
|
||||
};
|
||||
|
||||
match path_result {
|
||||
|
||||
@@ -14,9 +14,9 @@ use std::process::Stdio;
|
||||
use uutests::at_and_ucmd;
|
||||
use uutests::new_ucmd;
|
||||
use uutests::util::TestScenario;
|
||||
use uutests::util_name;
|
||||
#[cfg(not(windows))]
|
||||
use uutests::util::vec_of_size;
|
||||
use uutests::util_name;
|
||||
|
||||
#[test]
|
||||
fn test_output_simple() {
|
||||
@@ -755,17 +755,17 @@ fn test_cat_non_utf8_paths() {
|
||||
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
|
||||
|
||||
// Create a test file with non-UTF-8 bytes in the name
|
||||
let non_utf8_bytes = b"test_\xFF\xFE.txt";
|
||||
let non_utf8_name = OsStr::from_bytes(non_utf8_bytes);
|
||||
|
||||
|
||||
// Create the actual file with some content
|
||||
std::fs::write(at.plus(non_utf8_name), "Hello, non-UTF-8 world!\n").unwrap();
|
||||
|
||||
|
||||
// Test that cat handles non-UTF-8 file names without crashing
|
||||
let result = scene.ucmd().arg(non_utf8_name).succeeds();
|
||||
|
||||
|
||||
// The result should contain the file content
|
||||
let output = result.stdout_str_lossy();
|
||||
assert_eq!(output, "Hello, non-UTF-8 world!\n");
|
||||
|
||||
@@ -867,17 +867,17 @@ fn test_head_non_utf8_paths() {
|
||||
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
|
||||
|
||||
// Create a test file with non-UTF-8 bytes in the name
|
||||
let non_utf8_bytes = b"test_\xFF\xFE.txt";
|
||||
let non_utf8_name = OsStr::from_bytes(non_utf8_bytes);
|
||||
|
||||
|
||||
// Create the actual file with some content
|
||||
std::fs::write(at.plus(non_utf8_name), "line1\nline2\nline3\n").unwrap();
|
||||
|
||||
|
||||
// Test that head handles non-UTF-8 file names without crashing
|
||||
let result = scene.ucmd().arg(non_utf8_name).succeeds();
|
||||
|
||||
|
||||
// The result should contain the file content
|
||||
let output = result.stdout_str_lossy();
|
||||
assert!(output.contains("line1"));
|
||||
@@ -885,10 +885,12 @@ fn test_head_non_utf8_paths() {
|
||||
assert!(output.contains("line3"));
|
||||
|
||||
// Test with line count argument
|
||||
scene.ucmd()
|
||||
scene
|
||||
.ucmd()
|
||||
.args(&["-n", "2"])
|
||||
.arg(non_utf8_name)
|
||||
.succeeds()
|
||||
.stdout_contains("line1")
|
||||
.stdout_contains("line2");
|
||||
}
|
||||
// Test that head handles non-UTF-8 file names without crashing
|
||||
|
||||
@@ -852,36 +852,38 @@ fn test_ln_non_utf8_paths() {
|
||||
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
|
||||
|
||||
// Create a test file with non-UTF-8 bytes in the name
|
||||
let non_utf8_bytes = b"test_\xFF\xFE.txt";
|
||||
let non_utf8_name = OsStr::from_bytes(non_utf8_bytes);
|
||||
let non_utf8_link_bytes = b"link_\xFF\xFE.txt";
|
||||
let non_utf8_link_name = OsStr::from_bytes(non_utf8_link_bytes);
|
||||
|
||||
|
||||
// Create the actual file
|
||||
at.touch(non_utf8_name);
|
||||
|
||||
|
||||
// Test creating a hard link with non-UTF-8 file names
|
||||
scene.ucmd()
|
||||
scene
|
||||
.ucmd()
|
||||
.arg(non_utf8_name)
|
||||
.arg(non_utf8_link_name)
|
||||
.succeeds();
|
||||
|
||||
|
||||
// Both files should exist
|
||||
assert!(at.file_exists(non_utf8_name));
|
||||
assert!(at.file_exists(non_utf8_link_name));
|
||||
|
||||
|
||||
// Test creating a symbolic link with non-UTF-8 file names
|
||||
let symlink_bytes = b"symlink_\xFF\xFE.txt";
|
||||
let symlink_name = OsStr::from_bytes(symlink_bytes);
|
||||
|
||||
scene.ucmd()
|
||||
|
||||
scene
|
||||
.ucmd()
|
||||
.args(&["-s"])
|
||||
.arg(non_utf8_name)
|
||||
.arg(symlink_name)
|
||||
.succeeds();
|
||||
|
||||
|
||||
// Check if symlink was created successfully
|
||||
let symlink_path = at.plus(symlink_name);
|
||||
assert!(symlink_path.is_symlink());
|
||||
|
||||
@@ -382,18 +382,18 @@ fn test_readlink_non_utf8_paths() {
|
||||
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
|
||||
|
||||
// Create a target file and a symlink with non-UTF-8 bytes in the name
|
||||
at.touch("target_file");
|
||||
let non_utf8_bytes = b"symlink_\xFF\xFE";
|
||||
let non_utf8_name = OsStr::from_bytes(non_utf8_bytes);
|
||||
|
||||
|
||||
// Create symlink using std::os::unix::fs::symlink
|
||||
std::os::unix::fs::symlink(at.plus_as_string("target_file"), at.plus(non_utf8_name)).unwrap();
|
||||
|
||||
|
||||
// Test that readlink handles non-UTF-8 symlink names without crashing
|
||||
let result = scene.ucmd().arg(non_utf8_name).succeeds();
|
||||
|
||||
|
||||
// The result should contain the target path
|
||||
let output = result.stdout_str_lossy();
|
||||
assert!(output.contains("target_file"));
|
||||
|
||||
@@ -473,17 +473,17 @@ fn test_realpath_non_utf8_paths() {
|
||||
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
|
||||
|
||||
// Create a test file with non-UTF-8 bytes in the name
|
||||
let non_utf8_bytes = b"test_\xFF\xFE.txt";
|
||||
let non_utf8_name = OsStr::from_bytes(non_utf8_bytes);
|
||||
|
||||
|
||||
// Create the actual file
|
||||
at.touch(non_utf8_name);
|
||||
|
||||
|
||||
// Test that realpath handles non-UTF-8 paths without crashing
|
||||
let result = scene.ucmd().arg(non_utf8_name).succeeds();
|
||||
|
||||
|
||||
// The result should contain the non-UTF-8 bytes
|
||||
let output = result.stdout_str_lossy();
|
||||
assert!(output.contains("test_"));
|
||||
|
||||
+10
-15
@@ -1046,34 +1046,29 @@ fn test_rm_non_utf8_paths() {
|
||||
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
|
||||
|
||||
// Create a test file with non-UTF-8 bytes in the name
|
||||
let non_utf8_bytes = b"test_\xFF\xFE.txt";
|
||||
let non_utf8_name = OsStr::from_bytes(non_utf8_bytes);
|
||||
|
||||
|
||||
// Create the actual file
|
||||
at.touch(non_utf8_name);
|
||||
assert!(at.file_exists(non_utf8_name));
|
||||
|
||||
|
||||
// Test that rm handles non-UTF-8 file names without crashing
|
||||
scene.ucmd()
|
||||
.arg(non_utf8_name)
|
||||
.succeeds();
|
||||
|
||||
scene.ucmd().arg(non_utf8_name).succeeds();
|
||||
|
||||
// The file should be removed
|
||||
assert!(!at.file_exists(non_utf8_name));
|
||||
|
||||
|
||||
// Test with directory
|
||||
let non_utf8_dir_bytes = b"test_dir_\xFF\xFE";
|
||||
let non_utf8_dir_name = OsStr::from_bytes(non_utf8_dir_bytes);
|
||||
|
||||
|
||||
at.mkdir(non_utf8_dir_name);
|
||||
assert!(at.dir_exists(non_utf8_dir_name));
|
||||
|
||||
scene.ucmd()
|
||||
.args(&["-r"])
|
||||
.arg(non_utf8_dir_name)
|
||||
.succeeds();
|
||||
|
||||
|
||||
scene.ucmd().args(&["-r"]).arg(non_utf8_dir_name).succeeds();
|
||||
|
||||
assert!(!at.dir_exists(non_utf8_dir_name));
|
||||
}
|
||||
|
||||
@@ -1022,17 +1022,17 @@ fn test_touch_non_utf8_paths() {
|
||||
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
|
||||
|
||||
// Create a test file with non-UTF-8 bytes in the name
|
||||
let non_utf8_bytes = b"test_\xFF\xFE.txt";
|
||||
let non_utf8_name = OsStr::from_bytes(non_utf8_bytes);
|
||||
|
||||
|
||||
// Test that touch handles non-UTF-8 file names without crashing
|
||||
let result = scene.ucmd().arg(non_utf8_name).succeeds();
|
||||
|
||||
|
||||
// Verify no output and file was created
|
||||
result.no_output();
|
||||
|
||||
|
||||
// Check that the file was created (using the raw path)
|
||||
assert!(std::fs::metadata(at.plus(non_utf8_name)).is_ok());
|
||||
}
|
||||
|
||||
@@ -86,20 +86,18 @@ fn test_unlink_non_utf8_paths() {
|
||||
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
|
||||
|
||||
// Create a test file with non-UTF-8 bytes in the name
|
||||
let non_utf8_bytes = b"test_\xFF\xFE.txt";
|
||||
let non_utf8_name = OsStr::from_bytes(non_utf8_bytes);
|
||||
|
||||
|
||||
// Create the actual file
|
||||
at.touch(non_utf8_name);
|
||||
assert!(at.file_exists(non_utf8_name));
|
||||
|
||||
|
||||
// Test that unlink handles non-UTF-8 file names without crashing
|
||||
scene.ucmd()
|
||||
.arg(non_utf8_name)
|
||||
.succeeds();
|
||||
|
||||
scene.ucmd().arg(non_utf8_name).succeeds();
|
||||
|
||||
// The file should be removed
|
||||
assert!(!at.file_exists(non_utf8_name));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user