diff options
Diffstat (limited to 'vendor/cc/src/tempfile.rs')
| -rw-r--r-- | vendor/cc/src/tempfile.rs | 86 |
1 files changed, 86 insertions, 0 deletions
diff --git a/vendor/cc/src/tempfile.rs b/vendor/cc/src/tempfile.rs new file mode 100644 index 00000000..833e6f28 --- /dev/null +++ b/vendor/cc/src/tempfile.rs @@ -0,0 +1,86 @@ +#![cfg_attr(target_family = "wasm", allow(unused))] + +use std::{ + collections::hash_map::RandomState, + fs::{remove_file, File, OpenOptions}, + hash::{BuildHasher, Hasher}, + io, os, + path::{Path, PathBuf}, +}; + +#[cfg(not(any(unix, target_family = "wasm", 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 take_file(&mut self) -> Option<File> { + self.file.take() + } +} + +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); + } +} |
