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