1use std::io;
5
6use async_trait::async_trait;
7
8use super::*;
9
10#[async_trait]
11impl AsyncFileSystem for Vfs {
12 async fn async_lookup(
13 &self,
14 ctx: &Context,
15 parent: <Self as FileSystem>::Inode,
16 name: &CStr,
17 ) -> Result<Entry> {
18 if name.to_bytes_with_nul().contains(&SLASH_ASCII) {
20 return Err(io::Error::from_raw_os_error(libc::EINVAL));
21 }
22
23 match self.get_real_rootfs(parent)? {
24 (Left(fs), idata) => self.lookup_pseudo(fs, idata, ctx, name),
25 (Right(fs), idata) => {
26 let mut entry = fs.async_lookup(ctx, idata.ino(), name).await?;
28 self.convert_entry(idata.fs_idx(), entry.inode, &mut entry)
30 }
31 }
32 }
33
34 async fn async_getattr(
35 &self,
36 ctx: &Context,
37 inode: <Self as FileSystem>::Inode,
38 handle: Option<<Self as FileSystem>::Handle>,
39 ) -> Result<(libc::stat64, Duration)> {
40 match self.get_real_rootfs(inode)? {
41 (Left(fs), idata) => fs.getattr(ctx, idata.ino(), handle),
42 (Right(fs), idata) => fs.async_getattr(ctx, idata.ino(), handle).await,
43 }
44 }
45
46 async fn async_setattr(
47 &self,
48 ctx: &Context,
49 inode: <Self as FileSystem>::Inode,
50 attr: libc::stat64,
51 handle: Option<<Self as FileSystem>::Handle>,
52 valid: SetattrValid,
53 ) -> Result<(libc::stat64, Duration)> {
54 match self.get_real_rootfs(inode)? {
55 (Left(fs), idata) => fs.setattr(ctx, idata.ino(), attr, handle, valid),
56 (Right(fs), idata) => {
57 fs.async_setattr(ctx, idata.ino(), attr, handle, valid)
58 .await
59 }
60 }
61 }
62
63 async fn async_open(
64 &self,
65 ctx: &Context,
66 inode: <Self as FileSystem>::Inode,
67 flags: u32,
68 fuse_flags: u32,
69 ) -> Result<(Option<<Self as FileSystem>::Handle>, OpenOptions)> {
70 if self.opts.load().no_open {
71 Err(Error::from_raw_os_error(libc::ENOSYS))
72 } else {
73 match self.get_real_rootfs(inode)? {
74 (Left(fs), idata) => fs
75 .open(ctx, idata.ino(), flags, fuse_flags)
76 .map(|(a, b, _)| (a, b)),
77 (Right(fs), idata) => fs
78 .async_open(ctx, idata.ino(), flags, fuse_flags)
79 .await
80 .map(|(h, opt)| (h.map(Into::into), opt)),
81 }
82 }
83 }
84
85 async fn async_create(
86 &self,
87 ctx: &Context,
88 parent: <Self as FileSystem>::Inode,
89 name: &CStr,
90 args: CreateIn,
91 ) -> Result<(Entry, Option<<Self as FileSystem>::Handle>, OpenOptions)> {
92 validate_path_component(name)?;
93
94 match self.get_real_rootfs(parent)? {
95 (Left(fs), idata) => fs
96 .create(ctx, idata.ino(), name, args)
97 .map(|(a, b, c, _)| (a, b, c)),
98 (Right(fs), idata) => {
99 fs.async_create(ctx, idata.ino(), name, args)
100 .await
101 .map(|(mut a, b, c)| {
102 self.convert_entry(idata.fs_idx(), a.inode, &mut a)?;
103 Ok((a, b, c))
104 })?
105 }
106 }
107 }
108
109 #[allow(clippy::too_many_arguments)]
110 async fn async_read(
111 &self,
112 ctx: &Context,
113 inode: <Self as FileSystem>::Inode,
114 handle: <Self as FileSystem>::Handle,
115 w: &mut (dyn AsyncZeroCopyWriter + Send),
116 size: u32,
117 offset: u64,
118 lock_owner: Option<u64>,
119 flags: u32,
120 ) -> Result<usize> {
121 match self.get_real_rootfs(inode)? {
122 (Left(_fs), _idata) => Err(io::Error::from_raw_os_error(libc::ENOSYS)),
123 (Right(fs), idata) => {
124 fs.async_read(ctx, idata.ino(), handle, w, size, offset, lock_owner, flags)
125 .await
126 }
127 }
128 }
129
130 #[allow(clippy::too_many_arguments)]
131 async fn async_write(
132 &self,
133 ctx: &Context,
134 inode: <Self as FileSystem>::Inode,
135 handle: <Self as FileSystem>::Handle,
136 r: &mut (dyn AsyncZeroCopyReader + Send),
137 size: u32,
138 offset: u64,
139 lock_owner: Option<u64>,
140 delayed_write: bool,
141 flags: u32,
142 fuse_flags: u32,
143 ) -> Result<usize> {
144 match self.get_real_rootfs(inode)? {
145 (Left(_fs), _idata) => Err(io::Error::from_raw_os_error(libc::ENOSYS)),
146 (Right(fs), idata) => {
147 fs.async_write(
148 ctx,
149 idata.ino(),
150 handle,
151 r,
152 size,
153 offset,
154 lock_owner,
155 delayed_write,
156 flags,
157 fuse_flags,
158 )
159 .await
160 }
161 }
162 }
163
164 async fn async_fsync(
165 &self,
166 ctx: &Context,
167 inode: <Self as FileSystem>::Inode,
168 datasync: bool,
169 handle: <Self as FileSystem>::Handle,
170 ) -> Result<()> {
171 match self.get_real_rootfs(inode)? {
172 (Left(fs), idata) => fs.fsync(ctx, idata.ino(), datasync, handle),
173 (Right(fs), idata) => fs.async_fsync(ctx, idata.ino(), datasync, handle).await,
174 }
175 }
176
177 async fn async_fallocate(
178 &self,
179 ctx: &Context,
180 inode: <Self as FileSystem>::Inode,
181 handle: <Self as FileSystem>::Handle,
182 mode: u32,
183 offset: u64,
184 length: u64,
185 ) -> Result<()> {
186 match self.get_real_rootfs(inode)? {
187 (Left(fs), idata) => fs.fallocate(ctx, idata.ino(), handle, mode, offset, length),
188 (Right(fs), idata) => {
189 fs.async_fallocate(ctx, idata.ino(), handle, mode, offset, length)
190 .await
191 }
192 }
193 }
194
195 async fn async_fsyncdir(
196 &self,
197 ctx: &Context,
198 inode: <Self as FileSystem>::Inode,
199 datasync: bool,
200 handle: <Self as FileSystem>::Handle,
201 ) -> Result<()> {
202 match self.get_real_rootfs(inode)? {
203 (Left(fs), idata) => fs.fsyncdir(ctx, idata.ino(), datasync, handle),
204 (Right(fs), idata) => fs.async_fsyncdir(ctx, idata.ino(), datasync, handle).await,
205 }
206 }
207}
208
209#[cfg(test)]
210mod tests {
211 use super::super::tests::FakeFileSystemOne;
212 use super::*;
213 use crate::api::Vfs;
214
215 use std::ffi::CString;
216
217 #[tokio::test]
218 async fn test_vfs_async_lookup() {
219 let vfs = Vfs::new(VfsOptions::default());
220 let fs = FakeFileSystemOne {};
221 let ctx = Context {
222 uid: 0,
223 gid: 0,
224 pid: 0,
225 };
226
227 assert!(vfs.mount(Box::new(fs), "/x/y").is_ok());
228
229 let handle = tokio::spawn(async move {
230 let name = CString::new("x").unwrap();
232 let future = vfs.async_lookup(&ctx, ROOT_ID.into(), name.as_c_str());
233 let entry1 = future.await.unwrap();
234 assert_eq!(entry1.inode, 0x2);
235
236 let entry2 = vfs
238 .async_lookup(
239 &ctx,
240 entry1.inode.into(),
241 CString::new("y").unwrap().as_c_str(),
242 )
243 .await
244 .unwrap();
245 assert_eq!(entry2.inode, 0x100_0000_0000_0001);
246
247 let entry3 = vfs
249 .async_lookup(
250 &ctx,
251 entry2.inode.into(),
252 CString::new("z").unwrap().as_c_str(),
253 )
254 .await
255 .unwrap();
256 assert_eq!(entry3.inode, 0);
257 });
258 handle.await.unwrap();
259 }
260}