diff --git a/src/uu/touch/src/touch.rs b/src/uu/touch/src/touch.rs index 4192a7a83..f7034eee6 100644 --- a/src/uu/touch/src/touch.rs +++ b/src/uu/touch/src/touch.rs @@ -15,6 +15,7 @@ use clap::{crate_version, Arg, ArgAction, ArgGroup, ArgMatches, Command}; use filetime::{set_file_times, set_symlink_file_times, FileTime}; use std::ffi::OsString; use std::fs::{self, File}; +use std::io::{Error, ErrorKind}; use std::path::{Path, PathBuf}; use uucore::display::Quotable; use uucore::error::{FromIo, UResult, USimpleError}; @@ -126,7 +127,23 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { } if let Err(e) = File::create(path) { - show!(e.map_err_context(|| format!("cannot touch {}", path.quote()))); + // we need to check if the path is the path to a directory (ends with a separator) + // we can't use File::create to create a directory + // we cannot use path.is_dir() because it calls fs::metadata which we already called + // when stable, we can change to use e.kind() == std::io::ErrorKind::IsADirectory + let is_directory = if let Some(last_char) = path.to_string_lossy().chars().last() { + last_char == std::path::MAIN_SEPARATOR + } else { + false + }; + if is_directory { + let custom_err = Error::new(ErrorKind::Other, "No such file or directory"); + return Err( + custom_err.map_err_context(|| format!("cannot touch {}", filename.quote())) + ); + } else { + show!(e.map_err_context(|| format!("cannot touch {}", path.quote()))); + } continue; }; diff --git a/tests/by-util/test_touch.rs b/tests/by-util/test_touch.rs index 44a198452..51731b9ff 100644 --- a/tests/by-util/test_touch.rs +++ b/tests/by-util/test_touch.rs @@ -689,10 +689,23 @@ fn test_touch_system_fails() { } #[test] +#[cfg(not(target_os = "windows"))] fn test_touch_trailing_slash() { let (_at, mut ucmd) = at_and_ucmd!(); let file = "no-file/"; - ucmd.args(&[file]).fails(); + ucmd.args(&[file]).fails().stderr_only(format!( + "touch: cannot touch '{file}': No such file or directory\n" + )); +} + +#[test] +#[cfg(target_os = "windows")] +fn test_touch_trailing_slash_windows() { + let (_at, mut ucmd) = at_and_ucmd!(); + let file = "no-file/"; + ucmd.args(&[file]).fails().stderr_only(format!( + "touch: cannot touch '{file}': The filename, directory name, or volume label syntax is incorrect.\n" + )); } #[test]