1 use std::io;
2 use std::path::Path;
3 
4 #[cfg(windows)]
5 use crate::fs::_remove_dir_contents;
6 
7 #[cfg(not(windows))]
8 use crate::unix::_remove_dir_contents;
9 
10 /// Deletes the contents of `path`, but not the directory iteself.
11 ///
12 /// If `path` is a symlink to a directory, deletes the contents
13 /// of that directory.  Fails if `path` does not exist.
remove_dir_contents<P: AsRef<Path>>(path: P) -> io::Result<()>14 pub fn remove_dir_contents<P: AsRef<Path>>(path: P) -> io::Result<()> {
15     // This wrapper function exists because the core function
16     // for Windows, in crate::fs, returns a PathBuf, which our
17     // caller shouldn't see.
18     _remove_dir_contents(path)?;
19     Ok(())
20 }
21 
22 /// Makes `path` an empty directory: if it does not exist, it is
23 /// created it as an empty directory (as if with
24 /// `std::fs::create_dir`); if it does exist, its contents are
25 /// deleted (as if with `remove_dir_contents`).
26 ///
27 /// It is an error if `path` exists but is not a directory (or
28 /// a symlink to one).
ensure_empty_dir<P: AsRef<Path>>(path: P) -> io::Result<()>29 pub fn ensure_empty_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
30     match std::fs::create_dir(&path) {
31         Err(e) if e.kind() == io::ErrorKind::AlreadyExists
32             => remove_dir_contents(path),
33         otherwise => otherwise,
34     }
35 }
36 
37 #[cfg(test)]
38 mod test {
39     use tempfile::TempDir;
40     use crate::remove_dir_all;
41     use crate::remove_dir_contents;
42     use crate::ensure_empty_dir;
43     use std::fs::{self, File};
44     use std::path::PathBuf;
45     use std::io;
46 
expect_failure<T>(k: io::ErrorKind, r: io::Result<T>) -> io::Result<()>47     fn expect_failure<T>(k: io::ErrorKind, r: io::Result<T>) -> io::Result<()> {
48         match r {
49             Err(e) if e.kind() == k => Ok(()),
50             Err(e) => Err(e),
51             Ok(_) => Err(io::Error::new(
52                 io::ErrorKind::Other,
53                 "unexpected success".to_string(),
54             )),
55         }
56     }
57 
58     struct Prep {
59         _tmp: TempDir,
60         ours: PathBuf,
61         file: PathBuf,
62     }
63 
prep() -> Result<Prep, io::Error>64     fn prep() -> Result<Prep, io::Error> {
65         let tmp = TempDir::new()?;
66         let ours = tmp.path().join("t.mkdir");
67         let file = ours.join("file");
68         fs::create_dir(&ours)?;
69         File::create(&file)?;
70         File::open(&file)?;
71         Ok(Prep { _tmp: tmp, ours, file })
72     }
73 
74     #[test]
mkdir_rm() -> Result<(), io::Error>75     fn mkdir_rm() -> Result<(), io::Error> {
76         let p = prep()?;
77 
78         expect_failure(io::ErrorKind::Other, remove_dir_contents(&p.file))?;
79 
80         remove_dir_contents(&p.ours)?;
81         expect_failure(io::ErrorKind::NotFound, File::open(&p.file))?;
82 
83         remove_dir_contents(&p.ours)?;
84         remove_dir_all(&p.ours)?;
85         expect_failure(io::ErrorKind::NotFound, remove_dir_contents(&p.ours))?;
86         Ok(())
87     }
88 
89     #[test]
ensure_rm() -> Result<(), io::Error>90     fn ensure_rm() -> Result<(), io::Error> {
91         let p = prep()?;
92 
93         expect_failure(io::ErrorKind::Other, ensure_empty_dir(&p.file))?;
94 
95         ensure_empty_dir(&p.ours)?;
96         expect_failure(io::ErrorKind::NotFound, File::open(&p.file))?;
97         ensure_empty_dir(&p.ours)?;
98 
99         remove_dir_all(&p.ours)?;
100         ensure_empty_dir(&p.ours)?;
101         File::create(&p.file)?;
102 
103         Ok(())
104     }
105 }
106