mirror of
https://github.com/uutils/coreutils.git
synced 2026-06-10 15:48:22 -07:00
Add non-UTF-8 filename support to tee and improve fuzzer coverage
This commit is contained in:
@@ -17,8 +17,22 @@ use std::path::PathBuf;
|
||||
use uufuzz::{run_gnu_cmd, CommandResult};
|
||||
// Programs that typically take file/path arguments and should be tested
|
||||
static PATH_PROGRAMS: &[&str] = &[
|
||||
"basename", "cat", "chmod", "cp", "dirname", "du", "head", "ln", "ls", "mkdir", "mv",
|
||||
"readlink", "realpath", "rm", "rmdir", "tail", "touch", "unlink",
|
||||
// Core file operations
|
||||
"cat", "cp", "mv", "rm", "ln", "link", "unlink", "touch", "truncate",
|
||||
// Directory operations
|
||||
"ls", "mkdir", "rmdir", "du", "stat", "mktemp",
|
||||
// Path operations
|
||||
"basename", "dirname", "readlink", "realpath", "pathchk",
|
||||
// File content operations
|
||||
"head", "tail", "tee", "more", "od", "wc", "cksum", "sum",
|
||||
// File processing
|
||||
"sort", "uniq", "split", "csplit", "cut", "tr", "shred",
|
||||
// File permissions/ownership
|
||||
"chmod", "chown", "chgrp", "install",
|
||||
// Text processing with files
|
||||
"comm", "join", "paste", "pr", "fmt", "fold", "expand", "unexpand",
|
||||
// Directory listing variants
|
||||
"dir", "vdir",
|
||||
];
|
||||
|
||||
fn generate_non_utf8_bytes() -> Vec<u8> {
|
||||
@@ -84,20 +98,65 @@ fn test_program_with_non_utf8_path(program: &str, path: &PathBuf) -> CommandResu
|
||||
|
||||
// Build appropriate arguments for each program
|
||||
let local_args = match program {
|
||||
// Programs that need mode/permissions
|
||||
"chmod" => vec![
|
||||
OsString::from(program),
|
||||
OsString::from("644"),
|
||||
path_os.to_owned(),
|
||||
],
|
||||
"cp" | "mv" | "ln" => {
|
||||
// These need a destination - create a temp destination
|
||||
"chown" => vec![
|
||||
OsString::from(program),
|
||||
OsString::from("root:root"),
|
||||
path_os.to_owned(),
|
||||
],
|
||||
"chgrp" => vec![
|
||||
OsString::from(program),
|
||||
OsString::from("root"),
|
||||
path_os.to_owned(),
|
||||
],
|
||||
// Programs that need source and destination
|
||||
"cp" | "mv" | "ln" | "link" => {
|
||||
let dest_path = path.with_extension("dest");
|
||||
vec![
|
||||
OsString::from(program),
|
||||
path_os.to_owned(),
|
||||
dest_path.as_os_str().to_owned(),
|
||||
]
|
||||
}
|
||||
},
|
||||
"install" => {
|
||||
let dest_path = path.with_extension("dest");
|
||||
vec![
|
||||
OsString::from(program),
|
||||
path_os.to_owned(),
|
||||
dest_path.as_os_str().to_owned(),
|
||||
]
|
||||
},
|
||||
// Programs that need size/truncate operations
|
||||
"truncate" => vec![
|
||||
OsString::from(program),
|
||||
OsString::from("--size=0"),
|
||||
path_os.to_owned(),
|
||||
],
|
||||
"split" => vec![
|
||||
OsString::from(program),
|
||||
path_os.to_owned(),
|
||||
OsString::from("split_prefix_"),
|
||||
],
|
||||
"csplit" => vec![
|
||||
OsString::from(program),
|
||||
path_os.to_owned(),
|
||||
OsString::from("1"),
|
||||
],
|
||||
// Programs that work with multiple files (use just one for testing)
|
||||
"comm" | "join" => {
|
||||
// These need two files, use the same file twice for simplicity
|
||||
vec![
|
||||
OsString::from(program),
|
||||
path_os.to_owned(),
|
||||
path_os.to_owned(),
|
||||
]
|
||||
},
|
||||
// Programs that typically take file input
|
||||
_ => vec![OsString::from(program), path_os.to_owned()],
|
||||
};
|
||||
|
||||
@@ -175,7 +234,7 @@ fuzz_target!(|_data: &[u8]| {
|
||||
}
|
||||
|
||||
// Special cases for programs that need additional testing
|
||||
if **program == "mkdir" {
|
||||
if **program == "mkdir" || **program == "mktemp" {
|
||||
let non_utf8_dir_name = generate_non_utf8_osstring();
|
||||
let non_utf8_dir = temp_root.join(non_utf8_dir_name);
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
// cSpell:ignore POLLERR POLLRDBAND pfds revents
|
||||
|
||||
use clap::{Arg, ArgAction, Command, builder::PossibleValue};
|
||||
use std::ffi::OsString;
|
||||
use std::fs::OpenOptions;
|
||||
use std::io::{Error, ErrorKind, Read, Result, Write, stdin, stdout};
|
||||
use std::path::PathBuf;
|
||||
@@ -34,7 +35,7 @@ struct Options {
|
||||
append: bool,
|
||||
ignore_interrupts: bool,
|
||||
ignore_pipe_errors: bool,
|
||||
files: Vec<String>,
|
||||
files: Vec<OsString>,
|
||||
output_error: Option<OutputErrorMode>,
|
||||
}
|
||||
|
||||
@@ -77,8 +78,8 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||
};
|
||||
|
||||
let files = matches
|
||||
.get_many::<String>(options::FILE)
|
||||
.map(|v| v.map(ToString::to_string).collect())
|
||||
.get_many::<OsString>(options::FILE)
|
||||
.map(|v| v.cloned().collect())
|
||||
.unwrap_or_default();
|
||||
|
||||
let options = Options {
|
||||
@@ -127,7 +128,8 @@ pub fn uu_app() -> Command {
|
||||
.arg(
|
||||
Arg::new(options::FILE)
|
||||
.action(ArgAction::Append)
|
||||
.value_hint(clap::ValueHint::FilePath),
|
||||
.value_hint(clap::ValueHint::FilePath)
|
||||
.value_parser(clap::value_parser!(OsString)),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::IGNORE_PIPE_ERRORS)
|
||||
@@ -252,7 +254,7 @@ fn copy(mut input: impl Read, mut output: impl Write) -> Result<usize> {
|
||||
/// If that error should lead to program termination, this function returns Some(Err()),
|
||||
/// otherwise it returns None.
|
||||
fn open(
|
||||
name: &str,
|
||||
name: &OsString,
|
||||
append: bool,
|
||||
output_error: Option<&OutputErrorMode>,
|
||||
) -> Option<Result<NamedWriter>> {
|
||||
@@ -266,10 +268,10 @@ fn open(
|
||||
match mode.write(true).create(true).open(path.as_path()) {
|
||||
Ok(file) => Some(Ok(NamedWriter {
|
||||
inner: Box::new(file),
|
||||
name: name.to_owned(),
|
||||
name: name.to_string_lossy().to_string(),
|
||||
})),
|
||||
Err(f) => {
|
||||
show_error!("{}: {f}", name.maybe_quote());
|
||||
show_error!("{}: {f}", name.to_string_lossy().maybe_quote());
|
||||
match output_error {
|
||||
Some(OutputErrorMode::Exit | OutputErrorMode::ExitNoPipe) => Some(Err(f)),
|
||||
_ => None,
|
||||
|
||||
Reference in New Issue
Block a user