wasmer_wasix/fs/
relative_path_hack.rs

1use std::{path::Path, sync::Arc};
2
3use futures::future::BoxFuture;
4use virtual_fs::{FileSystem, FsError, OpenOptions, OpenOptionsConfig};
5
6#[derive(Debug)]
7pub struct RelativeOrAbsolutePathHack<F>(pub F);
8
9impl<F: FileSystem> RelativeOrAbsolutePathHack<F> {
10    fn execute<Func, Ret>(&self, path: &Path, operation: Func) -> Result<Ret, FsError>
11    where
12        Func: Fn(&F, &Path) -> Result<Ret, FsError>,
13    {
14        // First, try it with the path we were given
15        let result = operation(&self.0, path);
16
17        if result.is_err() && !path.is_absolute() {
18            // we were given a relative path, but maybe the operation will work
19            // using absolute paths instead.
20            let path = Path::new("/").join(path);
21            operation(&self.0, &path)
22        } else {
23            result
24        }
25    }
26}
27
28impl<F: FileSystem> virtual_fs::FileSystem for RelativeOrAbsolutePathHack<F> {
29    fn readlink(&self, path: &Path) -> virtual_fs::Result<std::path::PathBuf> {
30        self.execute(path, |fs, p| fs.readlink(p))
31    }
32
33    fn read_dir(&self, path: &Path) -> virtual_fs::Result<virtual_fs::ReadDir> {
34        self.execute(path, |fs, p| fs.read_dir(p))
35    }
36
37    fn create_dir(&self, path: &Path) -> virtual_fs::Result<()> {
38        self.execute(path, |fs, p| fs.create_dir(p))
39    }
40
41    fn remove_dir(&self, path: &Path) -> virtual_fs::Result<()> {
42        self.execute(path, |fs, p| fs.remove_dir(p))
43    }
44
45    fn rename<'a>(&'a self, from: &Path, to: &Path) -> BoxFuture<'a, virtual_fs::Result<()>> {
46        let from = from.to_owned();
47        let to = to.to_owned();
48        Box::pin(async move { self.0.rename(&from, &to).await })
49    }
50
51    fn metadata(&self, path: &Path) -> virtual_fs::Result<virtual_fs::Metadata> {
52        self.execute(path, |fs, p| fs.metadata(p))
53    }
54
55    fn symlink_metadata(&self, path: &Path) -> virtual_fs::Result<virtual_fs::Metadata> {
56        self.execute(path, |fs, p| fs.symlink_metadata(p))
57    }
58
59    fn remove_file(&self, path: &Path) -> virtual_fs::Result<()> {
60        self.execute(path, |fs, p| fs.remove_file(p))
61    }
62
63    fn new_open_options(&self) -> OpenOptions<'_> {
64        virtual_fs::OpenOptions::new(self)
65    }
66
67    fn mount(
68        &self,
69        name: String,
70        path: &Path,
71        fs: Box<dyn FileSystem + Send + Sync>,
72    ) -> virtual_fs::Result<()> {
73        let name_ref = &name;
74        let f_ref = &Arc::new(fs);
75        self.execute(path, move |f, p| {
76            f.mount(name_ref.clone(), p, Box::new(f_ref.clone()))
77        })
78    }
79}
80
81impl<F: FileSystem> virtual_fs::FileOpener for RelativeOrAbsolutePathHack<F> {
82    fn open(
83        &self,
84        path: &Path,
85        conf: &OpenOptionsConfig,
86    ) -> virtual_fs::Result<Box<dyn virtual_fs::VirtualFile + Send + Sync + 'static>> {
87        self.execute(path, |fs, p| {
88            fs.new_open_options().options(conf.clone()).open(p)
89        })
90    }
91}