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