filesystem/
os.rs

1use std::env;
2use std::ffi::OsString;
3use std::fs::{self, File, OpenOptions, Permissions};
4use std::io::{Read, Result, Write};
5#[cfg(unix)]
6use std::os::unix::fs::PermissionsExt;
7use std::path::{Path, PathBuf};
8
9#[cfg(feature = "temp")]
10use tempdir;
11
12#[cfg(unix)]
13use UnixFileSystem;
14use {DirEntry, FileSystem, ReadDir};
15#[cfg(feature = "temp")]
16use {TempDir, TempFileSystem};
17
18/// Tracks a temporary directory that will be deleted once the struct goes out of scope.
19///
20/// This is a wrapper around a [`TempDir`].
21///
22/// [`TempDir`]: https://doc.rust-lang.org/tempdir/tempdir/struct.TempDir.html
23#[cfg(feature = "temp")]
24#[derive(Debug)]
25pub struct OsTempDir(tempdir::TempDir);
26
27#[cfg(feature = "temp")]
28impl TempDir for OsTempDir {
29    fn path(&self) -> &Path {
30        self.0.path()
31    }
32}
33
34/// An implementation of `FileSystem` that interacts with the actual operating system's file system.
35///
36/// This is primarily a wrapper for [`fs`] methods.
37///
38/// [`fs`]: https://doc.rust-lang.org/std/fs/index.html
39#[derive(Clone, Debug, Default)]
40pub struct OsFileSystem {}
41
42impl OsFileSystem {
43    pub fn new() -> Self {
44        OsFileSystem {}
45    }
46}
47
48impl FileSystem for OsFileSystem {
49    type DirEntry = fs::DirEntry;
50    type ReadDir = fs::ReadDir;
51
52    fn current_dir(&self) -> Result<PathBuf> {
53        env::current_dir()
54    }
55
56    fn set_current_dir<P: AsRef<Path>>(&self, path: P) -> Result<()> {
57        env::set_current_dir(path)
58    }
59
60    fn is_dir<P: AsRef<Path>>(&self, path: P) -> bool {
61        path.as_ref().is_dir()
62    }
63
64    fn is_file<P: AsRef<Path>>(&self, path: P) -> bool {
65        path.as_ref().is_file()
66    }
67
68    fn create_dir<P: AsRef<Path>>(&self, path: P) -> Result<()> {
69        fs::create_dir(path)
70    }
71
72    fn create_dir_all<P: AsRef<Path>>(&self, path: P) -> Result<()> {
73        fs::create_dir_all(path)
74    }
75
76    fn remove_dir<P: AsRef<Path>>(&self, path: P) -> Result<()> {
77        fs::remove_dir(path)
78    }
79
80    fn remove_dir_all<P: AsRef<Path>>(&self, path: P) -> Result<()> {
81        fs::remove_dir_all(path)
82    }
83
84    fn read_dir<P: AsRef<Path>>(&self, path: P) -> Result<Self::ReadDir> {
85        fs::read_dir(path)
86    }
87
88    fn write_file<P, B>(&self, path: P, buf: B) -> Result<()>
89    where
90        P: AsRef<Path>,
91        B: AsRef<[u8]>,
92    {
93        let mut file = File::create(path)?;
94        file.write_all(buf.as_ref())
95    }
96
97    fn overwrite_file<P, B>(&self, path: P, buf: B) -> Result<()>
98    where
99        P: AsRef<Path>,
100        B: AsRef<[u8]>,
101    {
102        let mut file = OpenOptions::new().write(true).truncate(true).open(path)?;
103        file.write_all(buf.as_ref())
104    }
105
106    fn read_file<P: AsRef<Path>>(&self, path: P) -> Result<Vec<u8>> {
107        let mut contents = Vec::<u8>::new();
108        let mut file = File::open(path)?;
109
110        file.read_to_end(&mut contents)?;
111
112        Ok(contents)
113    }
114
115    fn read_file_into<P, B>(&self, path: P, mut buf: B) -> Result<usize>
116    where
117        P: AsRef<Path>,
118        B: AsMut<Vec<u8>>,
119    {
120        let mut file = File::open(path)?;
121        file.read_to_end(buf.as_mut())
122    }
123
124    fn read_file_to_string<P: AsRef<Path>>(&self, path: P) -> Result<String> {
125        let mut contents = String::new();
126        let mut file = File::open(path)?;
127
128        file.read_to_string(&mut contents)?;
129
130        Ok(contents)
131    }
132
133    fn create_file<P, B>(&self, path: P, buf: B) -> Result<()>
134    where
135        P: AsRef<Path>,
136        B: AsRef<[u8]>,
137    {
138        let mut file = OpenOptions::new().write(true).create_new(true).open(path)?;
139
140        file.write_all(buf.as_ref())
141    }
142
143    fn remove_file<P: AsRef<Path>>(&self, path: P) -> Result<()> {
144        fs::remove_file(path)
145    }
146
147    fn copy_file<P, Q>(&self, from: P, to: Q) -> Result<()>
148    where
149        P: AsRef<Path>,
150        Q: AsRef<Path>,
151    {
152        fs::copy(from, to).and(Ok(()))
153    }
154
155    fn rename<P, Q>(&self, from: P, to: Q) -> Result<()>
156    where
157        P: AsRef<Path>,
158        Q: AsRef<Path>,
159    {
160        fs::rename(from, to)
161    }
162
163    fn readonly<P: AsRef<Path>>(&self, path: P) -> Result<bool> {
164        permissions(path.as_ref()).map(|p| p.readonly())
165    }
166
167    fn set_readonly<P: AsRef<Path>>(&self, path: P, readonly: bool) -> Result<()> {
168        let mut permissions = permissions(path.as_ref())?;
169
170        permissions.set_readonly(readonly);
171
172        fs::set_permissions(path, permissions)
173    }
174
175    fn len<P: AsRef<Path>>(&self, path: P) -> u64 {
176        fs::metadata(path.as_ref()).map(|md| md.len()).unwrap_or(0)
177    }
178}
179
180#[cfg(unix)]
181impl UnixFileSystem for OsFileSystem {
182    fn mode<P: AsRef<Path>>(&self, path: P) -> Result<u32> {
183        permissions(path.as_ref()).map(|p| p.mode())
184    }
185
186    fn set_mode<P: AsRef<Path>>(&self, path: P, mode: u32) -> Result<()> {
187        let mut permissions = permissions(path.as_ref())?;
188
189        permissions.set_mode(mode);
190
191        fs::set_permissions(path, permissions)
192    }
193}
194
195#[cfg(feature = "temp")]
196impl TempFileSystem for OsFileSystem {
197    type TempDir = OsTempDir;
198
199    fn temp_dir<S: AsRef<str>>(&self, prefix: S) -> Result<Self::TempDir> {
200        tempdir::TempDir::new(prefix.as_ref()).map(OsTempDir)
201    }
202}
203
204impl DirEntry for fs::DirEntry {
205    fn file_name(&self) -> OsString {
206        self.file_name()
207    }
208
209    fn path(&self) -> PathBuf {
210        self.path()
211    }
212}
213
214impl ReadDir<fs::DirEntry> for fs::ReadDir {}
215
216fn permissions(path: &Path) -> Result<Permissions> {
217    let metadata = fs::metadata(path)?;
218
219    Ok(metadata.permissions())
220}