| use std::{ |
| collections::hash_map::RandomState, |
| fs::{remove_file, File, OpenOptions}, |
| hash::{BuildHasher, Hasher}, |
| io, os, |
| path::{Path, PathBuf}, |
| }; |
| |
| #[cfg(not(any(unix, target_os = "wasi", windows)))] |
| compile_error!("Your system is not supported since cc cannot create named tempfile"); |
| |
| fn rand() -> u64 { |
| RandomState::new().build_hasher().finish() |
| } |
| |
| fn tmpname(suffix: &str) -> String { |
| format!("{}{}", rand(), suffix) |
| } |
| |
| fn create_named(path: &Path) -> io::Result<File> { |
| let mut open_options = OpenOptions::new(); |
| |
| open_options.read(true).write(true).create_new(true); |
| |
| #[cfg(all(unix, not(target_os = "wasi")))] |
| <OpenOptions as os::unix::fs::OpenOptionsExt>::mode(&mut open_options, 0o600); |
| |
| #[cfg(windows)] |
| <OpenOptions as os::windows::fs::OpenOptionsExt>::custom_flags( |
| &mut open_options, |
| crate::windows::windows_sys::FILE_ATTRIBUTE_TEMPORARY, |
| ); |
| |
| open_options.open(path) |
| } |
| |
| pub(super) struct NamedTempfile { |
| path: PathBuf, |
| file: Option<File>, |
| } |
| |
| impl NamedTempfile { |
| pub(super) fn new(base: &Path, suffix: &str) -> io::Result<Self> { |
| for _ in 0..10 { |
| let path = base.join(tmpname(suffix)); |
| match create_named(&path) { |
| Ok(file) => { |
| return Ok(Self { |
| file: Some(file), |
| path, |
| }) |
| } |
| Err(e) if e.kind() == io::ErrorKind::AlreadyExists => continue, |
| Err(e) => return Err(e), |
| }; |
| } |
| |
| Err(io::Error::new( |
| io::ErrorKind::AlreadyExists, |
| format!( |
| "too many temporary files exist in base `{}` with suffix `{}`", |
| base.display(), |
| suffix |
| ), |
| )) |
| } |
| |
| pub(super) fn path(&self) -> &Path { |
| &self.path |
| } |
| |
| pub(super) fn file(&self) -> &File { |
| self.file.as_ref().unwrap() |
| } |
| } |
| |
| impl Drop for NamedTempfile { |
| fn drop(&mut self) { |
| // On Windows you have to close all handle to it before |
| // removing the file. |
| self.file.take(); |
| let _ = remove_file(&self.path); |
| } |
| } |