From 1f554739fd937e0699aae6efcc56248acd89aaf2 Mon Sep 17 00:00:00 2001 From: Logic769 Date: Fri, 30 Oct 2026 05:45:50 +0800 Subject: [PATCH 1/2] mktemp: treat an empty TMPDIR as unset --- src/uu/mktemp/src/mktemp.rs | 18 +++++++-------- tests/by-util/test_mktemp.rs | 43 ++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 10 deletions(-) diff --git a/src/uu/mktemp/src/mktemp.rs b/src/uu/mktemp/src/mktemp.rs index 64281e5756a..79810117643 100644 --- a/src/uu/mktemp/src/mktemp.rs +++ b/src/uu/mktemp/src/mktemp.rs @@ -131,22 +131,20 @@ impl Options { (tmpdir, OsString::from(template)) } Some(template) => { - let tmpdir = if let Some(tmpdir) = env::var_os(TMPDIR_ENV_VAR) + let tmpdir = if let Some(tmpdir) = + env::var_os(TMPDIR_ENV_VAR).filter(|val| !val.is_empty()) && matches.get_flag(OPT_T) { + // A non-empty `$TMPDIR` has priority over `-p` when + // `-t` is given. An empty `$TMPDIR` is treated as + // unset, so `-p` or the system default is used instead. Some(PathBuf::from(tmpdir)) } else if tmpdir.is_some() { tmpdir } else if matches.get_flag(OPT_T) || matches.contains_id(OPT_TMPDIR) { - // If --tmpdir is given without an argument, or -t is given - // export in TMPDIR - #[cfg(target_os = "wasi")] - // WASI's `std::env::temp_dir()` unconditionally panics - let default_tmp_dir = env::var_os(TMPDIR_ENV_VAR) - .map_or_else(|| PathBuf::from(FALLBACK_TMPDIR), PathBuf::from); - #[cfg(not(target_os = "wasi"))] - let default_tmp_dir = env::temp_dir(); - Some(default_tmp_dir) + // If --tmpdir is given without an argument, or -t is given, + // export in TMPDIR. + Some(get_tmpdir_env_or_default()) } else { None }; diff --git a/tests/by-util/test_mktemp.rs b/tests/by-util/test_mktemp.rs index ca93e30b466..b40163d5603 100644 --- a/tests/by-util/test_mktemp.rs +++ b/tests/by-util/test_mktemp.rs @@ -937,6 +937,49 @@ fn test_empty_tmpdir_env_var() { } } +#[test] +#[cfg_attr(wasi_runner, ignore = "WASI sandbox: host paths not visible")] +fn test_empty_tmpdir_env_var_with_template() { + #[cfg(not(any(windows, target_os = "android")))] + { + let scene = TestScenario::new(util_name!()); + let pathname = scene.fixtures.as_string(); + + // An empty `$TMPDIR` must be treated as unset, so `-t` and + // `--tmpdir` fall back to the system default temporary directory. + for args in [ + vec!["-t", TEST_TEMPLATE1], + vec!["--tmpdir", TEST_TEMPLATE1], + vec!["-d", "-t", TEST_TEMPLATE1], + ] { + let result = scene.ucmd().env(TMPDIR, "").args(&args).succeeds(); + let path = PathBuf::from(result.stdout_str().trim()); + assert!( + path.starts_with("/tmp"), + "expected a path under /tmp, got {path:?}", + ); + if args.contains(&"-d") { + let _ = std::fs::remove_dir(&path); + } else { + let _ = std::fs::remove_file(&path); + } + } + + // `-p` must take precedence over the empty `$TMPDIR`. + let result = scene + .ucmd() + .env(TMPDIR, "") + .args(&["-p", &pathname, "-t", TEST_TEMPLATE1]) + .succeeds(); + let path = PathBuf::from(result.stdout_str().trim()); + assert!( + path.starts_with(&pathname), + "expected a path under {pathname}, got {path:?}", + ); + let _ = std::fs::remove_file(&path); + } +} + #[test] fn test_nonexistent_dir_prefix() { #[cfg(not(windows))] From 83583d622e55e1965aeee486d88c97cddb0765d1 Mon Sep 17 00:00:00 2001 From: Logic769 Date: Mon, 2 Nov 2026 10:12:05 +0800 Subject: [PATCH 2/2] test(mktemp): check created path type instead of arguments --- tests/by-util/test_mktemp.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/by-util/test_mktemp.rs b/tests/by-util/test_mktemp.rs index b40163d5603..72b3b640ffc 100644 --- a/tests/by-util/test_mktemp.rs +++ b/tests/by-util/test_mktemp.rs @@ -958,7 +958,7 @@ fn test_empty_tmpdir_env_var_with_template() { path.starts_with("/tmp"), "expected a path under /tmp, got {path:?}", ); - if args.contains(&"-d") { + if path.is_dir() { let _ = std::fs::remove_dir(&path); } else { let _ = std::fs::remove_file(&path);