]>
Commit | Line | Data |
---|---|---|
22758248 XL |
1 | use rand::distributions::Alphanumeric; |
2 | use rand::{self, Rng}; | |
3 | use std::ffi::{OsStr, OsString}; | |
f8611cf8 | 4 | use std::path::{Path, PathBuf}; |
22758248 | 5 | use std::{io, str}; |
f8611cf8 | 6 | |
2f2e175c VK |
7 | use error::IoResultExt; |
8 | ||
22758248 XL |
9 | fn tmpname(prefix: &OsStr, suffix: &OsStr, rand_len: usize) -> OsString { |
10 | let mut buf = OsString::with_capacity(prefix.len() + suffix.len() + rand_len); | |
11 | buf.push(prefix); | |
f8611cf8 | 12 | |
22758248 XL |
13 | // Push each character in one-by-one. Unfortunately, this is the only |
14 | // safe(ish) simple way to do this without allocating a temporary | |
15 | // String/Vec. | |
f8611cf8 | 16 | unsafe { |
22758248 XL |
17 | rand::thread_rng() |
18 | .sample_iter(&Alphanumeric) | |
19 | .take(rand_len) | |
20 | .for_each(|b| buf.push(str::from_utf8_unchecked(&[b as u8]))) | |
f8611cf8 | 21 | } |
22758248 XL |
22 | buf.push(suffix); |
23 | buf | |
f8611cf8 VK |
24 | } |
25 | ||
26 | pub fn create_helper<F, R>( | |
27 | base: &Path, | |
22758248 XL |
28 | prefix: &OsStr, |
29 | suffix: &OsStr, | |
f8611cf8 VK |
30 | random_len: usize, |
31 | f: F, | |
32 | ) -> io::Result<R> | |
33 | where | |
34 | F: Fn(PathBuf) -> io::Result<R>, | |
35 | { | |
2f2e175c VK |
36 | let num_retries = if random_len != 0 { ::NUM_RETRIES } else { 1 }; |
37 | ||
38 | for _ in 0..num_retries { | |
f8611cf8 VK |
39 | let path = base.join(tmpname(prefix, suffix, random_len)); |
40 | return match f(path) { | |
41 | Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => continue, | |
42 | res => res, | |
43 | }; | |
44 | } | |
45 | ||
46 | Err(io::Error::new( | |
22758248 XL |
47 | io::ErrorKind::AlreadyExists, |
48 | "too many temporary files exist", | |
49 | )) | |
50 | .with_err_path(|| base) | |
f8611cf8 | 51 | } |