1use std::path::Path;
6
7use crate::core::env::expand_env;
8use crate::error::Error;
9
10#[derive(Debug)]
11pub struct Options {
12 pub parents: bool,
15
16 pub mode: nc::mode_t,
18
19 pub exist_ok: bool,
21
22 pub expand_env: bool,
23}
24
25impl Options {
26 pub fn new() -> Options {
27 Self::default()
28 }
29}
30
31impl Default for Options {
32 fn default() -> Self {
33 Options {
34 parents: false,
35 mode: 0o755,
36 exist_ok: false,
37 expand_env: true,
38 }
39 }
40}
41
42impl Options {
43 pub fn with_parents() -> Self {
44 Self {
45 parents: true,
46 ..Self::default()
47 }
48 }
49}
50
51pub fn mkdir<T: AsRef<str>>(directory: T, options: &Options) -> Result<(), Error> {
53 let exist_ok = if options.parents {
54 true
55 } else {
56 options.parents
57 };
58
59 let directory = if options.expand_env {
60 expand_env(directory)
61 } else {
62 directory.as_ref().to_string()
63 };
64
65 let path = Path::new(&directory);
66 do_mkdir(path, options.parents, options.mode, exist_ok).map_err(Into::into)
67}
68
69fn do_mkdir(p: &Path, recursive: bool, mode: nc::mode_t, exist_ok: bool) -> Result<(), nc::Errno> {
70 if p.exists() {
71 if exist_ok {
72 return Ok(());
73 } else {
74 return Err(nc::EEXIST);
75 }
76 }
77 if recursive {
78 match p.parent() {
79 Some(parent) => do_mkdir(parent, recursive, mode, true)?,
80 None => return Err(nc::ENOENT),
81 }
82 }
83
84 unsafe { nc::mkdir(p, mode) }
85}
86
87#[cfg(test)]
88mod tests {
89 use super::*;
90
91 #[test]
92 fn test_mkdir() {
93 let mut options = Options::new();
94 options.parents = true;
95 let ret = mkdir("/tmp/test1/test2", &options);
96 assert!(ret.is_ok());
97 }
98}