1use crate::fs::asyncify;
2
3use std::io;
4use 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)]
11pub 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
20impl 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 /// ```
33 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 /// ```
52 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 /// ```
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
107feature! {
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