1 use std::ffi::{OsStr, OsString};
2 use std::path::{Path, PathBuf};
3 use std::{io, iter::repeat_with};
4 
5 use crate::error::IoResultExt;
6 
tmpname(prefix: &OsStr, suffix: &OsStr, rand_len: usize) -> OsString7 fn tmpname(prefix: &OsStr, suffix: &OsStr, rand_len: usize) -> OsString {
8     let capacity = prefix
9         .len()
10         .saturating_add(suffix.len())
11         .saturating_add(rand_len);
12     let mut buf = OsString::with_capacity(capacity);
13     buf.push(prefix);
14     let mut char_buf = [0u8; 4];
15     for c in repeat_with(fastrand::alphanumeric).take(rand_len) {
16         buf.push(c.encode_utf8(&mut char_buf));
17     }
18     buf.push(suffix);
19     buf
20 }
21 
create_helper<R>( base: &Path, prefix: &OsStr, suffix: &OsStr, random_len: usize, mut f: impl FnMut(PathBuf) -> io::Result<R>, ) -> io::Result<R>22 pub fn create_helper<R>(
23     base: &Path,
24     prefix: &OsStr,
25     suffix: &OsStr,
26     random_len: usize,
27     mut f: impl FnMut(PathBuf) -> io::Result<R>,
28 ) -> io::Result<R> {
29     let num_retries = if random_len != 0 {
30         crate::NUM_RETRIES
31     } else {
32         1
33     };
34 
35     for _ in 0..num_retries {
36         let path = base.join(tmpname(prefix, suffix, random_len));
37         return match f(path) {
38             Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists && num_retries > 1 => continue,
39             // AddrInUse can happen if we're creating a UNIX domain socket and
40             // the path already exists.
41             Err(ref e) if e.kind() == io::ErrorKind::AddrInUse && num_retries > 1 => continue,
42             res => res,
43         };
44     }
45 
46     Err(io::Error::new(
47         io::ErrorKind::AlreadyExists,
48         "too many temporary files exist",
49     ))
50     .with_err_path(|| base)
51 }
52