use std::{fs::File, io, os::unix::ffi::OsStrExt as _, path::Path};
#[derive(Debug)]
pub struct TemporaryFile {
inner: tempfile::NamedTempFile,
}
impl TemporaryFile {
pub fn new_in(parent: &Path, prefix: &str) -> io::Result<Self> {
super::validate_prefix(prefix)?;
validate_parent(parent)?;
let parent = parent.canonicalize()?;
validate_parent(&parent)?;
Ok(Self {
inner: tempfile::Builder::new()
.prefix(prefix)
.tempfile_in(parent)?,
})
}
#[must_use]
pub fn path(&self) -> &Path {
self.inner.path()
}
#[must_use]
pub fn as_file(&self) -> &File {
self.inner.as_file()
}
#[must_use]
pub fn as_file_mut(&mut self) -> &mut File {
self.inner.as_file_mut()
}
pub fn close(self) -> io::Result<()> {
self.inner.close()
}
}
fn validate_parent(parent: &Path) -> io::Result<()> {
if parent
.as_os_str()
.as_bytes()
.iter()
.any(|byte| matches!(byte, b'\r' | b'\n'))
{
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
"temporary parent contains CR/LF",
));
}
Ok(())
}
#[cfg(test)]
mod tests;