1 use crate::fs::asyncify;
2 
3 use std::io;
4 use std::path::Path;
5 
6 /// A builder for creating directories in various manners.
7 ///
8 /// Additional Unix-specific options are available via importing the
9 /// [`DirBuilderExt`] trait.
10 ///
11 /// This is a specialized version of [`std::fs::DirBuilder`] for usage on
12 /// the Tokio runtime.
13 ///
14 /// [std::fs::DirBuilder]: std::fs::DirBuilder
15 /// [`DirBuilderExt`]: crate::fs::os::unix::DirBuilderExt
16 #[derive(Debug, Default)]
17 pub struct DirBuilder {
18     /// Indicates whether to create parent directories if they are missing.
19     recursive: bool,
20 
21     /// Set the Unix mode for newly created directories.
22     #[cfg(unix)]
23     pub(super) mode: Option<u32>,
24 }
25 
26 impl DirBuilder {
27     /// Creates a new set of options with default mode/security settings for all
28     /// platforms and also non-recursive.
29     ///
30     /// This is an async version of [`std::fs::DirBuilder::new`][std]
31     ///
32     /// [std]: std::fs::DirBuilder::new
33     ///
34     /// # Examples
35     ///
36     /// ```no_run
37     /// use tokio::fs::DirBuilder;
38     ///
39     /// let builder = DirBuilder::new();
40     /// ```
new() -> Self41     pub fn new() -> Self {
42         Default::default()
43     }
44 
45     /// Indicates whether to create directories recursively (including all parent directories).
46     /// Parents that do not exist are created with the same security and permissions settings.
47     ///
48     /// This option defaults to `false`.
49     ///
50     /// This is an async version of [`std::fs::DirBuilder::recursive`][std]
51     ///
52     /// [std]: std::fs::DirBuilder::recursive
53     ///
54     /// # Examples
55     ///
56     /// ```no_run
57     /// use tokio::fs::DirBuilder;
58     ///
59     /// let mut builder = DirBuilder::new();
60     /// builder.recursive(true);
61     /// ```
recursive(&mut self, recursive: bool) -> &mut Self62     pub fn recursive(&mut self, recursive: bool) -> &mut Self {
63         self.recursive = recursive;
64         self
65     }
66 
67     /// Creates the specified directory with the configured options.
68     ///
69     /// It is considered an error if the directory already exists unless
70     /// recursive mode is enabled.
71     ///
72     /// This is an async version of [`std::fs::DirBuilder::create`][std]
73     ///
74     /// [std]: std::fs::DirBuilder::create
75     ///
76     /// # Errors
77     ///
78     /// An error will be returned under the following circumstances:
79     ///
80     /// * Path already points to an existing file.
81     /// * Path already points to an existing directory and the mode is
82     ///   non-recursive.
83     /// * The calling process doesn't have permissions to create the directory
84     ///   or its missing parents.
85     /// * Other I/O error occurred.
86     ///
87     /// # Examples
88     ///
89     /// ```no_run
90     /// use tokio::fs::DirBuilder;
91     /// use std::io;
92     ///
93     /// #[tokio::main]
94     /// async fn main() -> io::Result<()> {
95     ///     DirBuilder::new()
96     ///         .recursive(true)
97     ///         .create("/tmp/foo/bar/baz")
98     ///         .await?;
99     ///
100     ///     Ok(())
101     /// }
102     /// ```
create<P: AsRef<Path>>(&self, path: P) -> io::Result<()>103     pub async fn create<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
104         let path = path.as_ref().to_owned();
105         let mut builder = std::fs::DirBuilder::new();
106         builder.recursive(self.recursive);
107 
108         #[cfg(unix)]
109         {
110             if let Some(mode) = self.mode {
111                 std::os::unix::fs::DirBuilderExt::mode(&mut builder, mode);
112             }
113         }
114 
115         asyncify(move || builder.create(path)).await
116     }
117 }
118