xref: /aosp_15_r20/external/crosvm/fuse/src/filesystem.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1 // Copyright 2019 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 //! Data structures and traits for the fuse filesystem.
6 
7 #![deny(missing_docs)]
8 
9 use std::convert::TryInto;
10 use std::ffi::CStr;
11 use std::fs::File;
12 use std::io;
13 use std::mem;
14 use std::mem::MaybeUninit;
15 use std::time::Duration;
16 
17 use crate::server::Mapper;
18 use crate::sys;
19 pub use crate::sys::FsOptions;
20 pub use crate::sys::IoctlFlags;
21 pub use crate::sys::IoctlIovec;
22 pub use crate::sys::OpenOptions;
23 pub use crate::sys::RemoveMappingOne;
24 pub use crate::sys::SetattrValid;
25 pub use crate::sys::ROOT_ID;
26 
27 const MAX_BUFFER_SIZE: u32 = 1 << 20;
28 
29 /// Information about a path in the filesystem.
30 #[derive(Debug)]
31 pub struct Entry {
32     /// An `Inode` that uniquely identifies this path. During `lookup`, setting this to `0` means a
33     /// negative entry. Returning `ENOENT` also means a negative entry but setting this to `0`
34     /// allows the kernel to cache the negative result for `entry_timeout`. The value should be
35     /// produced by converting a `FileSystem::Inode` into a `u64`.
36     pub inode: u64,
37 
38     /// The generation number for this `Entry`. Typically used for network file systems. An `inode`
39     /// / `generation` pair must be unique over the lifetime of the file system (rather than just
40     /// the lifetime of the mount). In other words, if a `FileSystem` implementation re-uses an
41     /// `Inode` after it has been deleted then it must assign a new, previously unused generation
42     /// number to the `Inode` at the same time.
43     pub generation: u64,
44 
45     /// Inode attributes. Even if `attr_timeout` is zero, `attr` must be correct. For example, for
46     /// `open()`, FUSE uses `attr.st_size` from `lookup()` to determine how many bytes to request.
47     /// If this value is not correct, incorrect data will be returned.
48     pub attr: libc::stat64,
49 
50     /// How long the values in `attr` should be considered valid. If the attributes of the `Entry`
51     /// are only modified by the FUSE client, then this should be set to a very large value.
52     pub attr_timeout: Duration,
53 
54     /// How long the name associated with this `Entry` should be considered valid. If directory
55     /// entries are only changed or deleted by the FUSE client, then this should be set to a very
56     /// large value.
57     pub entry_timeout: Duration,
58 }
59 
60 impl From<Entry> for sys::EntryOut {
from(entry: Entry) -> sys::EntryOut61     fn from(entry: Entry) -> sys::EntryOut {
62         sys::EntryOut {
63             nodeid: entry.inode,
64             generation: entry.generation,
65             entry_valid: entry.entry_timeout.as_secs(),
66             attr_valid: entry.attr_timeout.as_secs(),
67             entry_valid_nsec: entry.entry_timeout.subsec_nanos(),
68             attr_valid_nsec: entry.attr_timeout.subsec_nanos(),
69             attr: entry.attr.into(),
70         }
71     }
72 }
73 
74 impl Entry {
75     /// Creates a new negative cache entry. A negative d_entry has an inode number of 0, and is
76     /// valid for the duration of `negative_timeout`.
77     ///
78     /// # Arguments
79     ///
80     /// * `negative_timeout` - The duration for which this negative d_entry should be considered
81     ///   valid. After the timeout expires, the d_entry will be invalidated.
82     ///
83     /// # Returns
84     ///
85     /// A new negative entry with provided entry timeout and 0 attr timeout.
new_negative(negative_timeout: Duration) -> Entry86     pub fn new_negative(negative_timeout: Duration) -> Entry {
87         let attr = MaybeUninit::<libc::stat64>::zeroed();
88         Entry {
89             inode: 0, // Using 0 for negative entry
90             entry_timeout: negative_timeout,
91             // Zero-fill other fields that won't be used.
92             attr_timeout: Duration::from_secs(0),
93             generation: 0,
94             // SAFETY: zero-initialized `stat64` is a valid value.
95             attr: unsafe { attr.assume_init() },
96         }
97     }
98 }
99 
100 /// Represents information about an entry in a directory.
101 pub struct DirEntry<'a> {
102     /// The inode number for this entry. This does NOT have to be the same as the `Inode` for this
103     /// directory entry. However, it must be the same as the `attr.st_ino` field of the `Entry`
104     /// that would be returned by a `lookup` request in the parent directory for `name`.
105     pub ino: libc::ino64_t,
106 
107     /// Any non-zero value that the kernel can use to identify the current point in the directory
108     /// entry stream. It does not need to be the actual physical position. A value of `0` is
109     /// reserved to mean "from the beginning" and should never be used. The `offset` value of the
110     /// first entry in a stream should point to the beginning of the second entry and so on.
111     pub offset: u64,
112 
113     /// The type of this directory entry. Valid values are any of the `libc::DT_*` constants.
114     pub type_: u32,
115 
116     /// The name of this directory entry. There are no requirements for the contents of this field
117     /// and any sequence of bytes is considered valid.
118     pub name: &'a CStr,
119 }
120 
121 /// A reply to a `getxattr` method call.
122 #[derive(Debug)]
123 pub enum GetxattrReply {
124     /// The value of the requested extended attribute. This can be arbitrary textual or binary data
125     /// and does not need to be nul-terminated.
126     Value(Vec<u8>),
127 
128     /// The size of the buffer needed to hold the value of the requested extended attribute. Should
129     /// be returned when the `size` parameter is 0. Callers should note that it is still possible
130     /// for the size of the value to change in between `getxattr` calls and should not assume that
131     /// a subsequent call to `getxattr` with the returned count will always succeed.
132     Count(u32),
133 }
134 
135 /// A reply to a `listxattr` method call.
136 pub enum ListxattrReply {
137     /// A buffer containing a nul-separated list of the names of all the extended attributes
138     /// associated with this `Inode`. This list of names may be unordered and includes a namespace
139     /// prefix. There may be several disjoint namespaces associated with a single `Inode`.
140     Names(Vec<u8>),
141 
142     /// This size of the buffer needed to hold the full list of extended attribute names associated
143     /// with this `Inode`. Should be returned when the `size` parameter is 0. Callers should note
144     /// that it is still possible for the set of extended attributes to change between `listxattr`
145     /// calls and so should not assume that a subsequent call to `listxattr` with the returned
146     /// count will always succeed.
147     Count(u32),
148 }
149 
150 /// A reply to an `ioctl` method call.
151 #[derive(Debug)]
152 pub enum IoctlReply {
153     /// Indicates that the ioctl should be retried. This is only a valid reply when the `flags`
154     /// field of the ioctl request contains `IoctlFlags::UNRESTRICTED`. The kernel will read in
155     /// data and prepare output buffers as specified in the `input` and `output` fields before
156     /// re-sending the ioctl message.
157     Retry {
158         /// Data that should be read by the kernel module and sent to the server when the ioctl is
159         /// retried.
160         input: Vec<IoctlIovec>,
161 
162         /// Buffer space that should be prepared so that the server can send back the response to
163         /// the ioctl.
164         output: Vec<IoctlIovec>,
165     },
166 
167     /// Indicates that the ioctl was processed.
168     Done(io::Result<Vec<u8>>),
169 }
170 
171 /// A trait for directly copying data from the fuse transport into a `File` without first storing it
172 /// in an intermediate buffer.
173 pub trait ZeroCopyReader {
174     /// Copies at most `count` bytes from `self` directly into `f` at offset `off` without storing
175     /// it in any intermediate buffers. If the return value is `Ok(n)` then it must be guaranteed
176     /// that `0 <= n <= count`. If `n` is `0`, then it can indicate one of 3 possibilities:
177     ///
178     /// 1. There is no more data left in `self`.
179     /// 2. There is no more space in `f`.
180     /// 3. `count` was `0`.
181     ///
182     /// # Errors
183     ///
184     /// If any error is returned then the implementation must guarantee that no bytes were copied
185     /// from `self`. If the underlying write to `f` returns `0` then the implementation must return
186     /// an error of the kind `io::ErrorKind::WriteZero`.
read_to(&mut self, f: &mut File, count: usize, off: u64) -> io::Result<usize>187     fn read_to(&mut self, f: &mut File, count: usize, off: u64) -> io::Result<usize>;
188 
189     /// Copies exactly `count` bytes of data from `self` into `f` at offset `off`. `off + count`
190     /// must be less than `u64::MAX`.
191     ///
192     /// # Errors
193     ///
194     /// If an error is returned then the number of bytes copied from `self` is unspecified but it
195     /// will never be more than `count`.
read_exact_to(&mut self, f: &mut File, mut count: usize, mut off: u64) -> io::Result<()>196     fn read_exact_to(&mut self, f: &mut File, mut count: usize, mut off: u64) -> io::Result<()> {
197         let c = count
198             .try_into()
199             .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?;
200         if off.checked_add(c).is_none() {
201             return Err(io::Error::new(
202                 io::ErrorKind::InvalidInput,
203                 "`off` + `count` must be less than u64::MAX",
204             ));
205         }
206 
207         while count > 0 {
208             match self.read_to(f, count, off) {
209                 Ok(0) => {
210                     return Err(io::Error::new(
211                         io::ErrorKind::WriteZero,
212                         "failed to fill whole buffer",
213                     ))
214                 }
215                 Ok(n) => {
216                     count -= n;
217                     off += n as u64;
218                 }
219                 Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
220                 Err(e) => return Err(e),
221             }
222         }
223 
224         Ok(())
225     }
226 
227     /// Copies all remaining bytes from `self` into `f` at offset `off`. Equivalent to repeatedly
228     /// calling `read_to` until it returns either `Ok(0)` or a non-`ErrorKind::Interrupted` error.
229     ///
230     /// # Errors
231     ///
232     /// If an error is returned then the number of bytes copied from `self` is unspecified.
copy_to_end(&mut self, f: &mut File, mut off: u64) -> io::Result<usize>233     fn copy_to_end(&mut self, f: &mut File, mut off: u64) -> io::Result<usize> {
234         let mut out = 0;
235         loop {
236             match self.read_to(f, usize::MAX, off) {
237                 Ok(0) => return Ok(out),
238                 Ok(n) => {
239                     off = off.saturating_add(n as u64);
240                     out += n;
241                 }
242                 Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
243                 Err(e) => return Err(e),
244             }
245         }
246     }
247 }
248 
249 impl<'a, R: ZeroCopyReader> ZeroCopyReader for &'a mut R {
read_to(&mut self, f: &mut File, count: usize, off: u64) -> io::Result<usize>250     fn read_to(&mut self, f: &mut File, count: usize, off: u64) -> io::Result<usize> {
251         (**self).read_to(f, count, off)
252     }
read_exact_to(&mut self, f: &mut File, count: usize, off: u64) -> io::Result<()>253     fn read_exact_to(&mut self, f: &mut File, count: usize, off: u64) -> io::Result<()> {
254         (**self).read_exact_to(f, count, off)
255     }
copy_to_end(&mut self, f: &mut File, off: u64) -> io::Result<usize>256     fn copy_to_end(&mut self, f: &mut File, off: u64) -> io::Result<usize> {
257         (**self).copy_to_end(f, off)
258     }
259 }
260 
261 /// A trait for directly copying data from a `File` into the fuse transport without first storing
262 /// it in an intermediate buffer.
263 pub trait ZeroCopyWriter {
264     /// Copies at most `count` bytes from `f` at offset `off` directly into `self` without storing
265     /// it in any intermediate buffers. If the return value is `Ok(n)` then it must be guaranteed
266     /// that `0 <= n <= count`. If `n` is `0`, then it can indicate one of 3 possibilities:
267     ///
268     /// 1. There is no more data left in `f`.
269     /// 2. There is no more space in `self`.
270     /// 3. `count` was `0`.
271     ///
272     /// # Errors
273     ///
274     /// If any error is returned then the implementation must guarantee that no bytes were copied
275     /// from `f`. If the underlying read from `f` returns `0` then the implementation must return an
276     /// error of the kind `io::ErrorKind::UnexpectedEof`.
write_from(&mut self, f: &mut File, count: usize, off: u64) -> io::Result<usize>277     fn write_from(&mut self, f: &mut File, count: usize, off: u64) -> io::Result<usize>;
278 
279     /// Copies exactly `count` bytes of data from `f` at offset `off` into `self`. `off + count`
280     /// must be less than `u64::MAX`.
281     ///
282     /// # Errors
283     ///
284     /// If an error is returned then the number of bytes copied from `self` is unspecified but it
285     /// well never be more than `count`.
write_all_from(&mut self, f: &mut File, mut count: usize, mut off: u64) -> io::Result<()>286     fn write_all_from(&mut self, f: &mut File, mut count: usize, mut off: u64) -> io::Result<()> {
287         let c = count
288             .try_into()
289             .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?;
290         if off.checked_add(c).is_none() {
291             return Err(io::Error::new(
292                 io::ErrorKind::InvalidInput,
293                 "`off` + `count` must be less than u64::MAX",
294             ));
295         }
296 
297         while count > 0 {
298             match self.write_from(f, count, off) {
299                 Ok(0) => {
300                     return Err(io::Error::new(
301                         io::ErrorKind::UnexpectedEof,
302                         "failed to write whole buffer",
303                     ))
304                 }
305                 Ok(n) => {
306                     // No need for checked math here because we verified that `off + count` will not
307                     // overflow and `n` must be <= `count`.
308                     count -= n;
309                     off += n as u64;
310                 }
311                 Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
312                 Err(e) => return Err(e),
313             }
314         }
315 
316         Ok(())
317     }
318 
319     /// Copies all remaining bytes from `f` at offset `off` into `self`. Equivalent to repeatedly
320     /// calling `write_from` until it returns either `Ok(0)` or a non-`ErrorKind::Interrupted`
321     /// error.
322     ///
323     /// # Errors
324     ///
325     /// If an error is returned then the number of bytes copied from `f` is unspecified.
copy_to_end(&mut self, f: &mut File, mut off: u64) -> io::Result<usize>326     fn copy_to_end(&mut self, f: &mut File, mut off: u64) -> io::Result<usize> {
327         let mut out = 0;
328         loop {
329             match self.write_from(f, usize::MAX, off) {
330                 Ok(0) => return Ok(out),
331                 Ok(n) => {
332                     off = off.saturating_add(n as u64);
333                     out += n;
334                 }
335                 Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
336                 Err(e) => return Err(e),
337             }
338         }
339     }
340 }
341 
342 impl<'a, W: ZeroCopyWriter> ZeroCopyWriter for &'a mut W {
write_from(&mut self, f: &mut File, count: usize, off: u64) -> io::Result<usize>343     fn write_from(&mut self, f: &mut File, count: usize, off: u64) -> io::Result<usize> {
344         (**self).write_from(f, count, off)
345     }
write_all_from(&mut self, f: &mut File, count: usize, off: u64) -> io::Result<()>346     fn write_all_from(&mut self, f: &mut File, count: usize, off: u64) -> io::Result<()> {
347         (**self).write_all_from(f, count, off)
348     }
copy_to_end(&mut self, f: &mut File, off: u64) -> io::Result<usize>349     fn copy_to_end(&mut self, f: &mut File, off: u64) -> io::Result<usize> {
350         (**self).copy_to_end(f, off)
351     }
352 }
353 
354 /// Additional context associated with requests.
355 #[derive(Clone, Copy, Debug)]
356 pub struct Context {
357     /// The user ID of the calling process.
358     pub uid: libc::uid_t,
359 
360     /// The group ID of the calling process.
361     pub gid: libc::gid_t,
362 
363     /// The thread group ID of the calling process.
364     pub pid: libc::pid_t,
365 }
366 
367 impl From<sys::InHeader> for Context {
from(source: sys::InHeader) -> Self368     fn from(source: sys::InHeader) -> Self {
369         Context {
370             uid: source.uid,
371             gid: source.gid,
372             pid: source.pid as i32,
373         }
374     }
375 }
376 
377 /// A trait for iterating over the contents of a directory. This trait is needed because rust
378 /// doesn't support generic associated types, which means that it's not possible to implement a
379 /// regular iterator that yields a `DirEntry` due to its generic lifetime parameter.
380 pub trait DirectoryIterator {
381     /// Returns the next entry in the directory or `None` if there are no more.
next(&mut self) -> Option<DirEntry>382     fn next(&mut self) -> Option<DirEntry>;
383 }
384 
385 /// The main trait that connects a file system with a transport.
386 #[allow(unused_variables)]
387 pub trait FileSystem {
388     /// Represents a location in the filesystem tree and can be used to perform operations that act
389     /// on the metadata of a file/directory (e.g., `getattr` and `setattr`). Can also be used as the
390     /// starting point for looking up paths in the filesystem tree. An `Inode` may support operating
391     /// directly on the content of the path that to which it points. `FileSystem` implementations
392     /// that support this should set the `FsOptions::ZERO_MESSAGE_OPEN` option in the return value
393     /// of the `init` function. On linux based systems, an `Inode` is equivalent to opening a file
394     /// or directory with the `libc::O_PATH` flag.
395     ///
396     /// # Lookup Count
397     ///
398     /// The `FileSystem` implementation is required to keep a "lookup count" for every `Inode`.
399     /// Every time an `Entry` is returned by a `FileSystem` trait method, this lookup count should
400     /// increase by 1. The lookup count for an `Inode` decreases when the kernel sends a `forget`
401     /// request. `Inode`s with a non-zero lookup count may receive requests from the kernel even
402     /// after calls to `unlink`, `rmdir` or (when overwriting an existing file) `rename`.
403     /// `FileSystem` implementations must handle such requests properly and it is recommended to
404     /// defer removal of the `Inode` until the lookup count reaches zero. Calls to `unlink`, `rmdir`
405     /// or `rename` will be followed closely by `forget` unless the file or directory is open, in
406     /// which case the kernel issues `forget` only after the `release` or `releasedir` calls.
407     ///
408     /// Note that if a file system will be exported over NFS the `Inode`'s lifetime must extend even
409     /// beyond `forget`. See the `generation` field in `Entry`.
410     type Inode: From<u64> + Into<u64>;
411 
412     /// Represents a file or directory that is open for reading/writing.
413     type Handle: From<u64> + Into<u64>;
414 
415     /// An iterator over the entries of a directory. See the documentation for `readdir` for more
416     /// details.
417     type DirIter: DirectoryIterator;
418 
419     /// Maximum size of the buffer that the filesystem can generate data to, including the header.
420     /// This corresponds to max_write in the initialization.
max_buffer_size(&self) -> u32421     fn max_buffer_size(&self) -> u32 {
422         MAX_BUFFER_SIZE
423     }
424 
425     /// Initialize the file system.
426     ///
427     /// This method is called when a connection to the FUSE kernel module is first established. The
428     /// `capable` parameter indicates the features that are supported by the kernel module. The
429     /// implementation should return the options that it supports. Any options set in the returned
430     /// `FsOptions` that are not also set in `capable` are silently dropped.
init(&self, capable: FsOptions) -> io::Result<FsOptions>431     fn init(&self, capable: FsOptions) -> io::Result<FsOptions> {
432         Ok(FsOptions::empty())
433     }
434 
435     /// Clean up the file system.
436     ///
437     /// Called when the filesystem exits. All open `Handle`s should be closed and the lookup count
438     /// for all open `Inode`s implicitly goes to zero. At this point the connection to the FUSE
439     /// kernel module may already be gone so implementations should not rely on being able to
440     /// communicate with the kernel.
destroy(&self)441     fn destroy(&self) {}
442 
443     /// Look up a directory entry by name and get its attributes.
444     ///
445     /// If this call is successful then the lookup count of the `Inode` associated with the returned
446     /// `Entry` must be increased by 1.
lookup(&self, ctx: Context, parent: Self::Inode, name: &CStr) -> io::Result<Entry>447     fn lookup(&self, ctx: Context, parent: Self::Inode, name: &CStr) -> io::Result<Entry> {
448         Err(io::Error::from_raw_os_error(libc::ENOSYS))
449     }
450 
451     /// Forget about an inode.
452     ///
453     /// Called when the kernel removes an inode from its internal caches. `count` indicates the
454     /// amount by which the lookup count for the inode should be decreased. If reducing the lookup
455     /// count by `count` causes it to go to zero, then the implementation may delete the `Inode`.
forget(&self, ctx: Context, inode: Self::Inode, count: u64)456     fn forget(&self, ctx: Context, inode: Self::Inode, count: u64) {}
457 
458     /// Forget about multiple inodes.
459     ///
460     /// `requests` is a vector of `(inode, count)` pairs. See the documentation for `forget` for
461     /// more information.
batch_forget(&self, ctx: Context, requests: Vec<(Self::Inode, u64)>)462     fn batch_forget(&self, ctx: Context, requests: Vec<(Self::Inode, u64)>) {
463         for (inode, count) in requests {
464             self.forget(ctx, inode, count)
465         }
466     }
467 
468     /// Get attributes for a file / directory.
469     ///
470     /// If `handle` is not `None`, then it contains the handle previously returned by the
471     /// implementation after a call to `open` or `opendir`. However, implementations should still
472     /// take care to verify the handle if they do not trust the client (e.g., virtio-fs).
473     ///
474     /// If writeback caching is enabled (`FsOptions::WRITEBACK_CACHE`), then the kernel module
475     /// likely has a better idea of the length of the file than the file system (for
476     /// example, if there was a write that extended the size of the file but has not yet been
477     /// flushed). In this case, the `st_size` field of the returned struct is ignored.
478     ///
479     /// The returned `Duration` indicates how long the returned attributes should be considered
480     /// valid by the client. If the attributes are only changed via the FUSE kernel module (i.e.,
481     /// the kernel module has exclusive access), then this should be a very large value.
getattr( &self, ctx: Context, inode: Self::Inode, handle: Option<Self::Handle>, ) -> io::Result<(libc::stat64, Duration)>482     fn getattr(
483         &self,
484         ctx: Context,
485         inode: Self::Inode,
486         handle: Option<Self::Handle>,
487     ) -> io::Result<(libc::stat64, Duration)> {
488         Err(io::Error::from_raw_os_error(libc::ENOSYS))
489     }
490 
491     /// Set attributes for a file / directory.
492     ///
493     /// If `handle` is not `None`, then it contains the handle previously returned by the
494     /// implementation after a call to `open` or `opendir`. However, implementations should still
495     /// take care to verify the handle if they do not trust the client (e.g., virtio-fs).
496     ///
497     /// The `valid` parameter indicates the fields of `attr` that may be considered valid and should
498     /// be set by the file system. The content of all other fields in `attr` is undefined.
499     ///
500     /// If the `FsOptions::HANDLE_KILLPRIV` was set during `init`, then the implementation is
501     /// expected to reset the setuid and setgid bits if the file size or owner is being changed.
502     ///
503     /// This method returns the new attributes after making the modifications requested by the
504     /// client. The returned `Duration` indicates how long the returned attributes should be
505     /// considered valid by the client. If the attributes are only changed via the FUSE kernel
506     /// module (i.e., the kernel module has exclusive access), then this should be a very large
507     /// value.
setattr( &self, ctx: Context, inode: Self::Inode, attr: libc::stat64, handle: Option<Self::Handle>, valid: SetattrValid, ) -> io::Result<(libc::stat64, Duration)>508     fn setattr(
509         &self,
510         ctx: Context,
511         inode: Self::Inode,
512         attr: libc::stat64,
513         handle: Option<Self::Handle>,
514         valid: SetattrValid,
515     ) -> io::Result<(libc::stat64, Duration)> {
516         Err(io::Error::from_raw_os_error(libc::ENOSYS))
517     }
518 
519     /// Read a symbolic link.
readlink(&self, ctx: Context, inode: Self::Inode) -> io::Result<Vec<u8>>520     fn readlink(&self, ctx: Context, inode: Self::Inode) -> io::Result<Vec<u8>> {
521         Err(io::Error::from_raw_os_error(libc::ENOSYS))
522     }
523 
524     /// Create a symbolic link.
525     ///
526     /// The file system must create a symbolic link named `name` in the directory represented by
527     /// `parent`, which contains the string `linkname`. Returns an `Entry` for the newly created
528     /// symlink.
529     ///
530     /// If this call is successful then the lookup count of the `Inode` associated with the returned
531     /// `Entry` must be increased by 1.
symlink( &self, ctx: Context, linkname: &CStr, parent: Self::Inode, name: &CStr, security_ctx: Option<&CStr>, ) -> io::Result<Entry>532     fn symlink(
533         &self,
534         ctx: Context,
535         linkname: &CStr,
536         parent: Self::Inode,
537         name: &CStr,
538         security_ctx: Option<&CStr>,
539     ) -> io::Result<Entry> {
540         Err(io::Error::from_raw_os_error(libc::ENOSYS))
541     }
542 
543     /// Create a file node.
544     ///
545     /// Create a regular file, character device, block device, fifo, or socket node named `name` in
546     /// the directory represented by `inode`. Valid values for `mode` and `rdev` are the same as
547     /// those accepted by the `mknod(2)` system call. Returns an `Entry` for the newly created node.
548     ///
549     /// When the `FsOptions::DONT_MASK` feature is set, the file system is responsible for setting
550     /// the permissions of the created node to `mode & !umask`.
551     ///
552     /// If this call is successful then the lookup count of the `Inode` associated with the returned
553     /// `Entry` must be increased by 1.
mknod( &self, ctx: Context, inode: Self::Inode, name: &CStr, mode: u32, rdev: u32, umask: u32, security_ctx: Option<&CStr>, ) -> io::Result<Entry>554     fn mknod(
555         &self,
556         ctx: Context,
557         inode: Self::Inode,
558         name: &CStr,
559         mode: u32,
560         rdev: u32,
561         umask: u32,
562         security_ctx: Option<&CStr>,
563     ) -> io::Result<Entry> {
564         Err(io::Error::from_raw_os_error(libc::ENOSYS))
565     }
566 
567     /// Create a directory.
568     ///
569     /// When the `FsOptions::DONT_MASK` feature is set, the file system is responsible for setting
570     /// the permissions of the created directory to `mode & !umask`. Returns an `Entry` for the
571     /// newly created directory.
572     ///
573     /// If this call is successful then the lookup count of the `Inode` associated with the returned
574     /// `Entry` must be increased by 1.
mkdir( &self, ctx: Context, parent: Self::Inode, name: &CStr, mode: u32, umask: u32, security_ctx: Option<&CStr>, ) -> io::Result<Entry>575     fn mkdir(
576         &self,
577         ctx: Context,
578         parent: Self::Inode,
579         name: &CStr,
580         mode: u32,
581         umask: u32,
582         security_ctx: Option<&CStr>,
583     ) -> io::Result<Entry> {
584         Err(io::Error::from_raw_os_error(libc::ENOSYS))
585     }
586 
587     /// Create an unnamed temporary file.
chromeos_tmpfile( &self, ctx: Context, parent: Self::Inode, mode: u32, umask: u32, security_ctx: Option<&CStr>, ) -> io::Result<Entry>588     fn chromeos_tmpfile(
589         &self,
590         ctx: Context,
591         parent: Self::Inode,
592         mode: u32,
593         umask: u32,
594         security_ctx: Option<&CStr>,
595     ) -> io::Result<Entry> {
596         Err(io::Error::from_raw_os_error(libc::ENOSYS))
597     }
598 
599     /// Remove a file.
600     ///
601     /// If the file's inode lookup count is non-zero, then the file system is expected to delay
602     /// removal of the inode until the lookup count goes to zero. See the documentation of the
603     /// `forget` function for more information.
unlink(&self, ctx: Context, parent: Self::Inode, name: &CStr) -> io::Result<()>604     fn unlink(&self, ctx: Context, parent: Self::Inode, name: &CStr) -> io::Result<()> {
605         Err(io::Error::from_raw_os_error(libc::ENOSYS))
606     }
607 
608     /// Remove a directory.
609     ///
610     /// If the directory's inode lookup count is non-zero, then the file system is expected to delay
611     /// removal of the inode until the lookup count goes to zero. See the documentation of the
612     /// `forget` function for more information.
rmdir(&self, ctx: Context, parent: Self::Inode, name: &CStr) -> io::Result<()>613     fn rmdir(&self, ctx: Context, parent: Self::Inode, name: &CStr) -> io::Result<()> {
614         Err(io::Error::from_raw_os_error(libc::ENOSYS))
615     }
616 
617     /// Rename a file / directory.
618     ///
619     /// If the destination exists, it should be atomically replaced. If the destination's inode
620     /// lookup count is non-zero, then the file system is expected to delay removal of the inode
621     /// until the lookup count goes to zero. See the documentation of the `forget` function for more
622     /// information.
623     ///
624     /// `flags` may be `libc::RENAME_EXCHANGE` or `libc::RENAME_NOREPLACE`. If
625     /// `libc::RENAME_NOREPLACE` is specified, the implementation must not overwrite `newname` if it
626     /// exists and must return an error instead. If `libc::RENAME_EXCHANGE` is specified, the
627     /// implementation must atomically exchange the two files, i.e., both must exist and neither may
628     /// be deleted.
rename( &self, ctx: Context, olddir: Self::Inode, oldname: &CStr, newdir: Self::Inode, newname: &CStr, flags: u32, ) -> io::Result<()>629     fn rename(
630         &self,
631         ctx: Context,
632         olddir: Self::Inode,
633         oldname: &CStr,
634         newdir: Self::Inode,
635         newname: &CStr,
636         flags: u32,
637     ) -> io::Result<()> {
638         Err(io::Error::from_raw_os_error(libc::ENOSYS))
639     }
640 
641     /// Create a hard link.
642     ///
643     /// Create a hard link from `inode` to `newname` in the directory represented by `newparent`.
644     ///
645     /// If this call is successful then the lookup count of the `Inode` associated with the returned
646     /// `Entry` must be increased by 1.
link( &self, ctx: Context, inode: Self::Inode, newparent: Self::Inode, newname: &CStr, ) -> io::Result<Entry>647     fn link(
648         &self,
649         ctx: Context,
650         inode: Self::Inode,
651         newparent: Self::Inode,
652         newname: &CStr,
653     ) -> io::Result<Entry> {
654         Err(io::Error::from_raw_os_error(libc::ENOSYS))
655     }
656 
657     /// Open a file.
658     ///
659     /// Open the file associated with `inode` for reading / writing. All values accepted by the
660     /// `open(2)` system call are valid values for `flags` and must be handled by the file system.
661     /// However, there are some additional rules:
662     ///
663     /// * Creation flags (`libc::O_CREAT`, `libc::O_EXCL`, `libc::O_NOCTTY`) will be filtered out
664     ///   and handled by the kernel.
665     ///
666     /// * The file system should check the access modes (`libc::O_RDONLY`, `libc::O_WRONLY`,
667     ///   `libc::O_RDWR`) to determine if the operation is permitted. If the file system was mounted
668     ///   with the `-o default_permissions` mount option, then this check will also be carried out
669     ///   by the kernel before sending the open request.
670     ///
671     /// * When writeback caching is enabled (`FsOptions::WRITEBACK_CACHE`) the kernel may send read
672     ///   requests even for files opened with `libc::O_WRONLY`. The file system should be prepared
673     ///   to handle this.
674     ///
675     /// * When writeback caching is enabled, the kernel will handle the `libc::O_APPEND` flag.
676     ///   However, this will not work reliably unless the kernel has exclusive access to the file.
677     ///   In this case the file system may either ignore the `libc::O_APPEND` flag or return an
678     ///   error to indicate that reliable `libc::O_APPEND` handling is not available.
679     ///
680     /// * When writeback caching is disabled, the file system is expected to properly handle
681     ///   `libc::O_APPEND` and ensure that each write is appended to the end of the file.
682     ///
683     /// The file system may choose to return a `Handle` to refer to the newly opened file. The
684     /// kernel will then use this `Handle` for all operations on the content of the file (`read`,
685     /// `write`, `flush`, `release`, `fsync`). If the file system does not return a
686     /// `Handle` then the kernel will use the `Inode` for the file to operate on its contents. In
687     /// this case the file system may wish to enable the `FsOptions::ZERO_MESSAGE_OPEN` feature if
688     /// it is supported by the kernel (see below).
689     ///
690     /// The returned `OpenOptions` allow the file system to change the way the opened file is
691     /// handled by the kernel. See the documentation of `OpenOptions` for more information.
692     ///
693     /// If the `FsOptions::ZERO_MESSAGE_OPEN` feature is enabled by both the file system
694     /// implementation and the kernel, then the file system may return an error of `ENOSYS`. This
695     /// will be interpreted by the kernel as success and future calls to `open` and `release` will
696     /// be handled by the kernel without being passed on to the file system.
open( &self, ctx: Context, inode: Self::Inode, flags: u32, ) -> io::Result<(Option<Self::Handle>, OpenOptions)>697     fn open(
698         &self,
699         ctx: Context,
700         inode: Self::Inode,
701         flags: u32,
702     ) -> io::Result<(Option<Self::Handle>, OpenOptions)> {
703         // Matches the behavior of libfuse.
704         Ok((None, OpenOptions::empty()))
705     }
706 
707     /// Create and open a file.
708     ///
709     /// If the file does not already exist, the file system should create it with the specified
710     /// `mode`. When the `FsOptions::DONT_MASK` feature is set, the file system is responsible for
711     /// setting the permissions of the created file to `mode & !umask`.
712     ///
713     /// If the file system returns an `ENOSYS` error, then the kernel will treat this method as
714     /// unimplemented and all future calls to `create` will be handled by calling the `mknod` and
715     /// `open` methods instead.
716     ///
717     /// See the documentation for the `open` method for more information about opening the file. In
718     /// addition to the optional `Handle` and the `OpenOptions`, the file system must also return an
719     /// `Entry` for the file. This increases the lookup count for the `Inode` associated with the
720     /// file by 1.
create( &self, ctx: Context, parent: Self::Inode, name: &CStr, mode: u32, flags: u32, umask: u32, security_ctx: Option<&CStr>, ) -> io::Result<(Entry, Option<Self::Handle>, OpenOptions)>721     fn create(
722         &self,
723         ctx: Context,
724         parent: Self::Inode,
725         name: &CStr,
726         mode: u32,
727         flags: u32,
728         umask: u32,
729         security_ctx: Option<&CStr>,
730     ) -> io::Result<(Entry, Option<Self::Handle>, OpenOptions)> {
731         Err(io::Error::from_raw_os_error(libc::ENOSYS))
732     }
733 
734     /// Read data from a file.
735     ///
736     /// Returns `size` bytes of data starting from offset `off` from the file associated with
737     /// `inode` or `handle`.
738     ///
739     /// `flags` contains the flags used to open the file. Similarly, `handle` is the `Handle`
740     /// returned by the file system from the `open` method, if any. If the file system
741     /// implementation did not return a `Handle` from `open` then the contents of `handle` are
742     /// undefined.
743     ///
744     /// This method should return exactly the number of bytes requested by the kernel, except in the
745     /// case of error or EOF. Otherwise, the kernel will substitute the rest of the data with
746     /// zeroes. An exception to this rule is if the file was opened with the "direct I/O" option
747     /// (`libc::O_DIRECT`), in which case the kernel will forward the return code from this method
748     /// to the userspace application that made the system call.
read<W: io::Write + ZeroCopyWriter>( &self, ctx: Context, inode: Self::Inode, handle: Self::Handle, w: W, size: u32, offset: u64, lock_owner: Option<u64>, flags: u32, ) -> io::Result<usize>749     fn read<W: io::Write + ZeroCopyWriter>(
750         &self,
751         ctx: Context,
752         inode: Self::Inode,
753         handle: Self::Handle,
754         w: W,
755         size: u32,
756         offset: u64,
757         lock_owner: Option<u64>,
758         flags: u32,
759     ) -> io::Result<usize> {
760         Err(io::Error::from_raw_os_error(libc::ENOSYS))
761     }
762 
763     /// Write data to a file.
764     ///
765     /// Writes `size` bytes of data starting from offset `off` to the file associated with `inode`
766     /// or `handle`.
767     ///
768     /// `flags` contains the flags used to open the file. Similarly, `handle` is the `Handle`
769     /// returned by the file system from the `open` method, if any. If the file system
770     /// implementation did not return a `Handle` from `open` then the contents of `handle` are
771     /// undefined.
772     ///
773     /// If the `FsOptions::HANDLE_KILLPRIV` feature is not enabled then then the file system is
774     /// expected to clear the setuid and setgid bits.
775     ///
776     /// If `delayed_write` is true then it indicates that this is a write for buffered data.
777     ///
778     /// This method should return exactly the number of bytes requested by the kernel, except in the
779     /// case of error. An exception to this rule is if the file was opened with the "direct I/O"
780     /// option (`libc::O_DIRECT`), in which case the kernel will forward the return code from this
781     /// method to the userspace application that made the system call.
write<R: io::Read + ZeroCopyReader>( &self, ctx: Context, inode: Self::Inode, handle: Self::Handle, r: R, size: u32, offset: u64, lock_owner: Option<u64>, delayed_write: bool, flags: u32, ) -> io::Result<usize>782     fn write<R: io::Read + ZeroCopyReader>(
783         &self,
784         ctx: Context,
785         inode: Self::Inode,
786         handle: Self::Handle,
787         r: R,
788         size: u32,
789         offset: u64,
790         lock_owner: Option<u64>,
791         delayed_write: bool,
792         flags: u32,
793     ) -> io::Result<usize> {
794         Err(io::Error::from_raw_os_error(libc::ENOSYS))
795     }
796 
797     /// Flush the contents of a file.
798     ///
799     /// This method is called on every `close()` of a file descriptor. Since it is possible to
800     /// duplicate file descriptors there may be many `flush` calls for one call to `open`.
801     ///
802     /// File systems should not make any assumptions about when `flush` will be
803     /// called or even if it will be called at all.
804     ///
805     /// `handle` is the `Handle` returned by the file system from the `open` method, if any. If the
806     /// file system did not return a `Handle` from `open` then the contents of `handle` are
807     /// undefined.
808     ///
809     /// Unlike `fsync`, the file system is not required to flush pending writes. One reason to flush
810     /// data is if the file system wants to return write errors during close. However, this is not
811     /// portable because POSIX does not require `close` to wait for delayed I/O to complete.
812     ///
813     /// If the `FsOptions::POSIX_LOCKS` feature is enabled, then the file system must remove all
814     /// locks belonging to `lock_owner`.
815     ///
816     /// If this method returns an `ENOSYS` error then the kernel will treat it as success and all
817     /// subsequent calls to `flush` will be handled by the kernel without being forwarded to the
818     /// file system.
flush( &self, ctx: Context, inode: Self::Inode, handle: Self::Handle, lock_owner: u64, ) -> io::Result<()>819     fn flush(
820         &self,
821         ctx: Context,
822         inode: Self::Inode,
823         handle: Self::Handle,
824         lock_owner: u64,
825     ) -> io::Result<()> {
826         Err(io::Error::from_raw_os_error(libc::ENOSYS))
827     }
828 
829     /// Synchronize file contents.
830     ///
831     /// File systems must ensure that the file contents have been flushed to disk before returning
832     /// from this method. If `datasync` is true then only the file data (but not the metadata) needs
833     /// to be flushed.
834     ///
835     /// `handle` is the `Handle` returned by the file system from the `open` method, if any. If the
836     /// file system did not return a `Handle` from `open` then the contents of
837     /// `handle` are undefined.
838     ///
839     /// If this method returns an `ENOSYS` error then the kernel will treat it as success and all
840     /// subsequent calls to `fsync` will be handled by the kernel without being forwarded to the
841     /// file system.
fsync( &self, ctx: Context, inode: Self::Inode, datasync: bool, handle: Self::Handle, ) -> io::Result<()>842     fn fsync(
843         &self,
844         ctx: Context,
845         inode: Self::Inode,
846         datasync: bool,
847         handle: Self::Handle,
848     ) -> io::Result<()> {
849         Err(io::Error::from_raw_os_error(libc::ENOSYS))
850     }
851 
852     /// Allocate requested space for file data.
853     ///
854     /// If this function returns success, then the file sytem must guarantee that it is possible to
855     /// write up to `length` bytes of data starting at `offset` without failing due to a lack of
856     /// free space on the disk.
857     ///
858     /// `handle` is the `Handle` returned by the file system from the `open` method, if any. If the
859     /// file system did not return a `Handle` from `open` then the contents of `handle` are
860     /// undefined.
861     ///
862     /// If this method returns an `ENOSYS` error then the kernel will treat that as a permanent
863     /// failure: all future calls to `fallocate` will fail with `EOPNOTSUPP` without being forwarded
864     /// to the file system.
fallocate( &self, ctx: Context, inode: Self::Inode, handle: Self::Handle, mode: u32, offset: u64, length: u64, ) -> io::Result<()>865     fn fallocate(
866         &self,
867         ctx: Context,
868         inode: Self::Inode,
869         handle: Self::Handle,
870         mode: u32,
871         offset: u64,
872         length: u64,
873     ) -> io::Result<()> {
874         Err(io::Error::from_raw_os_error(libc::ENOSYS))
875     }
876 
877     /// Release an open file.
878     ///
879     /// This method is called when there are no more references to an open file: all file
880     /// descriptors are closed and all memory mappings are unmapped.
881     ///
882     /// For every `open` call there will be exactly one `release` call (unless the file system is
883     /// force-unmounted).
884     ///
885     /// The file system may reply with an error, but error values are not returned to the `close()`
886     /// or `munmap()` which triggered the release.
887     ///
888     /// `handle` is the `Handle` returned by the file system from the `open` method, if any. If the
889     /// file system did not return a `Handle` from `open` then the contents of
890     /// `handle` are undefined.
891     ///
892     /// If `flush` is `true` then the contents of the file should also be flushed to disk.
release( &self, ctx: Context, inode: Self::Inode, flags: u32, handle: Self::Handle, flush: bool, flock_release: bool, lock_owner: Option<u64>, ) -> io::Result<()>893     fn release(
894         &self,
895         ctx: Context,
896         inode: Self::Inode,
897         flags: u32,
898         handle: Self::Handle,
899         flush: bool,
900         flock_release: bool,
901         lock_owner: Option<u64>,
902     ) -> io::Result<()> {
903         Err(io::Error::from_raw_os_error(libc::ENOSYS))
904     }
905 
906     /// Get information about the file system.
statfs(&self, ctx: Context, inode: Self::Inode) -> io::Result<libc::statvfs64>907     fn statfs(&self, ctx: Context, inode: Self::Inode) -> io::Result<libc::statvfs64> {
908         // SAFETY: zero-initializing a struct with only POD fields.
909         let mut st: libc::statvfs64 = unsafe { mem::zeroed() };
910 
911         // This matches the behavior of libfuse as it returns these values if the
912         // filesystem doesn't implement this method.
913         st.f_namemax = 255;
914         st.f_bsize = 512;
915 
916         Ok(st)
917     }
918 
919     /// Set an extended attribute.
920     ///
921     /// If this method fails with an `ENOSYS` error, then the kernel will treat that as a permanent
922     /// failure. The kernel will return `EOPNOTSUPP` for all future calls to `setxattr` without
923     /// forwarding them to the file system.
924     ///
925     /// Valid values for flags are the same as those accepted by the `setxattr(2)` system call and
926     /// have the same behavior.
setxattr( &self, ctx: Context, inode: Self::Inode, name: &CStr, value: &[u8], flags: u32, ) -> io::Result<()>927     fn setxattr(
928         &self,
929         ctx: Context,
930         inode: Self::Inode,
931         name: &CStr,
932         value: &[u8],
933         flags: u32,
934     ) -> io::Result<()> {
935         Err(io::Error::from_raw_os_error(libc::ENOSYS))
936     }
937 
938     /// Get an extended attribute.
939     ///
940     /// If `size` is 0, then the file system should respond with `GetxattrReply::Count` and the
941     /// number of bytes needed to hold the value. If `size` is large enough to hold the value, then
942     /// the file system should reply with `GetxattrReply::Value` and the value of the extended
943     /// attribute. If `size` is not 0 but is also not large enough to hold the value, then the file
944     /// system should reply with an `ERANGE` error.
945     ///
946     /// If this method fails with an `ENOSYS` error, then the kernel will treat that as a permanent
947     /// failure. The kernel will return `EOPNOTSUPP` for all future calls to `getxattr` without
948     /// forwarding them to the file system.
getxattr( &self, ctx: Context, inode: Self::Inode, name: &CStr, size: u32, ) -> io::Result<GetxattrReply>949     fn getxattr(
950         &self,
951         ctx: Context,
952         inode: Self::Inode,
953         name: &CStr,
954         size: u32,
955     ) -> io::Result<GetxattrReply> {
956         Err(io::Error::from_raw_os_error(libc::ENOSYS))
957     }
958 
959     /// List extended attribute names.
960     ///
961     /// If `size` is 0, then the file system should respond with `ListxattrReply::Count` and the
962     /// number of bytes needed to hold a `\0` byte separated list of the names of all the extended
963     /// attributes. If `size` is large enough to hold the `\0` byte separated list of the attribute
964     /// names, then the file system should reply with `ListxattrReply::Names` and the list. If
965     /// `size` is not 0 but is also not large enough to hold the list, then the file system should
966     /// reply with an `ERANGE` error.
967     ///
968     /// If this method fails with an `ENOSYS` error, then the kernel will treat that as a permanent
969     /// failure. The kernel will return `EOPNOTSUPP` for all future calls to `listxattr` without
970     /// forwarding them to the file system.
listxattr(&self, ctx: Context, inode: Self::Inode, size: u32) -> io::Result<ListxattrReply>971     fn listxattr(&self, ctx: Context, inode: Self::Inode, size: u32) -> io::Result<ListxattrReply> {
972         Err(io::Error::from_raw_os_error(libc::ENOSYS))
973     }
974 
975     /// Remove an extended attribute.
976     ///
977     /// If this method fails with an `ENOSYS` error, then the kernel will treat that as a permanent
978     /// failure. The kernel will return `EOPNOTSUPP` for all future calls to `removexattr` without
979     /// forwarding them to the file system.
removexattr(&self, ctx: Context, inode: Self::Inode, name: &CStr) -> io::Result<()>980     fn removexattr(&self, ctx: Context, inode: Self::Inode, name: &CStr) -> io::Result<()> {
981         Err(io::Error::from_raw_os_error(libc::ENOSYS))
982     }
983 
984     /// Open a directory for reading.
985     ///
986     /// The file system may choose to return a `Handle` to refer to the newly opened directory. The
987     /// kernel will then use this `Handle` for all operations on the content of the directory
988     /// (`readdir`, `readdirplus`, `fsyncdir`, `releasedir`). If the file system does not return a
989     /// `Handle` then the kernel will use the `Inode` for the directory to operate on its contents.
990     /// In this case the file system may wish to enable the `FsOptions::ZERO_MESSAGE_OPENDIR`
991     /// feature if it is supported by the kernel (see below).
992     ///
993     /// The returned `OpenOptions` allow the file system to change the way the opened directory is
994     /// handled by the kernel. See the documentation of `OpenOptions` for more information.
995     ///
996     /// If the `FsOptions::ZERO_MESSAGE_OPENDIR` feature is enabled by both the file system
997     /// implementation and the kernel, then the file system may return an error of `ENOSYS`. This
998     /// will be interpreted by the kernel as success and future calls to `opendir` and `releasedir`
999     /// will be handled by the kernel without being passed on to the file system.
opendir( &self, ctx: Context, inode: Self::Inode, flags: u32, ) -> io::Result<(Option<Self::Handle>, OpenOptions)>1000     fn opendir(
1001         &self,
1002         ctx: Context,
1003         inode: Self::Inode,
1004         flags: u32,
1005     ) -> io::Result<(Option<Self::Handle>, OpenOptions)> {
1006         // Matches the behavior of libfuse.
1007         Ok((None, OpenOptions::empty()))
1008     }
1009 
1010     /// Read a directory.
1011     ///
1012     /// `handle` is the `Handle` returned by the file system from the `opendir` method, if any. If
1013     /// the file system did not return a `Handle` from `opendir` then the contents of `handle` are
1014     /// undefined.
1015     ///
1016     /// `size` indicates the maximum number of bytes that should be returned by this method.
1017     ///
1018     /// If `offset` is non-zero then it corresponds to one of the `offset` values from a `DirEntry`
1019     /// that was previously returned by a call to `readdir` for the same handle. In this case the
1020     /// file system should skip over the entries before the position defined by the `offset` value.
1021     /// If entries were added or removed while the `Handle` is open then the file system may still
1022     /// include removed entries or skip newly created entries. However, adding or removing entries
1023     /// should never cause the file system to skip over unrelated entries or include an entry more
1024     /// than once. This means that `offset` cannot be a simple index and must include sufficient
1025     /// information to uniquely determine the next entry in the list even when the set of entries is
1026     /// being changed.
1027     ///
1028     /// The file system may return entries for the current directory (".") and parent directory
1029     /// ("..") but is not required to do so. If the file system does not return these entries, then
1030     /// they are implicitly added by the kernel.
1031     ///
1032     /// The lookup count for `Inode`s associated with the returned directory entries is **NOT**
1033     /// affected by this method.
readdir( &self, ctx: Context, inode: Self::Inode, handle: Self::Handle, size: u32, offset: u64, ) -> io::Result<Self::DirIter>1034     fn readdir(
1035         &self,
1036         ctx: Context,
1037         inode: Self::Inode,
1038         handle: Self::Handle,
1039         size: u32,
1040         offset: u64,
1041     ) -> io::Result<Self::DirIter> {
1042         Err(io::Error::from_raw_os_error(libc::ENOSYS))
1043     }
1044 
1045     /// Synchronize the contents of a directory.
1046     ///
1047     /// File systems must ensure that the directory contents have been flushed to disk before
1048     /// returning from this method. If `datasync` is true then only the directory data (but not the
1049     /// metadata) needs to be flushed.
1050     ///
1051     /// `handle` is the `Handle` returned by the file system from the `opendir` method, if any. If
1052     /// the file system did not return a `Handle` from `opendir` then the contents of
1053     /// `handle` are undefined.
1054     ///
1055     /// If this method returns an `ENOSYS` error then the kernel will treat it as success and all
1056     /// subsequent calls to `fsyncdir` will be handled by the kernel without being forwarded to the
1057     /// file system.
fsyncdir( &self, ctx: Context, inode: Self::Inode, datasync: bool, handle: Self::Handle, ) -> io::Result<()>1058     fn fsyncdir(
1059         &self,
1060         ctx: Context,
1061         inode: Self::Inode,
1062         datasync: bool,
1063         handle: Self::Handle,
1064     ) -> io::Result<()> {
1065         Err(io::Error::from_raw_os_error(libc::ENOSYS))
1066     }
1067 
1068     /// Release an open directory.
1069     ///
1070     /// For every `opendir` call there will be exactly one `releasedir` call (unless the file system
1071     /// is force-unmounted).
1072     ///
1073     /// `handle` is the `Handle` returned by the file system from the `opendir` method, if any. If
1074     /// the file system did not return a `Handle` from `opendir` then the contents of `handle` are
1075     /// undefined.
1076     ///
1077     /// `flags` contains used the flags used to open the directory in `opendir`.
releasedir( &self, ctx: Context, inode: Self::Inode, flags: u32, handle: Self::Handle, ) -> io::Result<()>1078     fn releasedir(
1079         &self,
1080         ctx: Context,
1081         inode: Self::Inode,
1082         flags: u32,
1083         handle: Self::Handle,
1084     ) -> io::Result<()> {
1085         Err(io::Error::from_raw_os_error(libc::ENOSYS))
1086     }
1087 
1088     /// Check file access permissions.
1089     ///
1090     /// This method is called when a userspace process in the client makes an `access()` or
1091     /// `chdir()` system call. If the file system was mounted with the `-o default_permissions`
1092     /// mount option, then the kernel will perform these checks itself and this method will not be
1093     /// called.
1094     ///
1095     /// If this method returns an `ENOSYS` error, then the kernel will treat it as a permanent
1096     /// success: all future calls to `access` will return success without being forwarded to the
1097     /// file system.
access(&self, ctx: Context, inode: Self::Inode, mask: u32) -> io::Result<()>1098     fn access(&self, ctx: Context, inode: Self::Inode, mask: u32) -> io::Result<()> {
1099         Err(io::Error::from_raw_os_error(libc::ENOSYS))
1100     }
1101 
1102     /// Perform an ioctl on a file or directory.
1103     ///
1104     /// `handle` is the `Handle` returned by the file system from the `open` or `opendir` methods,
1105     /// if any. If the file system did not return a `Handle` from then the contents of `handle` are
1106     /// undefined.
1107     ///
1108     /// If `flags` contains `IoctlFlags::UNRESTRICTED` then the file system may retry the ioctl
1109     /// after informing the kernel about the input and output areas. If `flags` does not contain
1110     /// `IoctlFlags::UNRESTRICTED` then the kernel will prepare the input and output areas according
1111     /// to the encoding in the ioctl command. In that case the ioctl cannot be retried.
1112     ///
1113     /// `cmd` is the ioctl request made by the calling process, truncated to 32 bits.
1114     ///
1115     /// `arg` is the argument provided by the calling process.
1116     ///
1117     /// `in_size` is the length of the additional data that accompanies the request. The file system
1118     /// may fetch this data from `reader`.
1119     ///
1120     /// `out_size` is the length of the output area prepared by the kernel to hold the response to
1121     /// the ioctl.
ioctl<R: io::Read>( &self, ctx: Context, inode: Self::Inode, handle: Self::Handle, flags: IoctlFlags, cmd: u32, arg: u64, in_size: u32, out_size: u32, reader: R, ) -> io::Result<IoctlReply>1122     fn ioctl<R: io::Read>(
1123         &self,
1124         ctx: Context,
1125         inode: Self::Inode,
1126         handle: Self::Handle,
1127         flags: IoctlFlags,
1128         cmd: u32,
1129         arg: u64,
1130         in_size: u32,
1131         out_size: u32,
1132         reader: R,
1133     ) -> io::Result<IoctlReply> {
1134         Err(io::Error::from_raw_os_error(libc::ENOSYS))
1135     }
1136 
1137     /// TODO: support this
getlk(&self) -> io::Result<()>1138     fn getlk(&self) -> io::Result<()> {
1139         Err(io::Error::from_raw_os_error(libc::ENOSYS))
1140     }
1141 
1142     /// TODO: support this
setlk(&self) -> io::Result<()>1143     fn setlk(&self) -> io::Result<()> {
1144         Err(io::Error::from_raw_os_error(libc::ENOSYS))
1145     }
1146 
1147     /// TODO: support this
setlkw(&self) -> io::Result<()>1148     fn setlkw(&self) -> io::Result<()> {
1149         Err(io::Error::from_raw_os_error(libc::ENOSYS))
1150     }
1151 
1152     /// TODO: support this
bmap(&self) -> io::Result<()>1153     fn bmap(&self) -> io::Result<()> {
1154         Err(io::Error::from_raw_os_error(libc::ENOSYS))
1155     }
1156 
1157     /// TODO: support this
poll(&self) -> io::Result<()>1158     fn poll(&self) -> io::Result<()> {
1159         Err(io::Error::from_raw_os_error(libc::ENOSYS))
1160     }
1161 
1162     /// TODO: support this
notify_reply(&self) -> io::Result<()>1163     fn notify_reply(&self) -> io::Result<()> {
1164         Err(io::Error::from_raw_os_error(libc::ENOSYS))
1165     }
1166 
1167     /// TODO: support this
lseek(&self) -> io::Result<()>1168     fn lseek(&self) -> io::Result<()> {
1169         Err(io::Error::from_raw_os_error(libc::ENOSYS))
1170     }
1171 
1172     /// Copy a range of data from one file to another
1173     ///
1174     /// Performs an optimized copy between two file descriptors without the additional cost of
1175     /// transferring data through the kernel module to user space (glibc) and then back into
1176     /// the file system again.
1177     ///
1178     /// In case this method is not implemented, glibc falls back to reading data from the source and
1179     /// writing to the destination.
1180     ///
1181     /// If this method fails with an `ENOSYS` error, then the kernel will treat that as a permanent
1182     /// failure. The kernel will return `EOPNOTSUPP` for all future calls to `copy_file_range`
1183     /// without forwarding them to the file system.
1184     ///
1185     /// All values accepted by the `copy_file_range(2)` system call are valid values for `flags` and
1186     /// must be handled by the file system.
copy_file_range( &self, ctx: Context, inode_src: Self::Inode, handle_src: Self::Handle, offset_src: u64, inode_dst: Self::Inode, handle_dst: Self::Handle, offset_dst: u64, length: u64, flags: u64, ) -> io::Result<usize>1187     fn copy_file_range(
1188         &self,
1189         ctx: Context,
1190         inode_src: Self::Inode,
1191         handle_src: Self::Handle,
1192         offset_src: u64,
1193         inode_dst: Self::Inode,
1194         handle_dst: Self::Handle,
1195         offset_dst: u64,
1196         length: u64,
1197         flags: u64,
1198     ) -> io::Result<usize> {
1199         Err(io::Error::from_raw_os_error(libc::ENOSYS))
1200     }
1201 
1202     /// Set up memory mappings.
1203     ///
1204     /// Used to set up file mappings in DAX window.
1205     ///
1206     /// # Arguments
1207     ///
1208     /// * `file_offset` - Offset into the file to start the mapping.
1209     /// * `mem_offset` - Offset in Memory Window.
1210     /// * `size` - Length of mapping required.
1211     /// * `flags` - Bit field of `FUSE_SETUPMAPPING_FLAGS_*`.
1212     /// * `mapper` - Mapper object which performs the mapping.
set_up_mapping<M: Mapper>( &self, ctx: Context, inode: Self::Inode, handle: Self::Handle, file_offset: u64, mem_offset: u64, size: usize, flags: u32, mapper: M, ) -> io::Result<()>1213     fn set_up_mapping<M: Mapper>(
1214         &self,
1215         ctx: Context,
1216         inode: Self::Inode,
1217         handle: Self::Handle,
1218         file_offset: u64,
1219         mem_offset: u64,
1220         size: usize,
1221         flags: u32,
1222         mapper: M,
1223     ) -> io::Result<()> {
1224         Err(io::Error::from_raw_os_error(libc::ENOSYS))
1225     }
1226 
1227     /// Remove memory mappings.
1228     ///
1229     /// Used to tear down file mappings in DAX window. This method must be supported when
1230     /// `set_up_mapping` is supported.
remove_mapping<M: Mapper>(&self, msgs: &[RemoveMappingOne], mapper: M) -> io::Result<()>1231     fn remove_mapping<M: Mapper>(&self, msgs: &[RemoveMappingOne], mapper: M) -> io::Result<()> {
1232         Err(io::Error::from_raw_os_error(libc::ENOSYS))
1233     }
1234 
1235     /// Lookup and open/create the file
1236     ///
1237     /// In this call, program first do a lookup on the file. Then depending upon
1238     /// flags combination, either do create + open, open only or return error.
1239     /// In all successful cases, it will return the dentry. For return value's
1240     /// handle and open options atomic_open should apply same rules to handle
1241     /// flags and configuration in open/create system call.
1242     ///
1243     /// This function is called when the client supports FUSE_OPEN_ATOMIC.
1244     /// Implementing atomic_open is optional. When the it's not implemented,
1245     /// the client fall back to send lookup and open requests separately.
1246     ///
1247     ///  # Specification
1248     ///
1249     /// If file was indeed newly created (as a result of O_CREAT), then set
1250     /// `FOPEN_FILE_CREATED` bit in `struct OpenOptions open`. This bit is used by
1251     ///  crosvm to inform the fuse client to set `FILE_CREATED` bit in `struct
1252     /// fuse_file_info'.
1253     ///
1254     /// All flags applied to open/create should be handled samely in atomic open,
1255     /// only the following are exceptions:
1256     /// * The O_NOCTTY is filtered out by fuse client.
1257     /// * O_TRUNC is filtered out by VFS for O_CREAT, O_EXCL combination.
1258     ///
1259     /// # Implementation
1260     ///
1261     /// To implement this API, you need to handle the following cases:
1262     ///
1263     /// a) File does not exist
1264     ///  - O_CREAT:
1265     ///    - Create file with specified mode
1266     ///    - Set `FOPEN_FILE_CREATED` bit in `struct OpenOptions open`
1267     ///    - Open the file
1268     ///    - Return d_entry and file handler
1269     ///  - ~O_CREAT:
1270     ///    - ENOENT
1271     ///
1272     /// b) File exist already (exception is O_EXCL)
1273     ///    - O_CREAT:
1274     ///      - Open the file
1275     ///      - Return d_entry and file handler
1276     ///    - O_EXCL:
1277     ///      - EEXIST
1278     ///
1279     /// c) File is symbol link
1280     ///    - Return dentry and file handler
atomic_open( &self, ctx: Context, parent: Self::Inode, name: &CStr, mode: u32, flags: u32, umask: u32, security_ctx: Option<&CStr>, ) -> io::Result<(Entry, Option<Self::Handle>, OpenOptions)>1281     fn atomic_open(
1282         &self,
1283         ctx: Context,
1284         parent: Self::Inode,
1285         name: &CStr,
1286         mode: u32,
1287         flags: u32,
1288         umask: u32,
1289         security_ctx: Option<&CStr>,
1290     ) -> io::Result<(Entry, Option<Self::Handle>, OpenOptions)> {
1291         Err(io::Error::from_raw_os_error(libc::ENOSYS))
1292     }
1293 }
1294