Merge pull request #10566 from reubenwong97/patch/mktemp-fallback

mktemp: treat empty TMPDIR as unset and fallback to /tmp
This commit is contained in:
Chris Dryden
2026-01-30 19:25:01 -05:00
committed by GitHub
2 changed files with 69 additions and 4 deletions
+12 -4
View File
@@ -44,6 +44,8 @@ const TMPDIR_ENV_VAR: &str = "TMPDIR";
#[cfg(windows)]
const TMPDIR_ENV_VAR: &str = "TMP";
const FALLBACK_TMPDIR: &str = "/tmp";
#[derive(Error, Debug)]
enum MkTempError {
#[error("{}", translate!("mktemp-error-persist-file", "path" => .0.quote()))]
@@ -119,14 +121,12 @@ impl Options {
Some(d) => d.clone(),
// Otherwise use $TMPDIR if set, else use the system's default
// temporary directory.
None => env::var(TMPDIR_ENV_VAR)
.ok()
.map_or_else(env::temp_dir, PathBuf::from),
None => get_tmpdir_env_or_default(),
});
let (tmpdir, template) = match matches.get_one::<OsString>(ARG_TEMPLATE) {
// If no template argument is given, `--tmpdir` is implied.
None => {
let tmpdir = Some(tmpdir.unwrap_or_else(env::temp_dir));
let tmpdir = Some(tmpdir.unwrap_or_else(get_tmpdir_env_or_default));
let template = DEFAULT_TEMPLATE;
(tmpdir, OsString::from(template))
}
@@ -595,6 +595,14 @@ fn exec(dir: &Path, prefix: &str, rand: usize, suffix: &str, make_dir: bool) ->
Ok(path)
}
/// Reads from `TMPDIR_ENV_VAR` but defaults to /tmp if value is set to empty string.
fn get_tmpdir_env_or_default() -> PathBuf {
match env::var_os(TMPDIR_ENV_VAR) {
Some(val) if val.is_empty() => PathBuf::from(FALLBACK_TMPDIR),
_ => env::temp_dir(),
}
}
/// Create a temporary file or directory
///
/// Behavior is determined by the `options` parameter, see [`Options`] for details.
+57
View File
@@ -862,6 +862,63 @@ fn test_nonexistent_tmpdir_env_var() {
}
}
#[test]
fn test_empty_tmpdir_env_var() {
#[cfg(not(any(windows, target_os = "android")))]
{
let result = new_ucmd!().env(TMPDIR, "").succeeds();
assert!(result.stdout_str().starts_with("/tmp"));
}
#[cfg(any(windows, target_os = "android"))]
{
let result = new_ucmd!().env(TMPDIR, "").fails();
result.no_stdout();
let stderr = result.stderr_str();
assert!(
stderr.starts_with("mktemp: failed to create file via template"),
"{stderr}"
);
#[cfg(windows)]
assert!(
stderr.ends_with("/tmp\\tmp.XXXXXXXXXX': No such file or directory\n"),
"{stderr}",
);
#[cfg(target_os = "android")]
assert!(
stderr.ends_with("/tmp/tmp.XXXXXXXXXX': No such file or directory\n"),
"{stderr}",
);
}
#[cfg(not(any(windows, target_os = "android")))]
{
let result = new_ucmd!().env(TMPDIR, "").arg("-d").succeeds();
assert!(result.stdout_str().starts_with("/tmp"));
}
#[cfg(any(windows, target_os = "android"))]
{
let result = new_ucmd!().env(TMPDIR, "").arg("-d").fails();
result.no_stdout();
let stderr = result.stderr_str();
assert!(
stderr.starts_with("mktemp: failed to create directory via template"),
"{stderr}"
);
#[cfg(windows)]
assert!(
stderr.ends_with("/tmp\\tmp.XXXXXXXXXX': No such file or directory\n"),
"{stderr}",
);
#[cfg(target_os = "android")]
assert!(
stderr.ends_with("/tmp/tmp.XXXXXXXXXX': No such file or directory\n"),
"{stderr}",
);
}
}
#[test]
fn test_nonexistent_dir_prefix() {
#[cfg(not(windows))]