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