mirror of
https://github.com/uutils/coreutils
synced 2024-12-13 23:02:38 +00:00
Merge pull request #3940 from jfinkels/mktemp-nonexistent-tmpdir-env-var
mktemp: add message for directory not found
This commit is contained in:
commit
1e268b1a8f
2 changed files with 161 additions and 28 deletions
|
@ -16,6 +16,7 @@ use uucore::format_usage;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
use std::io::ErrorKind;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
use std::path::{Path, PathBuf, MAIN_SEPARATOR};
|
use std::path::{Path, PathBuf, MAIN_SEPARATOR};
|
||||||
|
|
||||||
|
@ -54,6 +55,9 @@ enum MkTempError {
|
||||||
SuffixContainsDirSeparator(String),
|
SuffixContainsDirSeparator(String),
|
||||||
InvalidTemplate(String),
|
InvalidTemplate(String),
|
||||||
TooManyTemplates,
|
TooManyTemplates,
|
||||||
|
|
||||||
|
/// When a specified temporary directory could not be found.
|
||||||
|
NotFound(String, String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UError for MkTempError {
|
impl UError for MkTempError {
|
||||||
|
@ -93,6 +97,12 @@ impl Display for MkTempError {
|
||||||
TooManyTemplates => {
|
TooManyTemplates => {
|
||||||
write!(f, "too many templates")
|
write!(f, "too many templates")
|
||||||
}
|
}
|
||||||
|
NotFound(template_type, s) => write!(
|
||||||
|
f,
|
||||||
|
"failed to create {} via template {}: No such file or directory",
|
||||||
|
template_type,
|
||||||
|
s.quote()
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -460,37 +470,74 @@ pub fn dry_exec(tmpdir: &str, prefix: &str, rand: usize, suffix: &str) -> UResul
|
||||||
println_verbatim(tmpdir).map_err_context(|| "failed to print directory name".to_owned())
|
println_verbatim(tmpdir).map_err_context(|| "failed to print directory name".to_owned())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exec(dir: &str, prefix: &str, rand: usize, suffix: &str, make_dir: bool) -> UResult<()> {
|
/// Create a temporary directory with the given parameters.
|
||||||
let context = || {
|
///
|
||||||
format!(
|
/// This function creates a temporary directory as a subdirectory of
|
||||||
"failed to create file via template '{}{}{}'",
|
/// `dir`. The name of the directory is the concatenation of `prefix`,
|
||||||
prefix,
|
/// a string of `rand` random characters, and `suffix`. The
|
||||||
"X".repeat(rand),
|
/// permissions of the directory are set to `u+rwx`
|
||||||
suffix
|
///
|
||||||
)
|
/// # Errors
|
||||||
};
|
///
|
||||||
|
/// If the temporary directory could not be written to disk or if the
|
||||||
|
/// given directory `dir` does not exist.
|
||||||
|
fn make_temp_dir(dir: &str, prefix: &str, rand: usize, suffix: &str) -> UResult<PathBuf> {
|
||||||
let mut builder = Builder::new();
|
let mut builder = Builder::new();
|
||||||
builder.prefix(prefix).rand_bytes(rand).suffix(suffix);
|
builder.prefix(prefix).rand_bytes(rand).suffix(suffix);
|
||||||
|
match builder.tempdir_in(&dir) {
|
||||||
let path = if make_dir {
|
Ok(d) => {
|
||||||
builder
|
// `into_path` consumes the TempDir without removing it
|
||||||
.tempdir_in(&dir)
|
let path = d.into_path();
|
||||||
.map_err_context(context)?
|
#[cfg(not(windows))]
|
||||||
.into_path() // `into_path` consumes the TempDir without removing it
|
fs::set_permissions(&path, fs::Permissions::from_mode(0o700))?;
|
||||||
} else {
|
Ok(path)
|
||||||
builder
|
}
|
||||||
.tempfile_in(&dir)
|
Err(e) if e.kind() == ErrorKind::NotFound => {
|
||||||
.map_err_context(context)?
|
let filename = format!("{}{}{}", prefix, "X".repeat(rand), suffix);
|
||||||
.keep() // `keep` ensures that the file is not deleted
|
let path = Path::new(dir).join(filename);
|
||||||
.map_err(|e| MkTempError::PersistError(e.file.path().to_path_buf()))?
|
let s = path.display().to_string();
|
||||||
.1
|
Err(MkTempError::NotFound("directory".to_string(), s).into())
|
||||||
};
|
}
|
||||||
|
Err(e) => Err(e.into()),
|
||||||
#[cfg(not(windows))]
|
|
||||||
if make_dir {
|
|
||||||
fs::set_permissions(&path, fs::Permissions::from_mode(0o700))?;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a temporary file with the given parameters.
|
||||||
|
///
|
||||||
|
/// This function creates a temporary file in the directory `dir`. The
|
||||||
|
/// name of the file is the concatenation of `prefix`, a string of
|
||||||
|
/// `rand` random characters, and `suffix`. The permissions of the
|
||||||
|
/// file are set to `u+rw`.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// If the file could not be written to disk or if the directory does
|
||||||
|
/// not exist.
|
||||||
|
fn make_temp_file(dir: &str, prefix: &str, rand: usize, suffix: &str) -> UResult<PathBuf> {
|
||||||
|
let mut builder = Builder::new();
|
||||||
|
builder.prefix(prefix).rand_bytes(rand).suffix(suffix);
|
||||||
|
match builder.tempfile_in(&dir) {
|
||||||
|
// `keep` ensures that the file is not deleted
|
||||||
|
Ok(named_tempfile) => match named_tempfile.keep() {
|
||||||
|
Ok((_, pathbuf)) => Ok(pathbuf),
|
||||||
|
Err(e) => Err(MkTempError::PersistError(e.file.path().to_path_buf()).into()),
|
||||||
|
},
|
||||||
|
Err(e) if e.kind() == ErrorKind::NotFound => {
|
||||||
|
let filename = format!("{}{}{}", prefix, "X".repeat(rand), suffix);
|
||||||
|
let path = Path::new(dir).join(filename);
|
||||||
|
let s = path.display().to_string();
|
||||||
|
Err(MkTempError::NotFound("file".to_string(), s).into())
|
||||||
|
}
|
||||||
|
Err(e) => Err(e.into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn exec(dir: &str, prefix: &str, rand: usize, suffix: &str, make_dir: bool) -> UResult<()> {
|
||||||
|
let path = if make_dir {
|
||||||
|
make_temp_dir(dir, prefix, rand, suffix)?
|
||||||
|
} else {
|
||||||
|
make_temp_file(dir, prefix, rand, suffix)?
|
||||||
|
};
|
||||||
|
|
||||||
// Get just the last component of the path to the created
|
// Get just the last component of the path to the created
|
||||||
// temporary file or directory.
|
// temporary file or directory.
|
||||||
|
|
|
@ -739,3 +739,89 @@ fn test_tmpdir_env_var() {
|
||||||
assert_matches_template!(template, filename);
|
assert_matches_template!(template, filename);
|
||||||
assert!(at.file_exists(filename));
|
assert!(at.file_exists(filename));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_nonexistent_tmpdir_env_var() {
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
new_ucmd!().env(TMPDIR, "no/such/dir").fails().stderr_only("mktemp: failed to create file via template 'no/such/dir/tmp.XXXXXXXXXX': No such file or directory\n");
|
||||||
|
#[cfg(windows)]
|
||||||
|
{
|
||||||
|
let result = new_ucmd!().env(TMPDIR, r"no\such\dir").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))]
|
||||||
|
new_ucmd!().env(TMPDIR, "no/such/dir").arg("-d").fails().stderr_only("mktemp: failed to create directory via template 'no/such/dir/tmp.XXXXXXXXXX': No such file or directory\n");
|
||||||
|
#[cfg(windows)]
|
||||||
|
{
|
||||||
|
let result = new_ucmd!().env(TMPDIR, r"no\such\dir").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))]
|
||||||
|
new_ucmd!().arg("d/XXX").fails().stderr_only(
|
||||||
|
"mktemp: failed to create file via template 'd/XXX': No such file or directory\n",
|
||||||
|
);
|
||||||
|
#[cfg(windows)]
|
||||||
|
{
|
||||||
|
let result = new_ucmd!().arg(r"d\XXX").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("d\\XXX': No such file or directory\n"),
|
||||||
|
"{}",
|
||||||
|
stderr
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
new_ucmd!().arg("-d").arg("d/XXX").fails().stderr_only(
|
||||||
|
"mktemp: failed to create directory via template 'd/XXX': No such file or directory\n",
|
||||||
|
);
|
||||||
|
#[cfg(windows)]
|
||||||
|
{
|
||||||
|
let result = new_ucmd!().arg("-d").arg(r"d\XXX").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("d\\XXX': No such file or directory\n"),
|
||||||
|
"{}",
|
||||||
|
stderr
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue