From 3e38c2ceb698c22f4fff335f62ee5a3e9190b833 Mon Sep 17 00:00:00 2001 From: Reuben Wong Date: Thu, 29 Jan 2026 23:02:48 +0800 Subject: [PATCH 1/7] mktemp: treat empty TMPDIR as unset and fallback to /tmp --- src/uu/mktemp/src/mktemp.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/uu/mktemp/src/mktemp.rs b/src/uu/mktemp/src/mktemp.rs index 5e3b8aa58..f84f00a00 100644 --- a/src/uu/mktemp/src/mktemp.rs +++ b/src/uu/mktemp/src/mktemp.rs @@ -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::(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. From 5c721ad0a3c8234810352e57dd7243d17c23e7b3 Mon Sep 17 00:00:00 2001 From: Reuben Wong Date: Fri, 30 Jan 2026 10:00:46 +0800 Subject: [PATCH 2/7] retrigger checks From f6151c59de669f87603cd78ce47eedcbdb629821 Mon Sep 17 00:00:00 2001 From: Reuben Wong Date: Fri, 30 Jan 2026 18:07:46 +0800 Subject: [PATCH 3/7] add tests for correct creation --- tests/by-util/test_mktemp.rs | 45 ++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/tests/by-util/test_mktemp.rs b/tests/by-util/test_mktemp.rs index cedcb4927..f99c7d128 100644 --- a/tests/by-util/test_mktemp.rs +++ b/tests/by-util/test_mktemp.rs @@ -862,6 +862,51 @@ fn test_nonexistent_tmpdir_env_var() { } } +#[test] +fn test_empty_tmpdir_env_var() { + #[cfg(not(windows))] + { + let result = new_ucmd!().env(TMPDIR, "").succeeds(); + assert!(result.stdout_str().starts_with("/tmp")); + } + + #[cfg(windows)] + { + 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}" + ); + assert!( + stderr.ends_with("no\\such\\dir\\tmp.XXXXXXXXXX': No such file or directory\n"), + "{stderr}", + ); + } + + #[cfg(not(windows))] + { + let result = new_ucmd!().env(TMPDIR, "").arg("-d").succeeds(); + assert!(result.stdout_str().starts_with("/tmp")); + } + + #[cfg(windows)] + { + 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}" + ); + assert!( + stderr.ends_with("no\\such\\dir\\tmp.XXXXXXXXXX': No such file or directory\n"), + "{stderr}", + ); + } +} + #[test] fn test_nonexistent_dir_prefix() { #[cfg(not(windows))] From 27d930c1ce5b74988a9f7b4163cc070e31e1cae4 Mon Sep 17 00:00:00 2001 From: Reuben Wong Date: Fri, 30 Jan 2026 18:28:59 +0800 Subject: [PATCH 4/7] fix test based on windows build --- tests/by-util/test_mktemp.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/by-util/test_mktemp.rs b/tests/by-util/test_mktemp.rs index f99c7d128..e40d5c06c 100644 --- a/tests/by-util/test_mktemp.rs +++ b/tests/by-util/test_mktemp.rs @@ -880,7 +880,7 @@ fn test_empty_tmpdir_env_var() { "{stderr}" ); assert!( - stderr.ends_with("no\\such\\dir\\tmp.XXXXXXXXXX': No such file or directory\n"), + stderr.ends_with("/tmp\tmp.XXXXXXXXXX': No such file or directory\n"), "{stderr}", ); } @@ -901,7 +901,7 @@ fn test_empty_tmpdir_env_var() { "{stderr}" ); assert!( - stderr.ends_with("no\\such\\dir\\tmp.XXXXXXXXXX': No such file or directory\n"), + stderr.ends_with("/tmp\tmp.XXXXXXXXXX': No such file or directory\n"), "{stderr}", ); } From 2fd74a89dcd4bf4f5dd3046850794d0bb9eda1dc Mon Sep 17 00:00:00 2001 From: Reuben Wong Date: Fri, 30 Jan 2026 22:28:41 +0800 Subject: [PATCH 5/7] fix unescaped t char --- tests/by-util/test_mktemp.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/by-util/test_mktemp.rs b/tests/by-util/test_mktemp.rs index e40d5c06c..b4d9c6c27 100644 --- a/tests/by-util/test_mktemp.rs +++ b/tests/by-util/test_mktemp.rs @@ -880,7 +880,7 @@ fn test_empty_tmpdir_env_var() { "{stderr}" ); assert!( - stderr.ends_with("/tmp\tmp.XXXXXXXXXX': No such file or directory\n"), + stderr.ends_with("/tmp\\tmp.XXXXXXXXXX': No such file or directory\n"), "{stderr}", ); } @@ -901,7 +901,7 @@ fn test_empty_tmpdir_env_var() { "{stderr}" ); assert!( - stderr.ends_with("/tmp\tmp.XXXXXXXXXX': No such file or directory\n"), + stderr.ends_with("/tmp\\tmp.XXXXXXXXXX': No such file or directory\n"), "{stderr}", ); } From 8001be03353fb2f113f1dc2054214e6baadd5ce6 Mon Sep 17 00:00:00 2001 From: Reuben Wong Date: Sat, 31 Jan 2026 00:02:49 +0800 Subject: [PATCH 6/7] failure expected on android temp directory is not located at /tmp --- tests/by-util/test_mktemp.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/by-util/test_mktemp.rs b/tests/by-util/test_mktemp.rs index b4d9c6c27..652f32a40 100644 --- a/tests/by-util/test_mktemp.rs +++ b/tests/by-util/test_mktemp.rs @@ -864,13 +864,13 @@ fn test_nonexistent_tmpdir_env_var() { #[test] fn test_empty_tmpdir_env_var() { - #[cfg(not(windows))] + #[cfg(not(any(windows, target_os = "android")))] { let result = new_ucmd!().env(TMPDIR, "").succeeds(); assert!(result.stdout_str().starts_with("/tmp")); } - #[cfg(windows)] + #[cfg(any(windows, target_os = "android"))] { let result = new_ucmd!().env(TMPDIR, "").fails(); result.no_stdout(); @@ -885,13 +885,13 @@ fn test_empty_tmpdir_env_var() { ); } - #[cfg(not(windows))] + #[cfg(not(any(windows, target_os = "android")))] { let result = new_ucmd!().env(TMPDIR, "").arg("-d").succeeds(); assert!(result.stdout_str().starts_with("/tmp")); } - #[cfg(windows)] + #[cfg(any(windows, target_os = "android"))] { let result = new_ucmd!().env(TMPDIR, "").arg("-d").fails(); result.no_stdout(); From fe454ba5ae8bd73d0af84e503de678c9c557a7b1 Mon Sep 17 00:00:00 2001 From: Reuben Wong Date: Sat, 31 Jan 2026 00:45:25 +0800 Subject: [PATCH 7/7] asserts specific to target build --- tests/by-util/test_mktemp.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/by-util/test_mktemp.rs b/tests/by-util/test_mktemp.rs index 652f32a40..306f147d8 100644 --- a/tests/by-util/test_mktemp.rs +++ b/tests/by-util/test_mktemp.rs @@ -879,10 +879,16 @@ fn test_empty_tmpdir_env_var() { 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")))] @@ -900,10 +906,16 @@ fn test_empty_tmpdir_env_var() { 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}", + ); } }