blob: 887070f00aee50da76561e341ac4e978eb015531 [file] [log] [blame]
use rand;
use rand::RngCore;
use std::ffi::OsString;
use std::path::{Path, PathBuf};
use std::{io, iter};
use error::IoResultExt;
fn tmpname(prefix: &str, suffix: &str, rand_len: usize) -> OsString {
let mut buf = String::with_capacity(prefix.len() + suffix.len() + rand_len);
buf.push_str(prefix);
buf.extend(iter::repeat('X').take(rand_len));
buf.push_str(suffix);
// Randomize.
unsafe {
// We guarantee utf8.
let bytes = &mut buf.as_mut_vec()[prefix.len()..prefix.len() + rand_len];
rand::thread_rng().fill_bytes(bytes);
for byte in bytes.iter_mut() {
*byte = match *byte % 62 {
v @ 0...9 => (v + b'0'),
v @ 10...35 => (v - 10 + b'a'),
v @ 36...61 => (v - 36 + b'A'),
_ => unreachable!(),
}
}
}
OsString::from(buf)
}
pub fn create_helper<F, R>(
base: &Path,
prefix: &str,
suffix: &str,
random_len: usize,
f: F,
) -> io::Result<R>
where
F: Fn(PathBuf) -> io::Result<R>,
{
let num_retries = if random_len != 0 { ::NUM_RETRIES } else { 1 };
for _ in 0..num_retries {
let path = base.join(tmpname(prefix, suffix, random_len));
return match f(path) {
Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => continue,
res => res,
};
}
Err(io::Error::new(
io::ErrorKind::AlreadyExists,
"too many temporary files exist"))
.with_err_path(|| base)
}