fuser_async/
filesystem.rs

1use std::collections::{BTreeSet, VecDeque};
2use std::ffi::{OsStr, OsString};
3use std::sync::Arc;
4
5use tokio::sync::RwLock;
6
7use crate::DirEntry;
8
9/// Base trait providing asynchronous functions for the system calls.
10///
11/// WARNING: The [`crate::FilesystemFUSE`] struct encapsulates implementors in a [`RwLock`].
12///          Therefore, care should be taken to not introduce deadlocks.
13///          An example would be if `open` waits on a `release` (e.g. to limit the number of open
14///          files), but the `open` acquires a write lock before any `release`.
15#[async_trait::async_trait]
16pub trait Filesystem {
17    type Error: Into<crate::error::Error>;
18    /// Close filesystem. See also [`fuser::Filesystem::destroy`].
19    async fn destroy(&mut self) -> Result<(), Self::Error> {
20        Ok(())
21    }
22    /// Lookup an entry by name in a directory. See also [`fuser::Filesystem::lookup`].
23    async fn lookup(&self, parent: u64, name: &OsStr) -> Result<fuser::FileAttr, Self::Error>;
24    /// Open a file and get a handle. See also [`fuser::Filesystem::open`].
25    async fn open(&self, _ino: u64, _flags: i32) -> Result<u64, Self::Error> {
26        Ok(0)
27    }
28    /// Release a file handle. See also [`fuser::Filesystem::release`].
29    async fn release(&self, _ino: u64, _fh: u64) -> Result<(), Self::Error> {
30        Ok(())
31    }
32    /// Get attributes on an entry. See also [`fuser::Filesystem::getattr`].
33    async fn getattr(&self, _ino: u64) -> Result<fuser::FileAttr, Self::Error>;
34    /// Set attributes. Currently only supports setting the size
35    async fn setattr(
36        &mut self,
37        ino: u64,
38        size: Option<u64>,
39    ) -> Result<fuser::FileAttr, Self::Error>;
40    /// Read a directory.
41    /// To be called repeatedly by specifying a gradually increasing offset,
42    /// until the returned iterator is empty. A minimum of two calls is required
43    /// to be certain that the end has been reached.
44    /// `offset` represents the index of the starting element.
45    /// See also [`fuser::Filesystem::readdir`].
46    async fn readdir(
47        &self,
48        ino: u64,
49        offset: u64,
50    ) -> Result<Box<dyn Iterator<Item = DirEntry> + Send + Sync + '_>, Self::Error>;
51    /// Read from a file. See also [`fuser::Filesystem::read`].
52    async fn read(
53        &self,
54        ino: u64,
55        fh: u64,
56        offset: i64,
57        size: u32,
58    ) -> Result<bytes::Bytes, Self::Error>;
59    /// Write to file. See also [`fuser::Filesystem::write`].
60    async fn write(
61        &self,
62        ino: u64,
63        fh: u64,
64        data: bytes::Bytes,
65        offset: i64,
66    ) -> Result<u32, Self::Error>;
67    /// Create and open a file. See also [`fuser::Filesystem::create`].
68    async fn create(
69        &mut self,
70        parent: u64,
71        name: OsString,
72        mode: u32,
73        umask: u32,
74        flags: i32,
75    ) -> Result<(fuser::FileAttr, u64), Self::Error>;
76    /// Create a directory. See also [`fuser::Filesystem::mkdir`].
77    async fn mkdir(&mut self, parent: u64, name: OsString) -> Result<fuser::FileAttr, Self::Error>;
78    /// Get the set of inodes from the filesystem.
79    ///
80    /// Implementors can usually provide a more efficient implementation than the blanket one,
81    /// which performs BFS from the root.
82    async fn inodes(&self) -> Result<BTreeSet<u64>, Self::Error> {
83        let mut inodes = BTreeSet::from([fuser::FUSE_ROOT_ID]);
84        let mut queue = VecDeque::from([fuser::FUSE_ROOT_ID]);
85        while let Some(ino) = queue.pop_front() {
86            for entry in self.readdir(ino, 0).await? {
87                inodes.insert(entry.inode);
88                if entry.file_type == fuser::FileType::Directory {
89                    queue.push_back(entry.inode);
90                }
91            }
92        }
93        Ok(inodes)
94    }
95}
96#[async_trait::async_trait]
97impl<T: Filesystem + Send + Sync + 'static> Filesystem for Arc<RwLock<T>> {
98    type Error = T::Error;
99    async fn destroy(&mut self) -> Result<(), Self::Error> {
100        let mut x = self.as_ref().write().await;
101        x.destroy().await
102    }
103    async fn lookup(&self, parent: u64, name: &OsStr) -> Result<fuser::FileAttr, Self::Error> {
104        let x = self.as_ref().read().await;
105        x.lookup(parent, name).await
106    }
107    async fn open(&self, ino: u64, flags: i32) -> Result<u64, Self::Error> {
108        let x = self.as_ref().read().await;
109        x.open(ino, flags).await
110    }
111    async fn release(&self, ino: u64, fh: u64) -> Result<(), Self::Error> {
112        let x = self.as_ref().read().await;
113        x.release(ino, fh).await
114    }
115    async fn getattr(&self, ino: u64) -> Result<fuser::FileAttr, Self::Error> {
116        let x = self.as_ref().read().await;
117        x.getattr(ino).await
118    }
119    async fn setattr(
120        &mut self,
121        ino: u64,
122        size: Option<u64>,
123    ) -> Result<fuser::FileAttr, Self::Error> {
124        let mut x = self.as_ref().write().await;
125        x.setattr(ino, size).await
126    }
127    async fn readdir(
128        &self,
129        ino: u64,
130        offset: u64,
131    ) -> Result<Box<dyn Iterator<Item = DirEntry> + Send + Sync + '_>, Self::Error> {
132        let x = self.as_ref().read().await;
133        let dir = x.readdir(ino, offset).await?;
134        // TODO: Avoid the collect (that would likely mean returning a `Stream` instead of an `Iterator`)
135        Ok(Box::new(dir.collect::<Vec<_>>().into_iter()))
136    }
137    async fn read(
138        &self,
139        ino: u64,
140        fh: u64,
141        offset: i64,
142        size: u32,
143    ) -> Result<bytes::Bytes, Self::Error> {
144        let x = self.as_ref().read().await;
145        x.read(ino, fh, offset, size).await
146    }
147    async fn write(
148        &self,
149        ino: u64,
150        fh: u64,
151        data: bytes::Bytes,
152        offset: i64,
153    ) -> Result<u32, Self::Error> {
154        let x = self.as_ref().read().await;
155        x.write(ino, fh, data, offset).await
156    }
157    async fn create(
158        &mut self,
159        parent: u64,
160        name: OsString,
161        mode: u32,
162        umask: u32,
163        flags: i32,
164    ) -> Result<(fuser::FileAttr, u64), Self::Error> {
165        let mut x = self.as_ref().write().await;
166        x.create(parent, name, mode, umask, flags).await
167    }
168    async fn mkdir(&mut self, parent: u64, name: OsString) -> Result<fuser::FileAttr, Self::Error> {
169        let mut x = self.as_ref().write().await;
170        x.mkdir(parent, name).await
171    }
172    async fn inodes(&self) -> Result<BTreeSet<u64>, Self::Error> {
173        let x = self.as_ref().read().await;
174        x.inodes().await
175    }
176}