rm: fix handling of non-UTF-8 filenames

This commit is contained in:
Sylvestre Ledru
2025-08-14 10:52:24 +02:00
parent b8702bd5df
commit a0f1e34d10
2 changed files with 50 additions and 10 deletions
+10 -10
View File
@@ -31,17 +31,17 @@ enum RmError {
#[error("{}", translate!("rm-error-missing-operand", "util_name" => uucore::execution_phrase()))]
MissingOperand,
#[error("{}", translate!("rm-error-cannot-remove-no-such-file", "file" => _0.quote()))]
CannotRemoveNoSuchFile(String),
CannotRemoveNoSuchFile(OsString),
#[error("{}", translate!("rm-error-cannot-remove-permission-denied", "file" => _0.quote()))]
CannotRemovePermissionDenied(String),
CannotRemovePermissionDenied(OsString),
#[error("{}", translate!("rm-error-cannot-remove-is-directory", "file" => _0.quote()))]
CannotRemoveIsDirectory(String),
CannotRemoveIsDirectory(OsString),
#[error("{}", translate!("rm-error-dangerous-recursive-operation"))]
DangerousRecursiveOperation,
#[error("{}", translate!("rm-error-use-no-preserve-root"))]
UseNoPreserveRoot,
#[error("{}", translate!("rm-error-refusing-to-remove-directory", "path" => _0))]
RefusingToRemoveDirectory(String),
#[error("{}", translate!("rm-error-refusing-to-remove-directory", "path" => _0.to_string_lossy()))]
RefusingToRemoveDirectory(OsString),
}
impl UError for RmError {}
@@ -366,7 +366,7 @@ pub fn remove(files: &[&OsStr], options: &Options) -> bool {
} else {
show_error!(
"{}",
RmError::CannotRemoveNoSuchFile(filename.to_string_lossy().to_string())
RmError::CannotRemoveNoSuchFile(filename.to_os_string())
);
true
}
@@ -542,7 +542,7 @@ fn handle_dir(path: &Path, options: &Options) -> bool {
if path_is_current_or_parent_directory(path) {
show_error!(
"{}",
RmError::RefusingToRemoveDirectory(path.display().to_string())
RmError::RefusingToRemoveDirectory(path.as_os_str().to_os_string())
);
return true;
}
@@ -559,7 +559,7 @@ fn handle_dir(path: &Path, options: &Options) -> bool {
} else {
show_error!(
"{}",
RmError::CannotRemoveIsDirectory(path.to_string_lossy().to_string())
RmError::CannotRemoveIsDirectory(path.as_os_str().to_os_string())
);
had_err = true;
}
@@ -580,7 +580,7 @@ fn remove_dir(path: &Path, options: &Options) -> bool {
if !options.dir && !options.recursive {
show_error!(
"{}",
RmError::CannotRemoveIsDirectory(path.to_string_lossy().to_string())
RmError::CannotRemoveIsDirectory(path.as_os_str().to_os_string())
);
return true;
}
@@ -621,7 +621,7 @@ fn remove_file(path: &Path, options: &Options) -> bool {
// GNU compatibility (rm/fail-eacces.sh)
show_error!(
"{}",
RmError::CannotRemovePermissionDenied(path.to_string_lossy().to_string())
RmError::CannotRemovePermissionDenied(path.as_os_str().to_os_string())
);
} else {
show_error!("cannot remove {}: {e}", path.quote());
+40
View File
@@ -1037,3 +1037,43 @@ fn test_inaccessible_dir_recursive() {
assert!(!at.dir_exists("a/unreadable"));
assert!(!at.dir_exists("a"));
}
#[test]
#[cfg(target_os = "linux")]
fn test_rm_non_utf8_paths() {
use std::ffi::OsStr;
use std::os::unix::ffi::OsStrExt;
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();
// 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();
assert!(!at.dir_exists(non_utf8_dir_name));
}