Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions src/uu/mktemp/src/mktemp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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()),
}
}

Expand Down Expand Up @@ -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()),
}
}

Expand Down
42 changes: 42 additions & 0 deletions tests/by-util/test_mktemp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
fn test_permission_denied_clean_message() {
fn test_permission_denied() {

The description should focus on testing the behavior being testing rather than lacking the specific (os error N) suffix (which is obvious).

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 <dir>` (default template) creates inside <dir>.
scene
.ucmd()
.arg("-p")
.arg(&dir)
.fails()
.stderr_only("mktemp: Permission denied\n");

// Directory case: `mktemp -d -p <dir>`.
scene
.ucmd()
.arg("-d")
.arg("-p")
.arg(&dir)
.fails()
.stderr_only("mktemp: Permission denied\n");

// Restore perms so the fixture tempdir cleanup can remove the entry.
let _ = fs::set_permissions(&dir, fs::Permissions::from_mode(0o755));
}
Loading