// Copyright 2020 The ChromiumOS Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. //! FUSE (Filesystem in Userspace) server and filesystem mounting support. #![cfg(any(target_os = "android", target_os = "linux"))] use std::ffi::FromBytesWithNulError; use std::fs::File; use std::io; use remain::sorted; use thiserror::Error as ThisError; pub mod filesystem; pub mod fuzzing; pub mod mount; mod server; #[allow(dead_code)] pub mod sys; pub mod worker; use filesystem::FileSystem; pub use mount::mount; pub use server::Mapper; pub use server::Reader; pub use server::Server; pub use server::Writer; /// Errors that may occur during the creation or operation of an Fs device. #[sorted] #[derive(ThisError, Debug)] pub enum Error { /// A request is missing readable descriptors. /// Failed to decode protocol messages. #[error("failed to decode fuse message: {0}")] DecodeMessage(io::Error), /// Failed to encode protocol messages. #[error("failed to encode fuse message: {0}")] EncodeMessage(io::Error), /// Failed to set up FUSE endpoint to talk with. #[error("failed to set up FUSE endpoint to talk with: {0}")] EndpointSetup(io::Error), /// Failed to flush protocol messages. #[error("failed to flush fuse message: {0}")] FlushMessage(io::Error), /// A C string parameter is invalid. #[error("a c string parameter is invalid: {0}")] InvalidCString(FromBytesWithNulError), /// The `len` field of the header is too small. #[error("the `len` field of the header is too small")] InvalidHeaderLength, /// The `size` field of the `SetxattrIn` message does not match the length /// of the decoded value. #[error( "The `size` field of the `SetxattrIn` message does not match the\ length of the decoded value: size = {0}, value.len() = {1}" )] InvalidXattrSize(u32, usize), /// One or more parameters are missing. #[error("one or more parameters are missing")] MissingParameter, /// Thread exited #[error("Thread exited")] ThreadExited, /// Requested too many `iovec`s for an `ioctl` retry. #[error( "requested too many `iovec`s for an `ioctl` retry reply: requested\ {0}, max: {1}" )] TooManyIovecs(usize, usize), } pub type Result = ::std::result::Result; #[derive(Default)] pub struct FuseConfig { dev_fuse_file: Option, max_write_bytes: Option, max_read_bytes: Option, num_of_threads: Option, } impl FuseConfig { pub fn new() -> Self { FuseConfig { ..Default::default() } } /// Set the FUSE device. pub fn dev_fuse(&mut self, file: File) -> &mut Self { self.dev_fuse_file = Some(file); self } /// Set the maximum data in a read request. Must be large enough (usually equal) to `n` in /// `MountOption::MaxRead(n)`. pub fn max_read(&mut self, bytes: u32) -> &mut Self { self.max_read_bytes = Some(bytes); self } /// Set the maximum data in a write request. pub fn max_write(&mut self, bytes: u32) -> &mut Self { self.max_write_bytes = Some(bytes); self } /// Set the number of threads to run the `FileSystem`. pub fn num_threads(&mut self, num: usize) -> &mut Self { self.num_of_threads = Some(num); self } pub fn enter_message_loop(self, fs: F) -> Result<()> { let FuseConfig { dev_fuse_file, max_write_bytes, max_read_bytes, num_of_threads, } = self; let num = num_of_threads.unwrap_or(1); if num == 1 { worker::start_message_loop( dev_fuse_file.ok_or(Error::MissingParameter)?, max_read_bytes.ok_or(Error::MissingParameter)?, max_write_bytes.ok_or(Error::MissingParameter)?, fs, ) } else { worker::internal::start_message_loop_mt( dev_fuse_file.ok_or(Error::MissingParameter)?, max_read_bytes.ok_or(Error::MissingParameter)?, max_write_bytes.ok_or(Error::MissingParameter)?, num, fs, ) } } }