1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 19:47:45 +00:00

Merge pull request #6907 from sylvestre/tr2

tr: generate an error for real if the input is a directory
This commit is contained in:
Daniel Hofstetter 2024-12-04 10:20:08 +01:00 committed by GitHub
commit d878f6c774
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 45 additions and 4 deletions

View file

@ -19,7 +19,7 @@ path = "src/tr.rs"
[dependencies]
nom = { workspace = true }
clap = { workspace = true }
uucore = { workspace = true }
uucore = { workspace = true, features = ["fs"] }
[[bin]]
name = "tr"

View file

@ -8,17 +8,17 @@
mod operation;
mod unicode_table;
use crate::operation::DeleteOperation;
use clap::{crate_version, value_parser, Arg, ArgAction, Command};
use operation::{
translate_input, Sequence, SqueezeOperation, SymbolTranslator, TranslateOperation,
};
use std::ffi::OsString;
use std::io::{stdin, stdout, BufWriter};
use uucore::{format_usage, help_about, help_section, help_usage, os_str_as_bytes, show};
use crate::operation::DeleteOperation;
use uucore::display::Quotable;
use uucore::error::{UResult, USimpleError, UUsageError};
use uucore::fs::is_stdin_directory;
use uucore::{format_usage, help_about, help_section, help_usage, os_str_as_bytes, show};
const ABOUT: &str = help_about!("tr.md");
const AFTER_HELP: &str = help_section!("after help", "tr.md");
@ -126,6 +126,10 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
translating,
)?;
if is_stdin_directory(&stdin) {
return Err(USimpleError::new(1, "read error: Is a directory"));
}
// '*_op' are the operations that need to be applied, in order.
if delete_flag {
if squeeze_flag {

View file

@ -20,6 +20,7 @@ use std::ffi::{OsStr, OsString};
use std::fs;
use std::fs::read_dir;
use std::hash::Hash;
use std::io::Stdin;
use std::io::{Error, ErrorKind, Result as IOResult};
#[cfg(unix)]
use std::os::unix::{fs::MetadataExt, io::AsRawFd};
@ -721,6 +722,34 @@ pub fn path_ends_with_terminator(path: &Path) -> bool {
.map_or(false, |wide| wide == b'/'.into() || wide == b'\\'.into())
}
/// Checks if the standard input (stdin) is a directory.
///
/// # Arguments
///
/// * `stdin` - A reference to the standard input handle.
///
/// # Returns
///
/// * `bool` - Returns `true` if stdin is a directory, `false` otherwise.
pub fn is_stdin_directory(stdin: &Stdin) -> bool {
#[cfg(unix)]
{
use nix::sys::stat::fstat;
let mode = fstat(stdin.as_raw_fd()).unwrap().st_mode as mode_t;
has!(mode, S_IFDIR)
}
#[cfg(windows)]
{
use std::os::windows::io::AsRawHandle;
let handle = stdin.as_raw_handle();
if let Ok(metadata) = fs::metadata(format!("{}", handle as usize)) {
return metadata.is_dir();
}
false
}
}
pub mod sane_blksize {
#[cfg(not(target_os = "windows"))]

View file

@ -20,6 +20,14 @@ fn test_invalid_input() {
.fails()
.code_is(1)
.stderr_contains("tr: extra operand '<'");
#[cfg(unix)]
new_ucmd!()
.args(&["1", "1"])
// will test "tr 1 1 < ."
.set_stdin(std::process::Stdio::from(std::fs::File::open(".").unwrap()))
.fails()
.code_is(1)
.stderr_contains("tr: read error: Is a directory");
}
#[test]