xref: /aosp_15_r20/external/crosvm/fuse/src/lib.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
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 
9 use std::ffi::FromBytesWithNulError;
10 use std::fs::File;
11 use std::io;
12 
13 use remain::sorted;
14 use thiserror::Error as ThisError;
15 
16 pub mod filesystem;
17 pub mod fuzzing;
18 pub mod mount;
19 mod server;
20 #[allow(dead_code)]
21 pub mod sys;
22 pub mod worker;
23 
24 use filesystem::FileSystem;
25 pub use mount::mount;
26 pub use server::Mapper;
27 pub use server::Reader;
28 pub use server::Server;
29 pub use server::Writer;
30 
31 /// Errors that may occur during the creation or operation of an Fs device.
32 #[sorted]
33 #[derive(ThisError, Debug)]
34 pub 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 
75 pub type Result<T> = ::std::result::Result<T, Error>;
76 
77 #[derive(Default)]
78 pub 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 
85 impl FuseConfig {
new() -> Self86     pub fn new() -> Self {
87         FuseConfig {
88             ..Default::default()
89         }
90     }
91 
92     /// Set the FUSE device.
dev_fuse(&mut self, file: File) -> &mut Self93     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)`.
max_read(&mut self, bytes: u32) -> &mut Self100     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.
max_write(&mut self, bytes: u32) -> &mut Self106     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`.
num_threads(&mut self, num: usize) -> &mut Self112     pub fn num_threads(&mut self, num: usize) -> &mut Self {
113         self.num_of_threads = Some(num);
114         self
115     }
116 
enter_message_loop<F: FileSystem + Sync + Send>(self, fs: F) -> Result<()>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 }
143