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