parent
a1bbaa3014
commit
d9fc959738
@ -0,0 +1,94 @@
|
||||
use std::{
|
||||
ops,
|
||||
path::{
|
||||
PathBuf,
|
||||
Path
|
||||
},
|
||||
fmt,
|
||||
};
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
pub mod error;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||
pub struct TempFile(PathBuf);
|
||||
|
||||
const FILENAME_LEN_BYTES: usize = 16;
|
||||
const PREFIX: &'static str = "lolistealer-";
|
||||
|
||||
lazy_static! {
|
||||
pub static ref LOCATION: &'static Path = {
|
||||
Box::leak(std::env::temp_dir().into_boxed_path())
|
||||
};
|
||||
}
|
||||
|
||||
/// Generate a new random byte string for a filename.
|
||||
fn generate_filename(mut to: impl fmt::Write) -> Result<(), error::Error>
|
||||
{
|
||||
let mut buffer = [0u8; FILENAME_LEN_BYTES];
|
||||
getrandom::getrandom(&mut buffer[..])?;
|
||||
|
||||
write!(to, "{}", PREFIX)?;
|
||||
for byte in buffer.iter() {
|
||||
write!(to, "{:2x}", *byte)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl TempFile
|
||||
{
|
||||
/// Create a new temp file path
|
||||
pub fn new() -> Self
|
||||
{
|
||||
let mut buffer = String::with_capacity((FILENAME_LEN_BYTES*2) + PREFIX.len());
|
||||
generate_filename(&mut buffer).expect("tf fatal");
|
||||
Self(LOCATION.join(buffer))
|
||||
}
|
||||
/// Try to create a new temp file path
|
||||
pub fn try_new() -> Result<Self, error::Error>
|
||||
{
|
||||
let mut buffer = String::with_capacity((FILENAME_LEN_BYTES*2) + PREFIX.len());
|
||||
generate_filename(&mut buffer)?;
|
||||
Ok(Self(LOCATION.join(buffer)))
|
||||
}
|
||||
|
||||
/// Consume the `TempFile` and return the raw path, performing no cleanup.
|
||||
pub fn into_pathbuf(mut self) -> PathBuf
|
||||
{
|
||||
let pb = std::mem::replace(&mut self.0, PathBuf::default());
|
||||
std::mem::forget(self);
|
||||
pb
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Drop for TempFile
|
||||
{
|
||||
fn drop(&mut self)
|
||||
{
|
||||
if self.0.exists() {
|
||||
if self.0.is_file() {
|
||||
let _ = std::fs::remove_file(&self.0);
|
||||
} else {
|
||||
let _ = std::fs::remove_dir_all(&self.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<Path> for TempFile
|
||||
{
|
||||
fn as_ref(&self) -> &Path
|
||||
{
|
||||
self.0.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Deref for TempFile
|
||||
{
|
||||
type Target = Path;
|
||||
fn deref(&self) -> &Self::Target
|
||||
{
|
||||
self.0.as_ref()
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
use std::{
|
||||
error,
|
||||
fmt,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error
|
||||
{
|
||||
RNG,
|
||||
Format(fmt::Error),
|
||||
Unknown,
|
||||
}
|
||||
|
||||
impl error::Error for Error
|
||||
{
|
||||
fn source(&self) -> Option<&(dyn error::Error + 'static)>
|
||||
{
|
||||
match &self {
|
||||
_ => None,
|
||||
Self::Format(rng) => Some(rng),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl fmt::Display for Error
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||||
{
|
||||
write!(f, "temp file error: ")?;
|
||||
match self
|
||||
{
|
||||
Error::RNG => write!(f, "rng failed"),
|
||||
Error::Format(fmt) => write!(f, "formatting: {}", fmt),
|
||||
_ => write!(f, "unknown"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<fmt::Error> for Error
|
||||
{
|
||||
fn from(f: fmt::Error) -> Self
|
||||
{
|
||||
Self::Format(f)
|
||||
}
|
||||
}
|
||||
impl From<getrandom::Error> for Error
|
||||
{
|
||||
fn from(_f: getrandom::Error) -> Self
|
||||
{
|
||||
Self::RNG
|
||||
}
|
||||
}
|
Loading…
Reference in new issue