1use crate::traits::{OpenOptionsConfig, VfsMetadata, VfsPermissions};
2use crate::with_vfs;
3use std::io::{self, Read, Seek, SeekFrom, Write};
4use std::path::{Path, PathBuf};
5
6#[derive(Debug)]
7pub struct File {
8 inner: Box<dyn crate::traits::VfsFile>,
9}
10
11impl File {
12 pub fn open<P: AsRef<Path>>(path: P) -> io::Result<File> {
13 OpenOptions::new().read(true).open(path)
14 }
15
16 pub fn create<P: AsRef<Path>>(path: P) -> io::Result<File> {
17 OpenOptions::new()
18 .write(true)
19 .create(true)
20 .truncate(true)
21 .open(path)
22 }
23
24 pub fn options() -> OpenOptions {
25 OpenOptions::new()
26 }
27
28 pub fn set_len(&self, size: u64) -> io::Result<()> {
29 self.inner.set_len(size)
30 }
31
32 pub fn metadata(&self) -> io::Result<Metadata> {
33 self.inner.metadata().map(|inner| Metadata { inner })
34 }
35
36 pub fn set_permissions(&mut self, perm: Permissions) -> io::Result<()> {
37 self.inner.set_permissions(perm.inner)
38 }
39
40 pub fn sync_all(&mut self) -> io::Result<()> {
41 self.inner.sync_all()
42 }
43}
44
45impl Read for File {
46 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
47 self.inner.read(buf)
48 }
49}
50impl Write for File {
51 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
52 self.inner.write(buf)
53 }
54 fn flush(&mut self) -> io::Result<()> {
55 self.inner.flush()
56 }
57}
58impl Seek for File {
59 fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
60 self.inner.seek(pos)
61 }
62}
63
64#[derive(Clone, Default)]
65pub struct OpenOptions {
66 config: OpenOptionsConfig,
67}
68
69impl OpenOptions {
70 pub fn new() -> Self {
71 Self {
72 config: OpenOptionsConfig::default(),
73 }
74 }
75 pub fn read(&mut self, read: bool) -> &mut Self {
76 self.config.read = read;
77 self
78 }
79 pub fn write(&mut self, write: bool) -> &mut Self {
80 self.config.write = write;
81 self
82 }
83 pub fn create(&mut self, create: bool) -> &mut Self {
84 self.config.create = create;
85 self
86 }
87 pub fn create_new(&mut self, create_new: bool) -> &mut Self {
88 self.config.create_new = create_new;
89 self
90 }
91 pub fn append(&mut self, append: bool) -> &mut Self {
92 self.config.append = append;
93 self
94 }
95 pub fn truncate(&mut self, truncate: bool) -> &mut Self {
96 self.config.truncate = truncate;
97 self
98 }
99 pub fn open<P: AsRef<Path>>(&self, path: P) -> io::Result<File> {
100 with_vfs(|vfs| {
101 vfs.open_file(path.as_ref(), &self.config)
102 .map(|inner| File { inner })
103 })
104 }
105}
106
107pub struct Metadata {
108 inner: Box<dyn VfsMetadata>,
109}
110
111#[derive(Clone, Copy)]
112pub struct FileType {
113 is_dir: bool,
114 is_file: bool,
115 is_symlink: bool,
116}
117
118impl FileType {
119 pub fn is_dir(&self) -> bool {
120 self.is_dir
121 }
122 pub fn is_file(&self) -> bool {
123 self.is_file
124 }
125 pub fn is_symlink(&self) -> bool {
126 self.is_symlink
127 }
128}
129
130impl Metadata {
131 pub fn is_dir(&self) -> bool {
132 self.inner.is_dir()
133 }
134 pub fn is_file(&self) -> bool {
135 self.inner.is_file()
136 }
137 pub fn is_symlink(&self) -> bool {
138 self.inner.is_symlink()
139 }
140 pub fn len(&self) -> u64 {
141 self.inner.len()
142 }
143 pub fn permissions(&self) -> Permissions {
144 Permissions {
145 inner: self.inner.permissions(),
146 }
147 }
148 pub fn file_type(&self) -> FileType {
149 FileType {
150 is_dir: self.is_dir(),
151 is_file: self.is_file(),
152 is_symlink: self.is_symlink(),
153 }
154 }
155}
156
157pub struct Permissions {
158 inner: Box<dyn VfsPermissions>,
159}
160
161impl Permissions {
162 pub fn readonly(&self) -> bool {
163 self.inner.readonly()
164 }
165 pub fn set_readonly(&mut self, readonly: bool) {
166 self.inner.set_readonly(readonly)
167 }
168}
169
170pub trait PermissionsExt {
171 fn mode(&self) -> u32;
172 fn set_mode(&mut self, mode: u32);
173}
174
175impl PermissionsExt for Permissions {
176 fn mode(&self) -> u32 {
177 self.inner.mode()
178 }
179 fn set_mode(&mut self, mode: u32) {
180 self.inner.set_mode(mode)
181 }
182}
183
184pub trait MetadataExt {
185 fn dev(&self) -> u64;
186 fn ino(&self) -> u64;
187 fn mode(&self) -> u32;
188 fn nlink(&self) -> u64;
189 fn uid(&self) -> u32;
190 fn gid(&self) -> u32;
191 fn rdev(&self) -> u64;
192 fn size(&self) -> u64;
193 fn atime(&self) -> i64;
194 fn atime_nsec(&self) -> i64;
195 fn mtime(&self) -> i64;
196 fn mtime_nsec(&self) -> i64;
197 fn ctime(&self) -> i64;
198 fn ctime_nsec(&self) -> i64;
199 fn blksize(&self) -> u64;
200 fn blocks(&self) -> u64;
201}
202
203impl MetadataExt for Metadata {
204 fn dev(&self) -> u64 {
205 self.inner.dev()
206 }
207 fn ino(&self) -> u64 {
208 self.inner.ino()
209 }
210 fn mode(&self) -> u32 {
211 self.inner.mode()
212 }
213 fn nlink(&self) -> u64 {
214 self.inner.nlink()
215 }
216 fn uid(&self) -> u32 {
217 self.inner.uid()
218 }
219 fn gid(&self) -> u32 {
220 self.inner.gid()
221 }
222 fn rdev(&self) -> u64 {
223 self.inner.rdev()
224 }
225 fn size(&self) -> u64 {
226 self.inner.size()
227 }
228 fn atime(&self) -> i64 {
229 self.inner.atime()
230 }
231 fn atime_nsec(&self) -> i64 {
232 self.inner.atime_nsec()
233 }
234 fn mtime(&self) -> i64 {
235 self.inner.mtime()
236 }
237 fn mtime_nsec(&self) -> i64 {
238 self.inner.mtime_nsec()
239 }
240 fn ctime(&self) -> i64 {
241 self.inner.ctime()
242 }
243 fn ctime_nsec(&self) -> i64 {
244 self.inner.ctime_nsec()
245 }
246 fn blksize(&self) -> u64 {
247 self.inner.blksize()
248 }
249 fn blocks(&self) -> u64 {
250 self.inner.blocks()
251 }
252}
253
254pub fn read<P: AsRef<Path>>(path: P) -> io::Result<Vec<u8>> {
255 with_vfs(|vfs| vfs.read(path.as_ref()))
256}
257
258pub fn write<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> io::Result<()> {
259 with_vfs(|vfs| vfs.write(path.as_ref(), contents.as_ref()))
260}
261
262pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<u64> {
263 with_vfs(|vfs| vfs.copy(from.as_ref(), to.as_ref()))
264}
265
266pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()> {
267 with_vfs(|vfs| vfs.rename(from.as_ref(), to.as_ref()))
268}
269
270pub fn remove_file<P: AsRef<Path>>(path: P) -> io::Result<()> {
271 with_vfs(|vfs| vfs.remove_file(path.as_ref()))
272}
273
274pub fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
275 with_vfs(|vfs| vfs.remove_dir(path.as_ref()))
276}
277
278pub fn remove_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
279 with_vfs(|vfs| vfs.remove_dir_all(path.as_ref()))
280}
281
282pub fn create_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
283 with_vfs(|vfs| vfs.create_dir(path.as_ref()))
284}
285
286pub fn create_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
287 with_vfs(|vfs| vfs.create_dir_all(path.as_ref()))
288}
289
290pub fn read_link<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
291 with_vfs(|vfs| vfs.read_link(path.as_ref()))
292}
293
294pub fn metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
295 with_vfs(|vfs| vfs.metadata(path.as_ref()).map(|inner| Metadata { inner }))
296}
297
298pub fn symlink_metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
299 with_vfs(|vfs| {
300 vfs.symlink_metadata(path.as_ref())
301 .map(|inner| Metadata { inner })
302 })
303}
304
305pub fn set_permissions<P: AsRef<Path>>(path: P, perm: Permissions) -> io::Result<()> {
306 with_vfs(|vfs| vfs.set_permissions(path.as_ref(), perm.inner))
307}
308
309pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(target: P, link: Q) -> io::Result<()> {
310 with_vfs(|vfs| vfs.symlink(target.as_ref(), link.as_ref()))
311}
312
313#[derive(Debug)]
314pub struct ReadDir {
315 entries: std::vec::IntoIter<PathBuf>,
316}
317
318impl Iterator for ReadDir {
319 type Item = io::Result<DirEntry>;
320 fn next(&mut self) -> Option<Self::Item> {
321 self.entries.next().map(|path| Ok(DirEntry { path }))
322 }
323}
324
325pub struct DirEntry {
326 path: PathBuf,
327}
328
329impl DirEntry {
330 pub fn path(&self) -> PathBuf {
331 self.path.clone()
332 }
333 pub fn file_name(&self) -> std::ffi::OsString {
334 self.path.file_name().unwrap_or_default().to_os_string()
335 }
336 pub fn file_type(&self) -> io::Result<FileType> {
337 metadata(&self.path).map(|meta| meta.file_type())
338 }
339 pub fn metadata(&self) -> io::Result<Metadata> {
340 symlink_metadata(&self.path)
341 }
342}
343
344pub trait DirEntryExt {
345 fn ino(&self) -> u64;
346}
347
348impl DirEntryExt for DirEntry {
349 fn ino(&self) -> u64 {
350 self.metadata().map(|m| m.ino()).unwrap_or(0)
351 }
352}
353
354pub fn read_dir<P: AsRef<Path>>(path: P) -> io::Result<ReadDir> {
355 with_vfs(|vfs| {
356 let entries = vfs.read_dir(path.as_ref())?;
357 Ok(ReadDir {
358 entries: entries.into_iter(),
359 })
360 })
361}
362
363pub fn temp_dir() -> PathBuf {
364 crate::with_vfs(|vfs| Ok(vfs.temp_dir())).unwrap_or_else(|_| PathBuf::from("/"))
365}