diff --git a/src/uu/mktemp/src/mktemp.rs b/src/uu/mktemp/src/mktemp.rs index 1f872714f09..f4cb420aad1 100644 --- a/src/uu/mktemp/src/mktemp.rs +++ b/src/uu/mktemp/src/mktemp.rs @@ -8,7 +8,7 @@ use clap::builder::{TypedValueParser, ValueParserFactory}; use clap::{Arg, ArgAction, ArgMatches, Command}; use uucore::display::{Quotable, println_verbatim}; -use uucore::error::{FromIo, UError, UResult, UUsageError}; +use uucore::error::{FromIo, UError, UResult, UUsageError, strip_errno}; use uucore::format_usage; use uucore::translate; @@ -74,6 +74,9 @@ enum MkTempError { #[error("{}", translate!("mktemp-error-not-found", "template_type" => .0.clone(), "template" => .1.quote()))] NotFound(String, PathBuf), + + #[error("{}", strip_errno(.0))] + Io(std::io::Error), } impl UError for MkTempError { @@ -570,7 +573,7 @@ fn make_temp_dir(dir: &Path, prefix: &str, rand: usize, suffix: &str) -> UResult let path = Path::new(dir).join(filename); Err(MkTempError::NotFound(translate!("mktemp-template-type-directory"), path).into()) } - Err(e) => Err(e.into()), + Err(e) => Err(MkTempError::Io(e).into()), } } @@ -599,7 +602,7 @@ fn make_temp_file(dir: &Path, prefix: &str, rand: usize, suffix: &str) -> UResul let path = Path::new(dir).join(filename); Err(MkTempError::NotFound(translate!("mktemp-template-type-file"), path).into()) } - Err(e) => Err(e.into()), + Err(e) => Err(MkTempError::Io(e).into()), } } diff --git a/tests/by-util/test_mktemp.rs b/tests/by-util/test_mktemp.rs index 0fa2896bb6f..fbbb7b4cd54 100644 --- a/tests/by-util/test_mktemp.rs +++ b/tests/by-util/test_mktemp.rs @@ -1209,3 +1209,45 @@ fn test_mktemp_hidden_file_single_dot() { template_name.len() ); } + +/// Creating a temporary file or directory in an unwritable directory must fail +/// with a clean `Permission denied` message, without leaking the raw +/// `(os error N)` suffix or the internal `at path ...` detail that the +/// underlying `tempfile` crate would otherwise embed. +#[cfg(unix)] +#[test] +fn test_permission_denied_clean_message() { + use std::fs; + use std::os::unix::fs::PermissionsExt; + use uucore::process::geteuid; + + // chmod 000 does not block root, so the assertion would not hold. + if geteuid() == 0 { + return; + } + + let scene = TestScenario::new(util_name!()); + let dir = scene.fixtures.plus("noperm"); + fs::create_dir_all(&dir).unwrap(); + fs::set_permissions(&dir, fs::Permissions::from_mode(0o000)).unwrap(); + + // File case: `mktemp -p