// Copyright 2019 The ChromiumOS Authors1// Use of this source code is governed by a BSD-style license that can be2// found in the LICENSE file.34//! Data structures and traits for the fuse filesystem.56#![deny(missing_docs)]78use std::convert::TryInto;9use std::ffi::CStr;10use std::fs::File;11use std::io;12use std::mem;13use std::mem::MaybeUninit;14use std::time::Duration;1516use crate::server::Mapper;17use crate::sys;18pub use crate::sys::FsOptions;19pub use crate::sys::IoctlFlags;20pub use crate::sys::IoctlIovec;21pub use crate::sys::OpenOptions;22pub use crate::sys::RemoveMappingOne;23pub use crate::sys::SetattrValid;24pub use crate::sys::ROOT_ID;2526const MAX_BUFFER_SIZE: u32 = 1 << 20;2728/// Information about a path in the filesystem.29#[derive(Debug)]30pub struct Entry {31/// An `Inode` that uniquely identifies this path. During `lookup`, setting this to `0` means a32/// negative entry. Returning `ENOENT` also means a negative entry but setting this to `0`33/// allows the kernel to cache the negative result for `entry_timeout`. The value should be34/// produced by converting a `FileSystem::Inode` into a `u64`.35pub inode: u64,3637/// The generation number for this `Entry`. Typically used for network file systems. An `inode`38/// / `generation` pair must be unique over the lifetime of the file system (rather than just39/// the lifetime of the mount). In other words, if a `FileSystem` implementation re-uses an40/// `Inode` after it has been deleted then it must assign a new, previously unused generation41/// number to the `Inode` at the same time.42pub generation: u64,4344/// Inode attributes. Even if `attr_timeout` is zero, `attr` must be correct. For example, for45/// `open()`, FUSE uses `attr.st_size` from `lookup()` to determine how many bytes to request.46/// If this value is not correct, incorrect data will be returned.47pub attr: libc::stat64,4849/// How long the values in `attr` should be considered valid. If the attributes of the `Entry`50/// are only modified by the FUSE client, then this should be set to a very large value.51pub attr_timeout: Duration,5253/// How long the name associated with this `Entry` should be considered valid. If directory54/// entries are only changed or deleted by the FUSE client, then this should be set to a very55/// large value.56pub entry_timeout: Duration,57}5859impl From<Entry> for sys::EntryOut {60fn from(entry: Entry) -> sys::EntryOut {61sys::EntryOut {62nodeid: entry.inode,63generation: entry.generation,64entry_valid: entry.entry_timeout.as_secs(),65attr_valid: entry.attr_timeout.as_secs(),66entry_valid_nsec: entry.entry_timeout.subsec_nanos(),67attr_valid_nsec: entry.attr_timeout.subsec_nanos(),68attr: entry.attr.into(),69}70}71}7273impl Entry {74/// Creates a new negative cache entry. A negative d_entry has an inode number of 0, and is75/// valid for the duration of `negative_timeout`.76///77/// # Arguments78///79/// * `negative_timeout` - The duration for which this negative d_entry should be considered80/// valid. After the timeout expires, the d_entry will be invalidated.81///82/// # Returns83///84/// A new negative entry with provided entry timeout and 0 attr timeout.85pub fn new_negative(negative_timeout: Duration) -> Entry {86let attr = MaybeUninit::<libc::stat64>::zeroed();87Entry {88inode: 0, // Using 0 for negative entry89entry_timeout: negative_timeout,90// Zero-fill other fields that won't be used.91attr_timeout: Duration::from_secs(0),92generation: 0,93// SAFETY: zero-initialized `stat64` is a valid value.94attr: unsafe { attr.assume_init() },95}96}97}9899/// Represents information about an entry in a directory.100pub struct DirEntry<'a> {101/// The inode number for this entry. This does NOT have to be the same as the `Inode` for this102/// directory entry. However, it must be the same as the `attr.st_ino` field of the `Entry`103/// that would be returned by a `lookup` request in the parent directory for `name`.104pub ino: libc::ino64_t,105106/// Any non-zero value that the kernel can use to identify the current point in the directory107/// entry stream. It does not need to be the actual physical position. A value of `0` is108/// reserved to mean "from the beginning" and should never be used. The `offset` value of the109/// first entry in a stream should point to the beginning of the second entry and so on.110pub offset: u64,111112/// The type of this directory entry. Valid values are any of the `libc::DT_*` constants.113pub type_: u32,114115/// The name of this directory entry. There are no requirements for the contents of this field116/// and any sequence of bytes is considered valid.117pub name: &'a CStr,118}119120/// A reply to a `getxattr` method call.121#[derive(Debug)]122pub enum GetxattrReply {123/// The value of the requested extended attribute. This can be arbitrary textual or binary data124/// and does not need to be nul-terminated.125Value(Vec<u8>),126127/// The size of the buffer needed to hold the value of the requested extended attribute. Should128/// be returned when the `size` parameter is 0. Callers should note that it is still possible129/// for the size of the value to change in between `getxattr` calls and should not assume that130/// a subsequent call to `getxattr` with the returned count will always succeed.131Count(u32),132}133134/// A reply to a `listxattr` method call.135pub enum ListxattrReply {136/// A buffer containing a nul-separated list of the names of all the extended attributes137/// associated with this `Inode`. This list of names may be unordered and includes a namespace138/// prefix. There may be several disjoint namespaces associated with a single `Inode`.139Names(Vec<u8>),140141/// This size of the buffer needed to hold the full list of extended attribute names associated142/// with this `Inode`. Should be returned when the `size` parameter is 0. Callers should note143/// 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 returned145/// count will always succeed.146Count(u32),147}148149/// A reply to an `ioctl` method call.150#[derive(Debug)]151pub enum IoctlReply {152/// Indicates that the ioctl should be retried. This is only a valid reply when the `flags`153/// field of the ioctl request contains `IoctlFlags::UNRESTRICTED`. The kernel will read in154/// data and prepare output buffers as specified in the `input` and `output` fields before155/// re-sending the ioctl message.156Retry {157/// Data that should be read by the kernel module and sent to the server when the ioctl is158/// retried.159input: Vec<IoctlIovec>,160161/// Buffer space that should be prepared so that the server can send back the response to162/// the ioctl.163output: Vec<IoctlIovec>,164},165166/// Indicates that the ioctl was processed.167Done(io::Result<Vec<u8>>),168}169170/// A trait for directly copying data from the fuse transport into a `File` without first storing it171/// in an intermediate buffer.172pub trait ZeroCopyReader {173/// Copies at most `count` bytes from `self` directly into `f` at offset `off` without storing174/// it in any intermediate buffers. If the return value is `Ok(n)` then it must be guaranteed175/// that `0 <= n <= count`. If `n` is `0`, then it can indicate one of 3 possibilities:176///177/// 1. There is no more data left in `self`.178/// 2. There is no more space in `f`.179/// 3. `count` was `0`.180///181/// # Errors182///183/// If any error is returned then the implementation must guarantee that no bytes were copied184/// from `self`. If the underlying write to `f` returns `0` then the implementation must return185/// an error of the kind `io::ErrorKind::WriteZero`.186fn read_to(&mut self, f: &mut File, count: usize, off: u64) -> io::Result<usize>;187188/// Copies exactly `count` bytes of data from `self` into `f` at offset `off`. `off + count`189/// must be less than `u64::MAX`.190///191/// # Errors192///193/// If an error is returned then the number of bytes copied from `self` is unspecified but it194/// will never be more than `count`.195fn read_exact_to(&mut self, f: &mut File, mut count: usize, mut off: u64) -> io::Result<()> {196let c = count197.try_into()198.map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?;199if off.checked_add(c).is_none() {200return Err(io::Error::new(201io::ErrorKind::InvalidInput,202"`off` + `count` must be less than u64::MAX",203));204}205206while count > 0 {207match self.read_to(f, count, off) {208Ok(0) => {209return Err(io::Error::new(210io::ErrorKind::WriteZero,211"failed to fill whole buffer",212))213}214Ok(n) => {215count -= n;216off += n as u64;217}218Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}219Err(e) => return Err(e),220}221}222223Ok(())224}225226/// Copies all remaining bytes from `self` into `f` at offset `off`. Equivalent to repeatedly227/// calling `read_to` until it returns either `Ok(0)` or a non-`ErrorKind::Interrupted` error.228///229/// # Errors230///231/// If an error is returned then the number of bytes copied from `self` is unspecified.232fn copy_to_end(&mut self, f: &mut File, mut off: u64) -> io::Result<usize> {233let mut out = 0;234loop {235match self.read_to(f, usize::MAX, off) {236Ok(0) => return Ok(out),237Ok(n) => {238off = off.saturating_add(n as u64);239out += n;240}241Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}242Err(e) => return Err(e),243}244}245}246}247248impl<R: ZeroCopyReader> ZeroCopyReader for &mut R {249fn read_to(&mut self, f: &mut File, count: usize, off: u64) -> io::Result<usize> {250(**self).read_to(f, count, off)251}252fn read_exact_to(&mut self, f: &mut File, count: usize, off: u64) -> io::Result<()> {253(**self).read_exact_to(f, count, off)254}255fn copy_to_end(&mut self, f: &mut File, off: u64) -> io::Result<usize> {256(**self).copy_to_end(f, off)257}258}259260/// A trait for directly copying data from a `File` into the fuse transport without first storing261/// it in an intermediate buffer.262pub trait ZeroCopyWriter {263/// Copies at most `count` bytes from `f` at offset `off` directly into `self` without storing264/// it in any intermediate buffers. If the return value is `Ok(n)` then it must be guaranteed265/// that `0 <= n <= count`. If `n` is `0`, then it can indicate one of 3 possibilities:266///267/// 1. There is no more data left in `f`.268/// 2. There is no more space in `self`.269/// 3. `count` was `0`.270///271/// # Errors272///273/// If any error is returned then the implementation must guarantee that no bytes were copied274/// from `f`. If the underlying read from `f` returns `0` then the implementation must return an275/// error of the kind `io::ErrorKind::UnexpectedEof`.276fn write_from(&mut self, f: &mut File, count: usize, off: u64) -> io::Result<usize>;277278/// Copies exactly `count` bytes of data from `f` at offset `off` into `self`. `off + count`279/// must be less than `u64::MAX`.280///281/// # Errors282///283/// If an error is returned then the number of bytes copied from `self` is unspecified but it284/// well never be more than `count`.285fn write_all_from(&mut self, f: &mut File, mut count: usize, mut off: u64) -> io::Result<()> {286let c = count287.try_into()288.map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?;289if off.checked_add(c).is_none() {290return Err(io::Error::new(291io::ErrorKind::InvalidInput,292"`off` + `count` must be less than u64::MAX",293));294}295296while count > 0 {297match self.write_from(f, count, off) {298Ok(0) => {299return Err(io::Error::new(300io::ErrorKind::UnexpectedEof,301"failed to write whole buffer",302))303}304Ok(n) => {305// No need for checked math here because we verified that `off + count` will not306// overflow and `n` must be <= `count`.307count -= n;308off += n as u64;309}310Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}311Err(e) => return Err(e),312}313}314315Ok(())316}317318/// Copies all remaining bytes from `f` at offset `off` into `self`. Equivalent to repeatedly319/// calling `write_from` until it returns either `Ok(0)` or a non-`ErrorKind::Interrupted`320/// error.321///322/// # Errors323///324/// If an error is returned then the number of bytes copied from `f` is unspecified.325fn copy_to_end(&mut self, f: &mut File, mut off: u64) -> io::Result<usize> {326let mut out = 0;327loop {328match self.write_from(f, usize::MAX, off) {329Ok(0) => return Ok(out),330Ok(n) => {331off = off.saturating_add(n as u64);332out += n;333}334Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}335Err(e) => return Err(e),336}337}338}339}340341impl<W: ZeroCopyWriter> ZeroCopyWriter for &mut W {342fn write_from(&mut self, f: &mut File, count: usize, off: u64) -> io::Result<usize> {343(**self).write_from(f, count, off)344}345fn write_all_from(&mut self, f: &mut File, count: usize, off: u64) -> io::Result<()> {346(**self).write_all_from(f, count, off)347}348fn copy_to_end(&mut self, f: &mut File, off: u64) -> io::Result<usize> {349(**self).copy_to_end(f, off)350}351}352353/// Additional context associated with requests.354#[derive(Clone, Copy, Debug)]355pub struct Context {356/// The user ID of the calling process.357pub uid: libc::uid_t,358359/// The group ID of the calling process.360pub gid: libc::gid_t,361362/// The thread group ID of the calling process.363pub pid: libc::pid_t,364}365366impl From<sys::InHeader> for Context {367fn from(source: sys::InHeader) -> Self {368Context {369uid: source.uid,370gid: source.gid,371pid: source.pid as i32,372}373}374}375376/// A trait for iterating over the contents of a directory. This trait is needed because rust377/// doesn't support generic associated types, which means that it's not possible to implement a378/// regular iterator that yields a `DirEntry` due to its generic lifetime parameter.379pub trait DirectoryIterator {380/// Returns the next entry in the directory or `None` if there are no more.381fn next(&mut self) -> Option<DirEntry>;382}383384/// The main trait that connects a file system with a transport.385#[allow(unused_variables)]386pub trait FileSystem {387/// Represents a location in the filesystem tree and can be used to perform operations that act388/// on the metadata of a file/directory (e.g., `getattr` and `setattr`). Can also be used as the389/// starting point for looking up paths in the filesystem tree. An `Inode` may support operating390/// directly on the content of the path that to which it points. `FileSystem` implementations391/// that support this should set the `FsOptions::ZERO_MESSAGE_OPEN` option in the return value392/// of the `init` function. On linux based systems, an `Inode` is equivalent to opening a file393/// or directory with the `libc::O_PATH` flag.394///395/// # Lookup Count396///397/// The `FileSystem` implementation is required to keep a "lookup count" for every `Inode`.398/// Every time an `Entry` is returned by a `FileSystem` trait method, this lookup count should399/// increase by 1. The lookup count for an `Inode` decreases when the kernel sends a `forget`400/// request. `Inode`s with a non-zero lookup count may receive requests from the kernel even401/// after calls to `unlink`, `rmdir` or (when overwriting an existing file) `rename`.402/// `FileSystem` implementations must handle such requests properly and it is recommended to403/// defer removal of the `Inode` until the lookup count reaches zero. Calls to `unlink`, `rmdir`404/// or `rename` will be followed closely by `forget` unless the file or directory is open, in405/// which case the kernel issues `forget` only after the `release` or `releasedir` calls.406///407/// Note that if a file system will be exported over NFS the `Inode`'s lifetime must extend even408/// beyond `forget`. See the `generation` field in `Entry`.409type Inode: From<u64> + Into<u64>;410411/// Represents a file or directory that is open for reading/writing.412type Handle: From<u64> + Into<u64>;413414/// An iterator over the entries of a directory. See the documentation for `readdir` for more415/// details.416type DirIter: DirectoryIterator;417418/// Maximum size of the buffer that the filesystem can generate data to, including the header.419/// This corresponds to max_write in the initialization.420fn max_buffer_size(&self) -> u32 {421MAX_BUFFER_SIZE422}423424/// Initialize the file system.425///426/// This method is called when a connection to the FUSE kernel module is first established. The427/// `capable` parameter indicates the features that are supported by the kernel module. The428/// implementation should return the options that it supports. Any options set in the returned429/// `FsOptions` that are not also set in `capable` are silently dropped.430fn init(&self, capable: FsOptions) -> io::Result<FsOptions> {431Ok(FsOptions::empty())432}433434/// Clean up the file system.435///436/// Called when the filesystem exits. All open `Handle`s should be closed and the lookup count437/// for all open `Inode`s implicitly goes to zero. At this point the connection to the FUSE438/// kernel module may already be gone so implementations should not rely on being able to439/// communicate with the kernel.440fn destroy(&self) {}441442/// Look up a directory entry by name and get its attributes.443///444/// If this call is successful then the lookup count of the `Inode` associated with the returned445/// `Entry` must be increased by 1.446fn lookup(&self, ctx: Context, parent: Self::Inode, name: &CStr) -> io::Result<Entry> {447Err(io::Error::from_raw_os_error(libc::ENOSYS))448}449450/// Forget about an inode.451///452/// Called when the kernel removes an inode from its internal caches. `count` indicates the453/// amount by which the lookup count for the inode should be decreased. If reducing the lookup454/// count by `count` causes it to go to zero, then the implementation may delete the `Inode`.455fn forget(&self, ctx: Context, inode: Self::Inode, count: u64) {}456457/// Forget about multiple inodes.458///459/// `requests` is a vector of `(inode, count)` pairs. See the documentation for `forget` for460/// more information.461fn batch_forget(&self, ctx: Context, requests: Vec<(Self::Inode, u64)>) {462for (inode, count) in requests {463self.forget(ctx, inode, count)464}465}466467/// Get attributes for a file / directory.468///469/// If `handle` is not `None`, then it contains the handle previously returned by the470/// implementation after a call to `open` or `opendir`. However, implementations should still471/// take care to verify the handle if they do not trust the client (e.g., virtio-fs).472///473/// If writeback caching is enabled (`FsOptions::WRITEBACK_CACHE`), then the kernel module474/// likely has a better idea of the length of the file than the file system (for475/// example, if there was a write that extended the size of the file but has not yet been476/// flushed). In this case, the `st_size` field of the returned struct is ignored.477///478/// The returned `Duration` indicates how long the returned attributes should be considered479/// valid by the client. If the attributes are only changed via the FUSE kernel module (i.e.,480/// the kernel module has exclusive access), then this should be a very large value.481fn getattr(482&self,483ctx: Context,484inode: Self::Inode,485handle: Option<Self::Handle>,486) -> io::Result<(libc::stat64, Duration)> {487Err(io::Error::from_raw_os_error(libc::ENOSYS))488}489490/// Set attributes for a file / directory.491///492/// If `handle` is not `None`, then it contains the handle previously returned by the493/// implementation after a call to `open` or `opendir`. However, implementations should still494/// take care to verify the handle if they do not trust the client (e.g., virtio-fs).495///496/// The `valid` parameter indicates the fields of `attr` that may be considered valid and should497/// be set by the file system. The content of all other fields in `attr` is undefined.498///499/// If the `FsOptions::HANDLE_KILLPRIV` was set during `init`, then the implementation is500/// expected to reset the setuid and setgid bits if the file size or owner is being changed.501///502/// This method returns the new attributes after making the modifications requested by the503/// client. The returned `Duration` indicates how long the returned attributes should be504/// considered valid by the client. If the attributes are only changed via the FUSE kernel505/// module (i.e., the kernel module has exclusive access), then this should be a very large506/// value.507fn setattr(508&self,509ctx: Context,510inode: Self::Inode,511attr: libc::stat64,512handle: Option<Self::Handle>,513valid: SetattrValid,514) -> io::Result<(libc::stat64, Duration)> {515Err(io::Error::from_raw_os_error(libc::ENOSYS))516}517518/// Read a symbolic link.519fn readlink(&self, ctx: Context, inode: Self::Inode) -> io::Result<Vec<u8>> {520Err(io::Error::from_raw_os_error(libc::ENOSYS))521}522523/// Create a symbolic link.524///525/// The file system must create a symbolic link named `name` in the directory represented by526/// `parent`, which contains the string `linkname`. Returns an `Entry` for the newly created527/// symlink.528///529/// If this call is successful then the lookup count of the `Inode` associated with the returned530/// `Entry` must be increased by 1.531fn symlink(532&self,533ctx: Context,534linkname: &CStr,535parent: Self::Inode,536name: &CStr,537security_ctx: Option<&CStr>,538) -> io::Result<Entry> {539Err(io::Error::from_raw_os_error(libc::ENOSYS))540}541542/// Create a file node.543///544/// Create a regular file, character device, block device, fifo, or socket node named `name` in545/// the directory represented by `inode`. Valid values for `mode` and `rdev` are the same as546/// those accepted by the `mknod(2)` system call. Returns an `Entry` for the newly created node.547///548/// When the `FsOptions::DONT_MASK` feature is set, the file system is responsible for setting549/// the permissions of the created node to `mode & !umask`.550///551/// If this call is successful then the lookup count of the `Inode` associated with the returned552/// `Entry` must be increased by 1.553fn mknod(554&self,555ctx: Context,556inode: Self::Inode,557name: &CStr,558mode: u32,559rdev: u32,560umask: u32,561security_ctx: Option<&CStr>,562) -> io::Result<Entry> {563Err(io::Error::from_raw_os_error(libc::ENOSYS))564}565566/// Create a directory.567///568/// When the `FsOptions::DONT_MASK` feature is set, the file system is responsible for setting569/// the permissions of the created directory to `mode & !umask`. Returns an `Entry` for the570/// newly created directory.571///572/// If this call is successful then the lookup count of the `Inode` associated with the returned573/// `Entry` must be increased by 1.574fn mkdir(575&self,576ctx: Context,577parent: Self::Inode,578name: &CStr,579mode: u32,580umask: u32,581security_ctx: Option<&CStr>,582) -> io::Result<Entry> {583Err(io::Error::from_raw_os_error(libc::ENOSYS))584}585586/// Create an unnamed temporary file.587fn chromeos_tmpfile(588&self,589ctx: Context,590parent: Self::Inode,591mode: u32,592umask: u32,593security_ctx: Option<&CStr>,594) -> io::Result<Entry> {595Err(io::Error::from_raw_os_error(libc::ENOSYS))596}597598/// Remove a file.599///600/// If the file's inode lookup count is non-zero, then the file system is expected to delay601/// removal of the inode until the lookup count goes to zero. See the documentation of the602/// `forget` function for more information.603fn unlink(&self, ctx: Context, parent: Self::Inode, name: &CStr) -> io::Result<()> {604Err(io::Error::from_raw_os_error(libc::ENOSYS))605}606607/// Remove a directory.608///609/// If the directory's inode lookup count is non-zero, then the file system is expected to delay610/// removal of the inode until the lookup count goes to zero. See the documentation of the611/// `forget` function for more information.612fn rmdir(&self, ctx: Context, parent: Self::Inode, name: &CStr) -> io::Result<()> {613Err(io::Error::from_raw_os_error(libc::ENOSYS))614}615616/// Rename a file / directory.617///618/// If the destination exists, it should be atomically replaced. If the destination's inode619/// lookup count is non-zero, then the file system is expected to delay removal of the inode620/// until the lookup count goes to zero. See the documentation of the `forget` function for more621/// information.622///623/// `flags` may be `libc::RENAME_EXCHANGE` or `libc::RENAME_NOREPLACE`. If624/// `libc::RENAME_NOREPLACE` is specified, the implementation must not overwrite `newname` if it625/// exists and must return an error instead. If `libc::RENAME_EXCHANGE` is specified, the626/// implementation must atomically exchange the two files, i.e., both must exist and neither may627/// be deleted.628fn rename(629&self,630ctx: Context,631olddir: Self::Inode,632oldname: &CStr,633newdir: Self::Inode,634newname: &CStr,635flags: u32,636) -> io::Result<()> {637Err(io::Error::from_raw_os_error(libc::ENOSYS))638}639640/// Create a hard link.641///642/// Create a hard link from `inode` to `newname` in the directory represented by `newparent`.643///644/// If this call is successful then the lookup count of the `Inode` associated with the returned645/// `Entry` must be increased by 1.646fn link(647&self,648ctx: Context,649inode: Self::Inode,650newparent: Self::Inode,651newname: &CStr,652) -> io::Result<Entry> {653Err(io::Error::from_raw_os_error(libc::ENOSYS))654}655656/// Open a file.657///658/// Open the file associated with `inode` for reading / writing. All values accepted by the659/// `open(2)` system call are valid values for `flags` and must be handled by the file system.660/// However, there are some additional rules:661///662/// * Creation flags (`libc::O_CREAT`, `libc::O_EXCL`, `libc::O_NOCTTY`) will be filtered out663/// and handled by the kernel.664///665/// * The file system should check the access modes (`libc::O_RDONLY`, `libc::O_WRONLY`,666/// `libc::O_RDWR`) to determine if the operation is permitted. If the file system was mounted667/// with the `-o default_permissions` mount option, then this check will also be carried out668/// by the kernel before sending the open request.669///670/// * When writeback caching is enabled (`FsOptions::WRITEBACK_CACHE`) the kernel may send read671/// requests even for files opened with `libc::O_WRONLY`. The file system should be prepared672/// to handle this.673///674/// * When writeback caching is enabled, the kernel will handle the `libc::O_APPEND` flag.675/// However, this will not work reliably unless the kernel has exclusive access to the file.676/// In this case the file system may either ignore the `libc::O_APPEND` flag or return an677/// error to indicate that reliable `libc::O_APPEND` handling is not available.678///679/// * When writeback caching is disabled, the file system is expected to properly handle680/// `libc::O_APPEND` and ensure that each write is appended to the end of the file.681///682/// The file system may choose to return a `Handle` to refer to the newly opened file. The683/// kernel will then use this `Handle` for all operations on the content of the file (`read`,684/// `write`, `flush`, `release`, `fsync`). If the file system does not return a685/// `Handle` then the kernel will use the `Inode` for the file to operate on its contents. In686/// this case the file system may wish to enable the `FsOptions::ZERO_MESSAGE_OPEN` feature if687/// it is supported by the kernel (see below).688///689/// The returned `OpenOptions` allow the file system to change the way the opened file is690/// handled by the kernel. See the documentation of `OpenOptions` for more information.691///692/// If the `FsOptions::ZERO_MESSAGE_OPEN` feature is enabled by both the file system693/// implementation and the kernel, then the file system may return an error of `ENOSYS`. This694/// will be interpreted by the kernel as success and future calls to `open` and `release` will695/// be handled by the kernel without being passed on to the file system.696fn open(697&self,698ctx: Context,699inode: Self::Inode,700flags: u32,701) -> io::Result<(Option<Self::Handle>, OpenOptions)> {702// Matches the behavior of libfuse.703Ok((None, OpenOptions::empty()))704}705706/// Create and open a file.707///708/// If the file does not already exist, the file system should create it with the specified709/// `mode`. When the `FsOptions::DONT_MASK` feature is set, the file system is responsible for710/// setting the permissions of the created file to `mode & !umask`.711///712/// If the file system returns an `ENOSYS` error, then the kernel will treat this method as713/// unimplemented and all future calls to `create` will be handled by calling the `mknod` and714/// `open` methods instead.715///716/// See the documentation for the `open` method for more information about opening the file. In717/// addition to the optional `Handle` and the `OpenOptions`, the file system must also return an718/// `Entry` for the file. This increases the lookup count for the `Inode` associated with the719/// file by 1.720fn create(721&self,722ctx: Context,723parent: Self::Inode,724name: &CStr,725mode: u32,726flags: u32,727umask: u32,728security_ctx: Option<&CStr>,729) -> io::Result<(Entry, Option<Self::Handle>, OpenOptions)> {730Err(io::Error::from_raw_os_error(libc::ENOSYS))731}732733/// Read data from a file.734///735/// Returns `size` bytes of data starting from offset `off` from the file associated with736/// `inode` or `handle`.737///738/// `flags` contains the flags used to open the file. Similarly, `handle` is the `Handle`739/// returned by the file system from the `open` method, if any. If the file system740/// implementation did not return a `Handle` from `open` then the contents of `handle` are741/// undefined.742///743/// This method should return exactly the number of bytes requested by the kernel, except in the744/// case of error or EOF. Otherwise, the kernel will substitute the rest of the data with745/// zeroes. An exception to this rule is if the file was opened with the "direct I/O" option746/// (`libc::O_DIRECT`), in which case the kernel will forward the return code from this method747/// to the userspace application that made the system call.748fn read<W: io::Write + ZeroCopyWriter>(749&self,750ctx: Context,751inode: Self::Inode,752handle: Self::Handle,753w: W,754size: u32,755offset: u64,756lock_owner: Option<u64>,757flags: u32,758) -> io::Result<usize> {759Err(io::Error::from_raw_os_error(libc::ENOSYS))760}761762/// Write data to a file.763///764/// Writes `size` bytes of data starting from offset `off` to the file associated with `inode`765/// or `handle`.766///767/// `flags` contains the flags used to open the file. Similarly, `handle` is the `Handle`768/// returned by the file system from the `open` method, if any. If the file system769/// implementation did not return a `Handle` from `open` then the contents of `handle` are770/// undefined.771///772/// If the `FsOptions::HANDLE_KILLPRIV` feature is not enabled then then the file system is773/// expected to clear the setuid and setgid bits.774///775/// If `delayed_write` is true then it indicates that this is a write for buffered data.776///777/// This method should return exactly the number of bytes requested by the kernel, except in the778/// case of error. An exception to this rule is if the file was opened with the "direct I/O"779/// option (`libc::O_DIRECT`), in which case the kernel will forward the return code from this780/// method to the userspace application that made the system call.781fn write<R: io::Read + ZeroCopyReader>(782&self,783ctx: Context,784inode: Self::Inode,785handle: Self::Handle,786r: R,787size: u32,788offset: u64,789lock_owner: Option<u64>,790delayed_write: bool,791flags: u32,792) -> io::Result<usize> {793Err(io::Error::from_raw_os_error(libc::ENOSYS))794}795796/// Flush the contents of a file.797///798/// This method is called on every `close()` of a file descriptor. Since it is possible to799/// duplicate file descriptors there may be many `flush` calls for one call to `open`.800///801/// File systems should not make any assumptions about when `flush` will be802/// called or even if it will be called at all.803///804/// `handle` is the `Handle` returned by the file system from the `open` method, if any. If the805/// file system did not return a `Handle` from `open` then the contents of `handle` are806/// undefined.807///808/// Unlike `fsync`, the file system is not required to flush pending writes. One reason to flush809/// data is if the file system wants to return write errors during close. However, this is not810/// portable because POSIX does not require `close` to wait for delayed I/O to complete.811///812/// If the `FsOptions::POSIX_LOCKS` feature is enabled, then the file system must remove all813/// locks belonging to `lock_owner`.814///815/// If this method returns an `ENOSYS` error then the kernel will treat it as success and all816/// subsequent calls to `flush` will be handled by the kernel without being forwarded to the817/// file system.818fn flush(819&self,820ctx: Context,821inode: Self::Inode,822handle: Self::Handle,823lock_owner: u64,824) -> io::Result<()> {825Err(io::Error::from_raw_os_error(libc::ENOSYS))826}827828/// Synchronize file contents.829///830/// File systems must ensure that the file contents have been flushed to disk before returning831/// from this method. If `datasync` is true then only the file data (but not the metadata) needs832/// to be flushed.833///834/// `handle` is the `Handle` returned by the file system from the `open` method, if any. If the835/// file system did not return a `Handle` from `open` then the contents of836/// `handle` are undefined.837///838/// If this method returns an `ENOSYS` error then the kernel will treat it as success and all839/// subsequent calls to `fsync` will be handled by the kernel without being forwarded to the840/// file system.841fn fsync(842&self,843ctx: Context,844inode: Self::Inode,845datasync: bool,846handle: Self::Handle,847) -> io::Result<()> {848Err(io::Error::from_raw_os_error(libc::ENOSYS))849}850851/// Allocate requested space for file data.852///853/// If this function returns success, then the file sytem must guarantee that it is possible to854/// write up to `length` bytes of data starting at `offset` without failing due to a lack of855/// free space on the disk.856///857/// `handle` is the `Handle` returned by the file system from the `open` method, if any. If the858/// file system did not return a `Handle` from `open` then the contents of `handle` are859/// undefined.860///861/// If this method returns an `ENOSYS` error then the kernel will treat that as a permanent862/// failure: all future calls to `fallocate` will fail with `EOPNOTSUPP` without being forwarded863/// to the file system.864fn fallocate(865&self,866ctx: Context,867inode: Self::Inode,868handle: Self::Handle,869mode: u32,870offset: u64,871length: u64,872) -> io::Result<()> {873Err(io::Error::from_raw_os_error(libc::ENOSYS))874}875876/// Release an open file.877///878/// This method is called when there are no more references to an open file: all file879/// descriptors are closed and all memory mappings are unmapped.880///881/// For every `open` call there will be exactly one `release` call (unless the file system is882/// force-unmounted).883///884/// The file system may reply with an error, but error values are not returned to the `close()`885/// or `munmap()` which triggered the release.886///887/// `handle` is the `Handle` returned by the file system from the `open` method, if any. If the888/// file system did not return a `Handle` from `open` then the contents of889/// `handle` are undefined.890///891/// If `flush` is `true` then the contents of the file should also be flushed to disk.892fn release(893&self,894ctx: Context,895inode: Self::Inode,896flags: u32,897handle: Self::Handle,898flush: bool,899flock_release: bool,900lock_owner: Option<u64>,901) -> io::Result<()> {902Err(io::Error::from_raw_os_error(libc::ENOSYS))903}904905/// Get information about the file system.906fn statfs(&self, ctx: Context, inode: Self::Inode) -> io::Result<libc::statvfs64> {907// SAFETY: zero-initializing a struct with only POD fields.908let mut st: libc::statvfs64 = unsafe { mem::zeroed() };909910// This matches the behavior of libfuse as it returns these values if the911// filesystem doesn't implement this method.912st.f_namemax = 255;913st.f_bsize = 512;914915Ok(st)916}917918/// Set an extended attribute.919///920/// If this method fails with an `ENOSYS` error, then the kernel will treat that as a permanent921/// failure. The kernel will return `EOPNOTSUPP` for all future calls to `setxattr` without922/// forwarding them to the file system.923///924/// Valid values for flags are the same as those accepted by the `setxattr(2)` system call and925/// have the same behavior.926fn setxattr(927&self,928ctx: Context,929inode: Self::Inode,930name: &CStr,931value: &[u8],932flags: u32,933) -> io::Result<()> {934Err(io::Error::from_raw_os_error(libc::ENOSYS))935}936937/// Get an extended attribute.938///939/// If `size` is 0, then the file system should respond with `GetxattrReply::Count` and the940/// number of bytes needed to hold the value. If `size` is large enough to hold the value, then941/// the file system should reply with `GetxattrReply::Value` and the value of the extended942/// attribute. If `size` is not 0 but is also not large enough to hold the value, then the file943/// system should reply with an `ERANGE` error.944///945/// If this method fails with an `ENOSYS` error, then the kernel will treat that as a permanent946/// failure. The kernel will return `EOPNOTSUPP` for all future calls to `getxattr` without947/// forwarding them to the file system.948fn getxattr(949&self,950ctx: Context,951inode: Self::Inode,952name: &CStr,953size: u32,954) -> io::Result<GetxattrReply> {955Err(io::Error::from_raw_os_error(libc::ENOSYS))956}957958/// List extended attribute names.959///960/// If `size` is 0, then the file system should respond with `ListxattrReply::Count` and the961/// number of bytes needed to hold a `\0` byte separated list of the names of all the extended962/// attributes. If `size` is large enough to hold the `\0` byte separated list of the attribute963/// names, then the file system should reply with `ListxattrReply::Names` and the list. If964/// `size` is not 0 but is also not large enough to hold the list, then the file system should965/// reply with an `ERANGE` error.966///967/// If this method fails with an `ENOSYS` error, then the kernel will treat that as a permanent968/// failure. The kernel will return `EOPNOTSUPP` for all future calls to `listxattr` without969/// forwarding them to the file system.970fn listxattr(&self, ctx: Context, inode: Self::Inode, size: u32) -> io::Result<ListxattrReply> {971Err(io::Error::from_raw_os_error(libc::ENOSYS))972}973974/// Remove an extended attribute.975///976/// If this method fails with an `ENOSYS` error, then the kernel will treat that as a permanent977/// failure. The kernel will return `EOPNOTSUPP` for all future calls to `removexattr` without978/// forwarding them to the file system.979fn removexattr(&self, ctx: Context, inode: Self::Inode, name: &CStr) -> io::Result<()> {980Err(io::Error::from_raw_os_error(libc::ENOSYS))981}982983/// Open a directory for reading.984///985/// The file system may choose to return a `Handle` to refer to the newly opened directory. The986/// kernel will then use this `Handle` for all operations on the content of the directory987/// (`readdir`, `readdirplus`, `fsyncdir`, `releasedir`). If the file system does not return a988/// `Handle` then the kernel will use the `Inode` for the directory to operate on its contents.989/// In this case the file system may wish to enable the `FsOptions::ZERO_MESSAGE_OPENDIR`990/// feature if it is supported by the kernel (see below).991///992/// The returned `OpenOptions` allow the file system to change the way the opened directory is993/// handled by the kernel. See the documentation of `OpenOptions` for more information.994///995/// If the `FsOptions::ZERO_MESSAGE_OPENDIR` feature is enabled by both the file system996/// implementation and the kernel, then the file system may return an error of `ENOSYS`. This997/// will be interpreted by the kernel as success and future calls to `opendir` and `releasedir`998/// will be handled by the kernel without being passed on to the file system.999fn opendir(1000&self,1001ctx: Context,1002inode: Self::Inode,1003flags: u32,1004) -> io::Result<(Option<Self::Handle>, OpenOptions)> {1005// Matches the behavior of libfuse.1006Ok((None, OpenOptions::empty()))1007}10081009/// Read a directory.1010///1011/// `handle` is the `Handle` returned by the file system from the `opendir` method, if any. If1012/// the file system did not return a `Handle` from `opendir` then the contents of `handle` are1013/// undefined.1014///1015/// `size` indicates the maximum number of bytes that should be returned by this method.1016///1017/// If `offset` is non-zero then it corresponds to one of the `offset` values from a `DirEntry`1018/// that was previously returned by a call to `readdir` for the same handle. In this case the1019/// file system should skip over the entries before the position defined by the `offset` value.1020/// If entries were added or removed while the `Handle` is open then the file system may still1021/// include removed entries or skip newly created entries. However, adding or removing entries1022/// should never cause the file system to skip over unrelated entries or include an entry more1023/// than once. This means that `offset` cannot be a simple index and must include sufficient1024/// information to uniquely determine the next entry in the list even when the set of entries is1025/// being changed.1026///1027/// The file system may return entries for the current directory (".") and parent directory1028/// ("..") but is not required to do so. If the file system does not return these entries, then1029/// they are implicitly added by the kernel.1030///1031/// The lookup count for `Inode`s associated with the returned directory entries is **NOT**1032/// affected by this method.1033fn readdir(1034&self,1035ctx: Context,1036inode: Self::Inode,1037handle: Self::Handle,1038size: u32,1039offset: u64,1040) -> io::Result<Self::DirIter> {1041Err(io::Error::from_raw_os_error(libc::ENOSYS))1042}10431044/// Synchronize the contents of a directory.1045///1046/// File systems must ensure that the directory contents have been flushed to disk before1047/// returning from this method. If `datasync` is true then only the directory data (but not the1048/// metadata) needs to be flushed.1049///1050/// `handle` is the `Handle` returned by the file system from the `opendir` method, if any. If1051/// the file system did not return a `Handle` from `opendir` then the contents of1052/// `handle` are undefined.1053///1054/// If this method returns an `ENOSYS` error then the kernel will treat it as success and all1055/// subsequent calls to `fsyncdir` will be handled by the kernel without being forwarded to the1056/// file system.1057fn fsyncdir(1058&self,1059ctx: Context,1060inode: Self::Inode,1061datasync: bool,1062handle: Self::Handle,1063) -> io::Result<()> {1064Err(io::Error::from_raw_os_error(libc::ENOSYS))1065}10661067/// Release an open directory.1068///1069/// For every `opendir` call there will be exactly one `releasedir` call (unless the file system1070/// is force-unmounted).1071///1072/// `handle` is the `Handle` returned by the file system from the `opendir` method, if any. If1073/// the file system did not return a `Handle` from `opendir` then the contents of `handle` are1074/// undefined.1075///1076/// `flags` contains used the flags used to open the directory in `opendir`.1077fn releasedir(1078&self,1079ctx: Context,1080inode: Self::Inode,1081flags: u32,1082handle: Self::Handle,1083) -> io::Result<()> {1084Err(io::Error::from_raw_os_error(libc::ENOSYS))1085}10861087/// Check file access permissions.1088///1089/// This method is called when a userspace process in the client makes an `access()` or1090/// `chdir()` system call. If the file system was mounted with the `-o default_permissions`1091/// mount option, then the kernel will perform these checks itself and this method will not be1092/// called.1093///1094/// If this method returns an `ENOSYS` error, then the kernel will treat it as a permanent1095/// success: all future calls to `access` will return success without being forwarded to the1096/// file system.1097fn access(&self, ctx: Context, inode: Self::Inode, mask: u32) -> io::Result<()> {1098Err(io::Error::from_raw_os_error(libc::ENOSYS))1099}11001101/// Perform an ioctl on a file or directory.1102///1103/// `handle` is the `Handle` returned by the file system from the `open` or `opendir` methods,1104/// if any. If the file system did not return a `Handle` from then the contents of `handle` are1105/// undefined.1106///1107/// If `flags` contains `IoctlFlags::UNRESTRICTED` then the file system may retry the ioctl1108/// after informing the kernel about the input and output areas. If `flags` does not contain1109/// `IoctlFlags::UNRESTRICTED` then the kernel will prepare the input and output areas according1110/// to the encoding in the ioctl command. In that case the ioctl cannot be retried.1111///1112/// `cmd` is the ioctl request made by the calling process, truncated to 32 bits.1113///1114/// `arg` is the argument provided by the calling process.1115///1116/// `in_size` is the length of the additional data that accompanies the request. The file system1117/// may fetch this data from `reader`.1118///1119/// `out_size` is the length of the output area prepared by the kernel to hold the response to1120/// the ioctl.1121fn ioctl<R: io::Read>(1122&self,1123ctx: Context,1124inode: Self::Inode,1125handle: Self::Handle,1126flags: IoctlFlags,1127cmd: u32,1128arg: u64,1129in_size: u32,1130out_size: u32,1131reader: R,1132) -> io::Result<IoctlReply> {1133Err(io::Error::from_raw_os_error(libc::ENOSYS))1134}11351136/// TODO: support this1137fn getlk(&self) -> io::Result<()> {1138Err(io::Error::from_raw_os_error(libc::ENOSYS))1139}11401141/// TODO: support this1142fn setlk(&self) -> io::Result<()> {1143Err(io::Error::from_raw_os_error(libc::ENOSYS))1144}11451146/// TODO: support this1147fn setlkw(&self) -> io::Result<()> {1148Err(io::Error::from_raw_os_error(libc::ENOSYS))1149}11501151/// TODO: support this1152fn bmap(&self) -> io::Result<()> {1153Err(io::Error::from_raw_os_error(libc::ENOSYS))1154}11551156/// TODO: support this1157fn poll(&self) -> io::Result<()> {1158Err(io::Error::from_raw_os_error(libc::ENOSYS))1159}11601161/// TODO: support this1162fn notify_reply(&self) -> io::Result<()> {1163Err(io::Error::from_raw_os_error(libc::ENOSYS))1164}11651166/// TODO: support this1167fn lseek(&self) -> io::Result<()> {1168Err(io::Error::from_raw_os_error(libc::ENOSYS))1169}11701171/// Copy a range of data from one file to another1172///1173/// Performs an optimized copy between two file descriptors without the additional cost of1174/// transferring data through the kernel module to user space (glibc) and then back into1175/// the file system again.1176///1177/// In case this method is not implemented, glibc falls back to reading data from the source and1178/// writing to the destination.1179///1180/// If this method fails with an `ENOSYS` error, then the kernel will treat that as a permanent1181/// failure. The kernel will return `EOPNOTSUPP` for all future calls to `copy_file_range`1182/// without forwarding them to the file system.1183///1184/// All values accepted by the `copy_file_range(2)` system call are valid values for `flags` and1185/// must be handled by the file system.1186fn copy_file_range(1187&self,1188ctx: Context,1189inode_src: Self::Inode,1190handle_src: Self::Handle,1191offset_src: u64,1192inode_dst: Self::Inode,1193handle_dst: Self::Handle,1194offset_dst: u64,1195length: u64,1196flags: u64,1197) -> io::Result<usize> {1198Err(io::Error::from_raw_os_error(libc::ENOSYS))1199}12001201/// Set up memory mappings.1202///1203/// Used to set up file mappings in DAX window.1204///1205/// # Arguments1206///1207/// * `file_offset` - Offset into the file to start the mapping.1208/// * `mem_offset` - Offset in Memory Window.1209/// * `size` - Length of mapping required.1210/// * `flags` - Bit field of `FUSE_SETUPMAPPING_FLAGS_*`.1211/// * `mapper` - Mapper object which performs the mapping.1212fn set_up_mapping<M: Mapper>(1213&self,1214ctx: Context,1215inode: Self::Inode,1216handle: Self::Handle,1217file_offset: u64,1218mem_offset: u64,1219size: usize,1220flags: u32,1221mapper: M,1222) -> io::Result<()> {1223Err(io::Error::from_raw_os_error(libc::ENOSYS))1224}12251226/// Remove memory mappings.1227///1228/// Used to tear down file mappings in DAX window. This method must be supported when1229/// `set_up_mapping` is supported.1230fn remove_mapping<M: Mapper>(&self, msgs: &[RemoveMappingOne], mapper: M) -> io::Result<()> {1231Err(io::Error::from_raw_os_error(libc::ENOSYS))1232}12331234/// Lookup and open/create the file1235///1236/// In this call, program first do a lookup on the file. Then depending upon1237/// flags combination, either do create + open, open only or return error.1238/// In all successful cases, it will return the dentry. For return value's1239/// handle and open options atomic_open should apply same rules to handle1240/// flags and configuration in open/create system call.1241///1242/// This function is called when the client supports FUSE_OPEN_ATOMIC.1243/// Implementing atomic_open is optional. When the it's not implemented,1244/// the client fall back to send lookup and open requests separately.1245///1246/// # Specification1247///1248/// If file was indeed newly created (as a result of O_CREAT), then set1249/// `FOPEN_FILE_CREATED` bit in `struct OpenOptions open`. This bit is used by1250/// crosvm to inform the fuse client to set `FILE_CREATED` bit in `struct1251/// fuse_file_info'.1252///1253/// All flags applied to open/create should be handled samely in atomic open,1254/// only the following are exceptions:1255/// * The O_NOCTTY is filtered out by fuse client.1256/// * O_TRUNC is filtered out by VFS for O_CREAT, O_EXCL combination.1257///1258/// # Implementation1259///1260/// To implement this API, you need to handle the following cases:1261///1262/// a) File does not exist1263/// - O_CREAT:1264/// - Create file with specified mode1265/// - Set `FOPEN_FILE_CREATED` bit in `struct OpenOptions open`1266/// - Open the file1267/// - Return d_entry and file handler1268/// - ~O_CREAT:1269/// - ENOENT1270///1271/// b) File exist already (exception is O_EXCL)1272/// - O_CREAT:1273/// - Open the file1274/// - Return d_entry and file handler1275/// - O_EXCL:1276/// - EEXIST1277///1278/// c) File is symbol link1279/// - Return dentry and file handler1280fn atomic_open(1281&self,1282ctx: Context,1283parent: Self::Inode,1284name: &CStr,1285mode: u32,1286flags: u32,1287umask: u32,1288security_ctx: Option<&CStr>,1289) -> io::Result<(Entry, Option<Self::Handle>, OpenOptions)> {1290Err(io::Error::from_raw_os_error(libc::ENOSYS))1291}1292}129312941295