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