fuse/
lib.rs

1// Copyright 2020 The ChromiumOS Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! FUSE (Filesystem in Userspace) server and filesystem mounting support.
6
7#![cfg(any(target_os = "android", target_os = "linux"))]
8
9use std::ffi::FromBytesWithNulError;
10use std::fs::File;
11use std::io;
12
13use remain::sorted;
14use thiserror::Error as ThisError;
15
16pub mod filesystem;
17pub mod fuzzing;
18pub mod mount;
19mod server;
20#[allow(dead_code)]
21pub mod sys;
22pub mod worker;
23
24use filesystem::FileSystem;
25pub use mount::mount;
26pub use server::Mapper;
27pub use server::Reader;
28pub use server::Server;
29pub use server::Writer;
30
31/// Errors that may occur during the creation or operation of an Fs device.
32#[sorted]
33#[derive(ThisError, Debug)]
34pub enum Error {
35    /// A request is missing readable descriptors.
36    /// Failed to decode protocol messages.
37    #[error("failed to decode fuse message: {0}")]
38    DecodeMessage(io::Error),
39    /// Failed to encode protocol messages.
40    #[error("failed to encode fuse message: {0}")]
41    EncodeMessage(io::Error),
42    /// Failed to set up FUSE endpoint to talk with.
43    #[error("failed to set up FUSE endpoint to talk with: {0}")]
44    EndpointSetup(io::Error),
45    /// Failed to flush protocol messages.
46    #[error("failed to flush fuse message: {0}")]
47    FlushMessage(io::Error),
48    /// A C string parameter is invalid.
49    #[error("a c string parameter is invalid: {0}")]
50    InvalidCString(FromBytesWithNulError),
51    /// The `len` field of the header is too small.
52    #[error("the `len` field of the header is too small")]
53    InvalidHeaderLength,
54    /// The `size` field of the `SetxattrIn` message does not match the length
55    /// of the decoded value.
56    #[error(
57        "The `size` field of the `SetxattrIn` message does not match the\
58             length of the decoded value: size = {0}, value.len() = {1}"
59    )]
60    InvalidXattrSize(u32, usize),
61    /// One or more parameters are missing.
62    #[error("one or more parameters are missing")]
63    MissingParameter,
64    /// Thread exited
65    #[error("Thread exited")]
66    ThreadExited,
67    /// Requested too many `iovec`s for an `ioctl` retry.
68    #[error(
69        "requested too many `iovec`s for an `ioctl` retry reply: requested\
70            {0}, max: {1}"
71    )]
72    TooManyIovecs(usize, usize),
73}
74
75pub type Result<T> = ::std::result::Result<T, Error>;
76
77#[derive(Default)]
78pub struct FuseConfig {
79    dev_fuse_file: Option<File>,
80    max_write_bytes: Option<u32>,
81    max_read_bytes: Option<u32>,
82    num_of_threads: Option<usize>,
83}
84
85impl FuseConfig {
86    pub fn new() -> Self {
87        FuseConfig {
88            ..Default::default()
89        }
90    }
91
92    /// Set the FUSE device.
93    pub fn dev_fuse(&mut self, file: File) -> &mut Self {
94        self.dev_fuse_file = Some(file);
95        self
96    }
97
98    /// Set the maximum data in a read request. Must be large enough (usually equal) to `n` in
99    /// `MountOption::MaxRead(n)`.
100    pub fn max_read(&mut self, bytes: u32) -> &mut Self {
101        self.max_read_bytes = Some(bytes);
102        self
103    }
104
105    /// Set the maximum data in a write request.
106    pub fn max_write(&mut self, bytes: u32) -> &mut Self {
107        self.max_write_bytes = Some(bytes);
108        self
109    }
110
111    /// Set the number of threads to run the `FileSystem`.
112    pub fn num_threads(&mut self, num: usize) -> &mut Self {
113        self.num_of_threads = Some(num);
114        self
115    }
116
117    pub fn enter_message_loop<F: FileSystem + Sync + Send>(self, fs: F) -> Result<()> {
118        let FuseConfig {
119            dev_fuse_file,
120            max_write_bytes,
121            max_read_bytes,
122            num_of_threads,
123        } = self;
124        let num = num_of_threads.unwrap_or(1);
125        if num == 1 {
126            worker::start_message_loop(
127                dev_fuse_file.ok_or(Error::MissingParameter)?,
128                max_read_bytes.ok_or(Error::MissingParameter)?,
129                max_write_bytes.ok_or(Error::MissingParameter)?,
130                fs,
131            )
132        } else {
133            worker::internal::start_message_loop_mt(
134                dev_fuse_file.ok_or(Error::MissingParameter)?,
135                max_read_bytes.ok_or(Error::MissingParameter)?,
136                max_write_bytes.ok_or(Error::MissingParameter)?,
137                num,
138                fs,
139            )
140        }
141    }
142}