Skip to main content

isideload_vfs/
fs.rs

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}