use std::{
fs::{DirBuilder, Permissions},
os::unix::fs::{DirBuilderExt, PermissionsExt},
path::PathBuf,
};
use tempfile::{Builder, TempDir, env};
use uuid::Uuid;
pub fn create_temp_dir(dir_path: Option<PathBuf>) -> TempDir {
Builder::new()
.permissions(Permissions::from_mode(0o700))
.prefix("uhyve-")
.suffix(&Uuid::new_v4().to_string())
.tempdir_in(dir_path.unwrap_or_else(|| {
let env_temp_dir = {
let mut env_temp_dir = env::temp_dir();
debug_assert!(!env_temp_dir.metadata().unwrap().permissions().readonly());
env_temp_dir.push(format!("uhyve-{}", unsafe { libc::getuid() }));
env_temp_dir
};
for i in 0..3 {
use std::io::ErrorKind;
if i == 2 {
panic!(
"Could not create temporary directory {}",
env_temp_dir.display(),
);
}
match env_temp_dir.metadata() {
Ok(metadata) => {
let temp_dir_mode = metadata.permissions().mode();
assert_eq!(
temp_dir_mode, 0o40700,
"Uhyve's preexisting tempdir has incorrect mode ({temp_dir_mode:#o}, expected: 0o40700)."
);
break;
}
Err(ref e) if e.kind() == ErrorKind::NotFound => {
DirBuilder::new()
.mode(0o700)
.create(&env_temp_dir)
.unwrap_or_else(|e| {
if e.kind() != ErrorKind::AlreadyExists {
panic!(
"Could not create temporary directory {}: {e}",
env_temp_dir.display(),
);
}
});
}
Err(e) => panic!(
"Could not create temporary directory {}: {e}",
env_temp_dir.display()
),
}
warn!("Race during tempdir creation, retrying...");
}
env_temp_dir
}))
.expect("The temporary directory could not be created.")
}
#[cfg(test)]
mod tests {
use std::fs::remove_dir;
use super::*;
#[test]
fn test_create_with_dir_path() {
let env_tempdir = env::temp_dir();
let tempdir = create_temp_dir(Some(env_tempdir.clone()));
let in_tmp_path: bool = tempdir.path().starts_with(&env_tempdir);
let in_tmp_subfolder: bool = tempdir
.path()
.starts_with(env_tempdir.join(format!("uhyve-{}", unsafe { libc::getuid() })));
remove_dir(tempdir.path()).unwrap_or_else(|e| {
panic!(
"Unable to remove directory used for test (in_tmp_path: {}, in_tmp_subfolder: {}): {}",
in_tmp_path, in_tmp_subfolder, e
);
});
assert!(in_tmp_path, "directory: {}", tempdir.path().display());
assert!(!in_tmp_subfolder, "directory: {}", tempdir.path().display());
}
#[test]
fn test_create_without_dir_path() {
let tempdir = create_temp_dir(None);
let in_tmp_subfolder: bool = tempdir
.path()
.starts_with(env::temp_dir().join(format!("uhyve-{}", unsafe { libc::getuid() })));
remove_dir(tempdir.path()).unwrap_or_else(|e| {
panic!(
"Unable to remove directory used for test (in_tmp_subfolder: {}): {}",
in_tmp_subfolder, e
);
});
assert!(
in_tmp_subfolder,
"directory: {:?}",
tempdir.path().display()
);
}
}