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