From dadef988c3324857b3e84b7fd8fc630162f71ba6 Mon Sep 17 00:00:00 2001 From: Jakob Truelsen Date: Fri, 27 Feb 2026 09:25:18 +0100 Subject: [PATCH 01/13] Use zerocopy instead of bincode --- Cargo.lock | 83 +++------ Cargo.toml | 2 +- src/helper.rs | 4 - src/notify.rs | 45 ++--- src/raw/abi.rs | 303 ++++++++++++++++++--------------- src/raw/session.rs | 415 ++++++++++++++++++--------------------------- 6 files changed, 380 insertions(+), 472 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3658dd5..c613aac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -179,26 +179,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "bincode-next" -version = "2.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a347d3b94606a7b3d588fe1ff7f41996bbb3690ade4e79935b26565af10e03f" -dependencies = [ - "bincode_derive-next", - "serde", - "unty-next", -] - -[[package]] -name = "bincode_derive-next" -version = "2.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "197e777c78cc9fbe8396cf82e18f84bb6026b8ec534ebb3097f4d98894e8b540" -dependencies = [ - "virtue-next", -] - [[package]] name = "bitflags" version = "2.10.0" @@ -340,7 +320,6 @@ dependencies = [ "async-lock", "async-notify", "async-process", - "bincode-next", "bytes", "futures-channel", "futures-util", @@ -351,6 +330,7 @@ dependencies = [ "tracing", "trait-make", "which", + "zerocopy", ] [[package]] @@ -656,35 +636,6 @@ dependencies = [ "windows-sys 0.60.2", ] -[[package]] -name = "serde" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" -dependencies = [ - "serde_core", -] - -[[package]] -name = "serde_core" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "sharded-slab" version = "0.1.7" @@ -863,24 +814,12 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" -[[package]] -name = "unty-next" -version = "0.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "169ea32c8f5801e4b397f08d2b5d3d0d3675d11c241aad7338b601beed52a291" - [[package]] name = "valuable" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" -[[package]] -name = "virtue-next" -version = "0.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4daab4b8a8c3c1408ea5e60a5d380790ff15d0cfe0333c14ce98210c1339fd8" - [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" @@ -1136,3 +1075,23 @@ name = "windows_x86_64_msvc" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + +[[package]] +name = "zerocopy" +version = "0.8.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a789c6e490b576db9f7e6b6d661bcc9799f7c0ac8352f56ea20193b2681532e5" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f65c489a7071a749c849713807783f70672b28094011623e200cb86dcb835953" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/Cargo.toml b/Cargo.toml index 0c33f34..59a6af0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,7 +29,6 @@ async-lock = { version = "3.3.0", optional = true } async-notify = "0.3" async-io = { version = "2.3.1", optional = true } async-process = { version = "2.1.0", optional = true } -bincode-next = { version = "2.0.4", default-features = false, features = ["derive", "std"] } bytes = "1.5" futures-channel = { version = "0.3.30", features = ["sink"] } futures-util = { version = "0.3.30", features = ["sink"] } @@ -39,6 +38,7 @@ slab = "0.4.9" tracing = "0.1.40" trait-make = "0.1" which = { version = "6", optional = true } +zerocopy = {version = "0.8.10", features = ["derive", "std"]} [dependencies.tokio] version = "1.45" diff --git a/src/helper.rs b/src/helper.rs index f7a344d..a737ab4 100644 --- a/src/helper.rs +++ b/src/helper.rs @@ -55,7 +55,3 @@ pub const fn get_padding_size(dir_entry_size: usize) -> usize { entry_size - dir_entry_size } - -pub fn get_bincode_config() -> impl bincode_next::config::Config { - bincode_next::config::legacy() -} diff --git a/src/notify.rs b/src/notify.rs index 54ee4dd..284967d 100644 --- a/src/notify.rs +++ b/src/notify.rs @@ -3,13 +3,12 @@ use std::ffi::OsString; use std::os::unix::ffi::OsStrExt; -use bincode_next::encode_into_std_write; use bytes::{Buf, Bytes}; use futures_channel::mpsc::UnboundedSender; use futures_util::future::Either; use futures_util::sink::SinkExt; +use zerocopy::IntoBytes; -use crate::helper::get_bincode_config; use crate::raw::abi::{ fuse_notify_code, fuse_notify_delete_out, fuse_notify_inval_entry_out, fuse_notify_inval_inode_out, fuse_notify_poll_wakeup_out, fuse_notify_retrieve_out, @@ -47,10 +46,11 @@ impl Notify { let mut data = Vec::with_capacity(FUSE_OUT_HEADER_SIZE + FUSE_NOTIFY_POLL_WAKEUP_OUT_SIZE); - let config = get_bincode_config(); - encode_into_std_write(&out_header, &mut data, config) + out_header + .write_to_io(&mut data) .expect("vec size is not enough"); - encode_into_std_write(&wakeup_out, &mut data, config) + wakeup_out + .write_to_io(&mut data) .expect("vec size is not enough"); Either::Left(data) @@ -72,10 +72,11 @@ impl Notify { let mut data = Vec::with_capacity(FUSE_OUT_HEADER_SIZE + FUSE_NOTIFY_INVAL_INODE_OUT_SIZE); - let config = get_bincode_config(); - encode_into_std_write(&out_header, &mut data, config) + out_header + .write_to_io(&mut data) .expect("vec size is not enough"); - encode_into_std_write(&invalid_inode_out, &mut data, config) + invalid_inode_out + .write_to_io(&mut data) .expect("vec size is not enough"); Either::Left(data) @@ -97,10 +98,11 @@ impl Notify { let mut data = Vec::with_capacity(FUSE_OUT_HEADER_SIZE + FUSE_NOTIFY_INVAL_ENTRY_OUT_SIZE); - let config = get_bincode_config(); - encode_into_std_write(&out_header, &mut data, config) + out_header + .write_to_io(&mut data) .expect("vec size is not enough"); - encode_into_std_write(&invalid_entry_out, &mut data, config) + invalid_entry_out + .write_to_io(&mut data) .expect("vec size is not enough"); // TODO should I add null at the end? @@ -129,10 +131,11 @@ impl Notify { let mut data = Vec::with_capacity(FUSE_OUT_HEADER_SIZE + FUSE_NOTIFY_DELETE_OUT_SIZE); - let config = get_bincode_config(); - encode_into_std_write(&out_header, &mut data, config) + out_header + .write_to_io(&mut data) .expect("vec size is not enough"); - encode_into_std_write(&delete_out, &mut data, config) + delete_out + .write_to_io(&mut data) .expect("vec size is not enough"); // TODO should I add null at the end? @@ -161,10 +164,11 @@ impl Notify { let mut data_buf = Vec::with_capacity(FUSE_OUT_HEADER_SIZE + FUSE_NOTIFY_STORE_OUT_SIZE); - let config = get_bincode_config(); - encode_into_std_write(&out_header, &mut data_buf, config) + out_header + .write_to_io(&mut data_buf) .expect("vec size is not enough"); - encode_into_std_write(&store_out, &mut data_buf, config) + store_out + .write_to_io(&mut data_buf) .expect("vec size is not enough"); Either::Right((data_buf, data.clone())) @@ -193,10 +197,11 @@ impl Notify { let mut data = Vec::with_capacity(FUSE_OUT_HEADER_SIZE + FUSE_NOTIFY_RETRIEVE_OUT_SIZE); - let config = get_bincode_config(); - encode_into_std_write(&out_header, &mut data, config) + out_header + .write_to_io(&mut data) .expect("vec size is not enough"); - encode_into_std_write(&retrieve_out, &mut data, config) + retrieve_out + .write_to_io(&mut data) .expect("vec size is not enough"); Either::Left(data) diff --git a/src/raw/abi.rs b/src/raw/abi.rs index fa3d486..1bf4bc8 100644 --- a/src/raw/abi.rs +++ b/src/raw/abi.rs @@ -22,7 +22,7 @@ use std::error::Error; use std::fmt::{self, Debug, Display, Formatter}; use std::mem; -use bincode_next::{Decode, Encode}; +use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout}; /// The min size of read buffer. In Linux kernel the `FUSE_MIN_READ_BUFFER` is /// @@ -231,8 +231,9 @@ pub const FUSE_IOCTL_MAX_IOV: u32 = 256; /// request poll notify pub const FUSE_POLL_SCHEDULE_NOTIFY: u32 = 1 << 0; -#[derive(Debug, Encode)] -#[allow(non_camel_case_types)] +#[derive(Debug, IntoBytes, Immutable)] +#[allow(non_camel_case_types, unused)] +#[repr(C)] pub struct fuse_attr { pub ino: u64, pub size: u64, @@ -259,8 +260,9 @@ pub struct fuse_attr { pub(crate) _padding: u32, } -#[derive(Debug, Encode)] -#[allow(non_camel_case_types)] +#[derive(Debug, IntoBytes, Immutable)] +#[allow(non_camel_case_types, unused)] +#[repr(C)] pub struct fuse_kstatfs { // Total blocks (in units of frsize) pub blocks: u64, @@ -282,8 +284,9 @@ pub struct fuse_kstatfs { pub spare: [u32; 6], } -#[derive(Debug, Decode, Encode)] -#[allow(non_camel_case_types)] +#[derive(Debug, FromBytes, KnownLayout, IntoBytes, Immutable)] +#[allow(non_camel_case_types, unused)] +#[repr(C)] pub struct fuse_file_lock { pub start: u64, pub end: u64, @@ -491,8 +494,9 @@ impl TryFrom for fuse_notify_code { pub const FUSE_ENTRY_OUT_SIZE: usize = mem::size_of::(); -#[derive(Debug, Encode)] -#[allow(non_camel_case_types)] +#[derive(Debug, IntoBytes, Immutable)] +#[allow(non_camel_case_types, unused)] +#[repr(C)] pub struct fuse_entry_out { pub nodeid: u64, pub generation: u64, @@ -503,32 +507,34 @@ pub struct fuse_entry_out { pub attr: fuse_attr, } -#[derive(Debug, Decode)] -#[allow(non_camel_case_types)] +#[derive(Debug, FromBytes, KnownLayout, Immutable)] +#[allow(non_camel_case_types, unused)] +#[repr(C)] pub struct fuse_forget_in { pub nlookup: u64, } pub const FUSE_FORGET_ONE_SIZE: usize = mem::size_of::(); -#[derive(Debug, Decode)] -#[allow(non_camel_case_types)] +#[derive(Debug, FromBytes, KnownLayout, Immutable)] +#[allow(non_camel_case_types, unused)] +#[repr(C)] pub struct fuse_forget_one { pub nodeid: u64, pub(crate) _nlookup: u64, } -pub const FUSE_BATCH_FORGET_IN_SIZE: usize = mem::size_of::(); - -#[derive(Debug, Decode)] -#[allow(non_camel_case_types)] +#[derive(Debug, FromBytes, KnownLayout, Immutable)] +#[allow(non_camel_case_types, unused)] +#[repr(C)] pub struct fuse_batch_forget_in { pub count: u32, pub(crate) _dummy: u32, } -#[derive(Debug, Decode)] -#[allow(non_camel_case_types)] +#[derive(Debug, FromBytes, KnownLayout, Immutable)] +#[allow(non_camel_case_types, unused)] +#[repr(C)] pub struct fuse_getattr_in { pub getattr_flags: u32, pub dummy: u32, @@ -537,8 +543,9 @@ pub struct fuse_getattr_in { pub const FUSE_ATTR_OUT_SIZE: usize = mem::size_of::(); -#[derive(Debug, Encode)] -#[allow(non_camel_case_types)] +#[derive(Debug, IntoBytes, Immutable)] +#[allow(non_camel_case_types, unused)] +#[repr(C)] pub struct fuse_attr_out { pub attr_valid: u64, pub attr_valid_nsec: u32, @@ -548,7 +555,8 @@ pub struct fuse_attr_out { #[cfg(target_os = "macos")] #[derive(Debug)] -#[allow(non_camel_case_types)] +#[allow(non_camel_case_types, unused)] +#[repr(C)] pub struct fuse_getxtimes_out { pub bkuptime: u64, pub crtime: u64, @@ -556,10 +564,9 @@ pub struct fuse_getxtimes_out { pub crtimensec: u32, } -pub const FUSE_MKNOD_IN_SIZE: usize = mem::size_of::(); - -#[derive(Debug, Decode)] -#[allow(non_camel_case_types)] +#[derive(Debug, FromBytes, KnownLayout, Immutable)] +#[allow(non_camel_case_types, unused)] +#[repr(C)] pub struct fuse_mknod_in { pub mode: u32, pub rdev: u32, @@ -567,19 +574,17 @@ pub struct fuse_mknod_in { _padding: u32, } -pub const FUSE_MKDIR_IN_SIZE: usize = mem::size_of::(); - -#[derive(Debug, Decode)] -#[allow(non_camel_case_types)] +#[derive(Debug, FromBytes, KnownLayout, Immutable)] +#[allow(non_camel_case_types, unused)] +#[repr(C)] pub struct fuse_mkdir_in { pub mode: u32, pub umask: u32, } -pub const FUSE_RENAME_IN_SIZE: usize = mem::size_of::(); - -#[derive(Debug, Decode)] -#[allow(non_camel_case_types)] +#[derive(Debug, FromBytes, KnownLayout, Immutable)] +#[allow(non_camel_case_types, unused)] +#[repr(C)] pub struct fuse_rename_in { pub newdir: u64, // https://github.com/osxfuse/fuse/blob/master/include/fuse_kernel.h#L448 @@ -589,10 +594,9 @@ pub struct fuse_rename_in { _padding: u32, } -pub const FUSE_RENAME2_IN_SIZE: usize = mem::size_of::(); - -#[derive(Debug, Decode)] -#[allow(non_camel_case_types)] +#[derive(Debug, FromBytes, KnownLayout, Immutable)] +#[allow(non_camel_case_types, unused)] +#[repr(C)] pub struct fuse_rename2_in { pub newdir: u64, pub flags: u32, @@ -601,23 +605,24 @@ pub struct fuse_rename2_in { #[cfg(target_os = "macos")] #[derive(Debug)] -#[allow(non_camel_case_types)] +#[allow(non_camel_case_types, unused)] +#[repr(C)] pub struct fuse_exchange_in { pub olddir: u64, pub newdir: u64, pub options: u64, } -pub const FUSE_LINK_IN_SIZE: usize = mem::size_of::(); - -#[derive(Debug, Decode)] -#[allow(non_camel_case_types)] +#[derive(Debug, FromBytes, KnownLayout, Immutable)] +#[allow(non_camel_case_types, unused)] +#[repr(C)] pub struct fuse_link_in { pub oldnodeid: u64, } -#[derive(Debug, Decode)] -#[allow(non_camel_case_types)] +#[derive(Debug, FromBytes, KnownLayout, Immutable)] +#[allow(non_camel_case_types, unused)] +#[repr(C)] pub struct fuse_setattr_in { pub valid: u32, _padding: u32, @@ -651,17 +656,17 @@ pub struct fuse_setattr_in { pub flags: u32, // see chflags(2) } -#[derive(Debug, Decode)] -#[allow(non_camel_case_types)] +#[derive(Debug, FromBytes, KnownLayout, Immutable)] +#[allow(non_camel_case_types, unused)] +#[repr(C)] pub struct fuse_open_in { pub flags: u32, pub(crate) _unused: u32, } -pub const FUSE_CREATE_IN_SIZE: usize = mem::size_of::(); - -#[derive(Debug, Decode)] -#[allow(non_camel_case_types)] +#[derive(Debug, FromBytes, KnownLayout, Immutable)] +#[allow(non_camel_case_types, unused)] +#[repr(C)] pub struct fuse_create_in { pub flags: u32, pub mode: u32, @@ -671,16 +676,18 @@ pub struct fuse_create_in { pub const FUSE_OPEN_OUT_SIZE: usize = mem::size_of::(); -#[derive(Debug, Encode)] -#[allow(non_camel_case_types)] +#[derive(Debug, IntoBytes, Immutable)] +#[allow(non_camel_case_types, unused)] +#[repr(C)] pub struct fuse_open_out { pub fh: u64, pub open_flags: u32, pub(crate) _padding: u32, } -#[derive(Debug, Decode)] -#[allow(non_camel_case_types)] +#[derive(Debug, FromBytes, KnownLayout, Immutable)] +#[allow(non_camel_case_types, unused)] +#[repr(C)] pub struct fuse_release_in { pub fh: u64, pub flags: u32, @@ -688,8 +695,9 @@ pub struct fuse_release_in { pub lock_owner: u64, } -#[derive(Debug, Decode)] -#[allow(non_camel_case_types)] +#[derive(Debug, FromBytes, KnownLayout, Immutable)] +#[allow(non_camel_case_types, unused)] +#[repr(C)] pub struct fuse_flush_in { pub fh: u64, pub(crate) _unused: u32, @@ -697,8 +705,9 @@ pub struct fuse_flush_in { pub lock_owner: u64, } -#[derive(Debug, Decode)] -#[allow(non_camel_case_types)] +#[derive(Debug, FromBytes, KnownLayout, Immutable)] +#[allow(non_camel_case_types, unused)] +#[repr(C)] pub struct fuse_read_in { pub fh: u64, pub offset: u64, @@ -711,8 +720,9 @@ pub struct fuse_read_in { pub const FUSE_WRITE_IN_SIZE: usize = mem::size_of::(); -#[derive(Debug, Decode)] -#[allow(non_camel_case_types)] +#[derive(Debug, FromBytes, KnownLayout, Immutable)] +#[allow(non_camel_case_types, unused)] +#[repr(C)] pub struct fuse_write_in { pub fh: u64, pub offset: u64, @@ -725,8 +735,9 @@ pub struct fuse_write_in { pub const FUSE_WRITE_OUT_SIZE: usize = mem::size_of::(); -#[derive(Debug, Encode)] -#[allow(non_camel_case_types)] +#[derive(Debug, IntoBytes, Immutable)] +#[allow(non_camel_case_types, unused)] +#[repr(C)] pub struct fuse_write_out { pub size: u32, pub(crate) _padding: u32, @@ -734,24 +745,25 @@ pub struct fuse_write_out { pub const FUSE_STATFS_OUT_SIZE: usize = mem::size_of::(); -#[derive(Debug, Encode)] -#[allow(non_camel_case_types)] +#[derive(Debug, IntoBytes, Immutable)] +#[allow(non_camel_case_types, unused)] +#[repr(C)] pub struct fuse_statfs_out { pub st: fuse_kstatfs, } -#[derive(Debug, Decode)] -#[allow(non_camel_case_types)] +#[derive(Debug, FromBytes, KnownLayout, Immutable)] +#[allow(non_camel_case_types, unused)] +#[repr(C)] pub struct fuse_fsync_in { pub fh: u64, pub fsync_flags: u32, _padding: u32, } -pub const FUSE_SETXATTR_IN_SIZE: usize = mem::size_of::(); - -#[derive(Debug, Decode)] -#[allow(non_camel_case_types)] +#[derive(Debug, FromBytes, KnownLayout, Immutable)] +#[allow(non_camel_case_types, unused)] +#[repr(C)] pub struct fuse_setxattr_in { pub size: u32, pub flags: u32, @@ -761,10 +773,9 @@ pub struct fuse_setxattr_in { _padding: u32, } -pub const FUSE_GETXATTR_IN_SIZE: usize = mem::size_of::(); - -#[derive(Debug, Decode)] -#[allow(non_camel_case_types)] +#[derive(Debug, FromBytes, KnownLayout, Immutable)] +#[allow(non_camel_case_types, unused)] +#[repr(C)] pub struct fuse_getxattr_in { pub size: u32, _padding: u32, @@ -776,16 +787,18 @@ pub struct fuse_getxattr_in { pub const FUSE_GETXATTR_OUT_SIZE: usize = mem::size_of::(); -#[derive(Debug, Encode)] -#[allow(non_camel_case_types)] +#[derive(Debug, IntoBytes, Immutable)] +#[allow(non_camel_case_types, unused)] +#[repr(C)] pub struct fuse_getxattr_out { pub size: u32, pub(crate) _padding: u32, } #[cfg(feature = "file-lock")] -#[derive(Debug, Decode)] -#[allow(non_camel_case_types)] +#[derive(Debug, FromBytes, KnownLayout, Immutable)] +#[allow(non_camel_case_types, unused)] +#[repr(C)] pub struct fuse_lk_in { pub fh: u64, pub owner: u64, @@ -798,21 +811,24 @@ pub struct fuse_lk_in { pub const FUSE_LK_OUT_SIZE: usize = mem::size_of::(); #[cfg(feature = "file-lock")] -#[derive(Debug, Encode)] -#[allow(non_camel_case_types)] +#[derive(Debug, IntoBytes, Immutable)] +#[allow(non_camel_case_types, unused)] +#[repr(C)] pub struct fuse_lk_out { pub lk: fuse_file_lock, } -#[derive(Debug, Decode)] -#[allow(non_camel_case_types)] +#[derive(Debug, FromBytes, KnownLayout, Immutable)] +#[allow(non_camel_case_types, unused)] +#[repr(C)] pub struct fuse_access_in { pub mask: u32, _padding: u32, } -#[derive(Debug, Decode)] -#[allow(non_camel_case_types)] +#[derive(Debug, FromBytes, KnownLayout, Immutable)] +#[allow(non_camel_case_types, unused)] +#[repr(C)] pub struct fuse_init_in { pub(crate) _major: u32, pub(crate) _minor: u32, @@ -822,8 +838,9 @@ pub struct fuse_init_in { pub const FUSE_INIT_OUT_SIZE: usize = mem::size_of::(); -#[derive(Debug, Encode)] -#[allow(non_camel_case_types)] +#[derive(Debug, IntoBytes, Immutable)] +#[allow(non_camel_case_types, unused)] +#[repr(C)] pub struct fuse_init_out { pub major: u32, pub minor: u32, @@ -839,7 +856,7 @@ pub struct fuse_init_out { } /*#[derive(Debug)] -#[allow(non_camel_case_types)] +#[allow(non_camel_case_types, unused)] pub struct cuse_init_in { pub major: u32, pub minor: u32, @@ -848,7 +865,7 @@ pub struct cuse_init_in { }*/ /*#[derive(Debug)] -#[allow(non_camel_case_types)] +#[allow(non_camel_case_types, unused)] pub struct cuse_init_out { pub major: u32, pub minor: u32, @@ -863,14 +880,16 @@ pub struct cuse_init_out { pub spare: [u32; 10], }*/ -#[derive(Debug, Decode)] -#[allow(non_camel_case_types)] +#[derive(Debug, FromBytes, KnownLayout, Immutable)] +#[allow(non_camel_case_types, unused)] +#[repr(C)] pub struct fuse_interrupt_in { pub unique: u64, } -#[derive(Debug, Decode)] -#[allow(non_camel_case_types)] +#[derive(Debug, FromBytes, KnownLayout, Immutable)] +#[allow(non_camel_case_types, unused)] +#[repr(C)] pub struct fuse_bmap_in { pub block: u64, pub blocksize: u32, @@ -879,14 +898,15 @@ pub struct fuse_bmap_in { pub const FUSE_BMAP_OUT_SIZE: usize = mem::size_of::(); -#[derive(Debug, Encode)] -#[allow(non_camel_case_types)] +#[derive(Debug, IntoBytes, Immutable)] +#[allow(non_camel_case_types, unused)] +#[repr(C)] pub struct fuse_bmap_out { pub block: u64, } //#[derive(Debug, Decode)] -//#[allow(non_camel_case_types)] +//#[allow(non_camel_case_types, unused)] //pub struct fuse_ioctl_in { //pub fh: u64, //pub flags: u32, @@ -897,14 +917,14 @@ pub struct fuse_bmap_out { //} //#[derive(Debug)] -//#[allow(non_camel_case_types)] +//#[allow(non_camel_case_types, unused)] //pub struct fuse_ioctl_iovec { //pub base: u64, //pub len: u64, //} //#[derive(Debug)] -//#[allow(non_camel_case_types)] +//#[allow(non_camel_case_types, unused)] //pub struct fuse_ioctl_out { //pub result: i32, //pub flags: u32, @@ -912,8 +932,9 @@ pub struct fuse_bmap_out { //pub out_iovs: u32, //} -#[derive(Debug, Decode)] -#[allow(non_camel_case_types)] +#[derive(Debug, FromBytes, KnownLayout, Immutable)] +#[allow(non_camel_case_types, unused)] +#[repr(C)] pub struct fuse_poll_in { pub fh: u64, pub kh: u64, @@ -923,8 +944,9 @@ pub struct fuse_poll_in { pub const FUSE_POLL_OUT_SIZE: usize = mem::size_of::(); -#[derive(Debug, Encode)] -#[allow(non_camel_case_types)] +#[derive(Debug, IntoBytes, Immutable)] +#[allow(non_camel_case_types, unused)] +#[repr(C)] pub struct fuse_poll_out { pub revents: u32, pub(crate) _padding: u32, @@ -932,14 +954,16 @@ pub struct fuse_poll_out { pub const FUSE_NOTIFY_POLL_WAKEUP_OUT_SIZE: usize = mem::size_of::(); -#[derive(Debug, Encode)] -#[allow(non_camel_case_types)] +#[derive(Debug, IntoBytes, Immutable)] +#[allow(non_camel_case_types, unused)] +#[repr(C)] pub struct fuse_notify_poll_wakeup_out { pub kh: u64, } -#[derive(Debug, Decode)] -#[allow(non_camel_case_types)] +#[derive(Debug, FromBytes, KnownLayout, Immutable)] +#[allow(non_camel_case_types, unused)] +#[repr(C)] pub struct fuse_fallocate_in { pub fh: u64, pub offset: u64, @@ -950,8 +974,9 @@ pub struct fuse_fallocate_in { pub const FUSE_IN_HEADER_SIZE: usize = mem::size_of::(); -#[derive(Debug, Decode)] -#[allow(non_camel_case_types)] +#[derive(Debug, FromBytes, KnownLayout, Immutable)] +#[allow(non_camel_case_types, unused)] +#[repr(C)] pub struct fuse_in_header { pub len: u32, pub opcode: u32, @@ -965,8 +990,9 @@ pub struct fuse_in_header { pub const FUSE_OUT_HEADER_SIZE: usize = mem::size_of::(); -#[derive(Debug, Encode)] -#[allow(non_camel_case_types)] +#[derive(Debug, IntoBytes, Immutable)] +#[allow(non_camel_case_types, unused)] +#[repr(C)] pub struct fuse_out_header { pub len: u32, pub error: i32, @@ -975,8 +1001,9 @@ pub struct fuse_out_header { pub const FUSE_DIRENT_SIZE: usize = mem::size_of::(); -#[derive(Debug, Encode)] -#[allow(non_camel_case_types)] +#[derive(Debug, IntoBytes, Immutable)] +#[allow(non_camel_case_types, unused)] +#[repr(C)] pub struct fuse_dirent { pub ino: u64, pub off: u64, @@ -987,8 +1014,9 @@ pub struct fuse_dirent { pub const FUSE_DIRENTPLUS_SIZE: usize = mem::size_of::(); -#[derive(Debug, Encode)] -#[allow(non_camel_case_types)] +#[derive(Debug, IntoBytes, Immutable)] +#[allow(non_camel_case_types, unused)] +#[repr(C)] pub struct fuse_direntplus { pub entry_out: fuse_entry_out, pub dirent: fuse_dirent, @@ -996,8 +1024,9 @@ pub struct fuse_direntplus { pub const FUSE_NOTIFY_INVAL_INODE_OUT_SIZE: usize = mem::size_of::(); -#[derive(Debug, Encode)] -#[allow(non_camel_case_types)] +#[derive(Debug, IntoBytes, Immutable)] +#[allow(non_camel_case_types, unused)] +#[repr(C)] pub struct fuse_notify_inval_inode_out { pub ino: u64, pub off: i64, @@ -1006,8 +1035,9 @@ pub struct fuse_notify_inval_inode_out { pub const FUSE_NOTIFY_INVAL_ENTRY_OUT_SIZE: usize = mem::size_of::(); -#[derive(Debug, Encode)] -#[allow(non_camel_case_types)] +#[derive(Debug, IntoBytes, Immutable)] +#[allow(non_camel_case_types, unused)] +#[repr(C)] pub struct fuse_notify_inval_entry_out { pub parent: u64, pub namelen: u32, @@ -1016,8 +1046,9 @@ pub struct fuse_notify_inval_entry_out { pub const FUSE_NOTIFY_DELETE_OUT_SIZE: usize = mem::size_of::(); -#[derive(Debug, Encode)] -#[allow(non_camel_case_types)] +#[derive(Debug, IntoBytes, Immutable)] +#[allow(non_camel_case_types, unused)] +#[repr(C)] pub struct fuse_notify_delete_out { pub parent: u64, pub child: u64, @@ -1027,8 +1058,9 @@ pub struct fuse_notify_delete_out { pub const FUSE_NOTIFY_STORE_OUT_SIZE: usize = mem::size_of::(); -#[derive(Debug, Encode)] -#[allow(non_camel_case_types)] +#[derive(Debug, IntoBytes, Immutable)] +#[allow(non_camel_case_types, unused)] +#[repr(C)] pub struct fuse_notify_store_out { pub nodeid: u64, pub offset: u64, @@ -1038,8 +1070,9 @@ pub struct fuse_notify_store_out { pub const FUSE_NOTIFY_RETRIEVE_OUT_SIZE: usize = mem::size_of::(); -#[derive(Debug, Encode)] -#[allow(non_camel_case_types)] +#[derive(Debug, IntoBytes, Immutable)] +#[allow(non_camel_case_types, unused)] +#[repr(C)] pub struct fuse_notify_retrieve_out { pub notify_unique: u64, pub nodeid: u64, @@ -1048,11 +1081,10 @@ pub struct fuse_notify_retrieve_out { pub(crate) _padding: u32, } -pub const FUSE_NOTIFY_RETRIEVE_IN_SIZE: usize = mem::size_of::(); - -#[derive(Debug, Decode)] +#[derive(Debug, FromBytes, KnownLayout, Immutable)] // matches the size of fuse_write_in -#[allow(non_camel_case_types)] +#[allow(non_camel_case_types, unused)] +#[repr(C)] pub struct fuse_notify_retrieve_in { _dummy1: u64, pub offset: u64, @@ -1062,8 +1094,9 @@ pub struct fuse_notify_retrieve_in { _dummy4: u64, } -#[derive(Debug, Decode)] -#[allow(non_camel_case_types)] +#[derive(Debug, FromBytes, KnownLayout, Immutable)] +#[allow(non_camel_case_types, unused)] +#[repr(C)] pub struct fuse_lseek_in { pub fh: u64, pub offset: u64, @@ -1073,14 +1106,16 @@ pub struct fuse_lseek_in { pub const FUSE_LSEEK_OUT_SIZE: usize = mem::size_of::(); -#[derive(Debug, Encode)] -#[allow(non_camel_case_types)] +#[derive(Debug, IntoBytes, Immutable)] +#[allow(non_camel_case_types, unused)] +#[repr(C)] pub struct fuse_lseek_out { pub offset: u64, } -#[derive(Debug, Decode)] -#[allow(non_camel_case_types)] +#[derive(Debug, FromBytes, KnownLayout, Immutable)] +#[allow(non_camel_case_types, unused)] +#[repr(C)] pub struct fuse_copy_file_range_in { pub fh_in: u64, pub off_in: u64, diff --git a/src/raw/session.rs b/src/raw/session.rs index d4bbf21..29a3e44 100644 --- a/src/raw/session.rs +++ b/src/raw/session.rs @@ -28,7 +28,6 @@ use async_global_executor::{self as task, Task as JoinHandle}; feature = "unprivileged" ))] use async_process::Command; -use bincode_next::{decode_from_slice, encode_into_std_write, encode_to_vec}; use bytes::Bytes; use futures_channel::mpsc::{unbounded, UnboundedReceiver, UnboundedSender}; use futures_util::future::{Either, FutureExt}; @@ -50,6 +49,7 @@ use tokio::task::JoinHandle; #[cfg(all(not(feature = "async-io-runtime"), feature = "tokio-runtime"))] use tokio::{fs::read_dir, task}; use tracing::{debug, debug_span, error, instrument, warn, Instrument, Span}; +use zerocopy::{FromBytes, IntoBytes}; #[cfg(all(target_os = "linux", feature = "unprivileged"))] use crate::find_fusermount3; @@ -590,9 +590,7 @@ impl Session { reply_error_in_place(libc::ENOSYS.into(), request, &self.response_sender).await; - return Err(IoError::other( - format!("receive unknown opcode {}", err.0), - )); + return Err(IoError::other(format!("receive unknown opcode {}", err.0))); } Ok(opcode) => opcode, @@ -603,9 +601,7 @@ impl Session { if opcode != fuse_opcode::FUSE_INIT { error!(?opcode, "received unexpected opcode"); - return Err(IoError::other( - format!("unexpected opcode {opcode:?}"), - )); + return Err(IoError::other(format!("unexpected opcode {opcode:?}"))); } let data_size = in_header.len as usize - FUSE_IN_HEADER_SIZE; @@ -674,18 +670,18 @@ impl Session { }; } - let in_header = match decode_from_slice::(&header_buffer, get_bincode_config()) { + let in_header = match fuse_in_header::read_from_bytes(&header_buffer) { Err(err) => { error!("deserialize fuse_in_header failed {}", err); return ReadResult::Request { - in_header: Err(IoError::other(err)), + in_header: Err(IoError::other("deserialize fuse_in_header failed")), header_buffer, data_buffer, }; } - Ok((in_header, _)) => in_header, + Ok(in_header) => in_header, }; ReadResult::Request { @@ -925,7 +921,7 @@ impl Session { /*fuse_opcode::FUSE_IOCTL => { let mut resp_sender = self.response_sender.clone(); - let ioctl_in = decode_from_slice::(data, get_bincode_config()) { + let ioctl_in = match fuse_ioctl_in::read_from_prefix(data) { Err(err) => { error!("deserialize fuse_ioctl_in failed {}", err); @@ -998,7 +994,7 @@ impl Session { fuse_connection: &FuseConnection, fs: &FS, ) -> IoResult { - let init_in = match decode_from_slice::(data, get_bincode_config()) { + let init_in = match fuse_init_in::read_from_prefix(data) { Err(err) => { error!( "deserialize fuse_init_in failed {}, request unique {}", @@ -1011,11 +1007,8 @@ impl Session { unique: request.unique, }; - let init_out_header_data = encode_to_vec(&init_out_header, get_bincode_config()) - .expect("won't happened"); - if let Err(err) = fuse_connection - .write_vectored::<_, Vec>(init_out_header_data, None) + .write_vectored::<_, &[u8]>(init_out_header.as_bytes(), None) .await .1 { @@ -1224,11 +1217,8 @@ impl Session { unique: request.unique, }; - let init_out_header_data = encode_to_vec(&init_out_header, get_bincode_config()) - .expect("won't happened"); - if let Err(err) = fuse_connection - .write_vectored::<_, Vec>(init_out_header_data, None) + .write_vectored::<_, &[u8]>(init_out_header.as_bytes(), None) .await .1 { @@ -1265,9 +1255,8 @@ impl Session { let mut data = Vec::with_capacity(FUSE_OUT_HEADER_SIZE + FUSE_INIT_OUT_SIZE); - let config = get_bincode_config(); - encode_into_std_write(&out_header, &mut data, config).unwrap(); - encode_into_std_write(&init_out, &mut data, config).unwrap(); + out_header.write_to_io(&mut data).unwrap(); + init_out.write_to_io(&mut data).unwrap(); if let Err(err) = fuse_connection .write_vectored::<_, Vec>(data, None) @@ -1321,8 +1310,7 @@ impl Session { unique: request.unique, }; - encode_to_vec(&out_header, get_bincode_config()) - .expect("won't happened") + out_header.as_bytes().to_vec() } Ok(entry) => { @@ -1338,9 +1326,8 @@ impl Session { let mut data = Vec::with_capacity(FUSE_OUT_HEADER_SIZE + FUSE_ENTRY_OUT_SIZE); - let config = get_bincode_config(); - encode_into_std_write(&out_header, &mut data, config).unwrap(); - encode_into_std_write(&entry_out, &mut data, config).unwrap(); + out_header.write_to_io(&mut data).unwrap(); + entry_out.write_to_io(&mut data).unwrap(); data } @@ -1359,7 +1346,7 @@ impl Session { data: &[u8], fs: &Arc, ) { - let forget_in = match decode_from_slice::(data, get_bincode_config()) { + let forget_in = match fuse_forget_in::read_from_prefix(data) { Err(err) => { error!( "deserialize fuse_forget_in failed {}, request unique {}", @@ -1394,7 +1381,7 @@ impl Session { data: &[u8], fs: &Arc, ) { - let getattr_in = match decode_from_slice::(data, get_bincode_config()) { + let getattr_in = match fuse_getattr_in::read_from_prefix(data) { Err(err) => { error!( "deserialize fuse_forget_in failed {}, request unique {}", @@ -1435,8 +1422,7 @@ impl Session { unique: request.unique, }; - encode_to_vec(&out_header, get_bincode_config()) - .expect("won't happened") + out_header.as_bytes().to_vec() } Ok(attr) => { @@ -1455,9 +1441,8 @@ impl Session { let mut data = Vec::with_capacity(FUSE_OUT_HEADER_SIZE + FUSE_ATTR_OUT_SIZE); - let config = get_bincode_config(); - encode_into_std_write(&out_header, &mut data, config).unwrap(); - encode_into_std_write(&attr_out, &mut data, config).unwrap(); + out_header.write_to_io(&mut data).unwrap(); + attr_out.write_to_io(&mut data).unwrap(); data } @@ -1475,7 +1460,7 @@ impl Session { data: &[u8], fs: &Arc, ) { - let setattr_in = match decode_from_slice::(data, get_bincode_config()) { + let setattr_in = match fuse_setattr_in::read_from_prefix(data) { Err(err) => { error!( "deserialize fuse_setattr_in failed {}, request unique {}", @@ -1515,8 +1500,7 @@ impl Session { unique: request.unique, }; - encode_to_vec(&out_header, get_bincode_config()) - .expect("won't happened") + out_header.as_bytes().to_vec() } Ok(attr) => { @@ -1530,9 +1514,8 @@ impl Session { let mut data = Vec::with_capacity(FUSE_OUT_HEADER_SIZE + FUSE_ATTR_OUT_SIZE); - let config = get_bincode_config(); - encode_into_std_write(&out_header, &mut data, config).unwrap(); - encode_into_std_write(&attr_out, &mut data, config).unwrap(); + out_header.write_to_io(&mut data).unwrap(); + attr_out.write_to_io(&mut data).unwrap(); data } @@ -1561,10 +1544,7 @@ impl Session { unique: request.unique, }; - Either::Left( - encode_to_vec(&out_header, get_bincode_config()) - .expect("won't happened"), - ) + Either::Left(out_header.as_bytes().to_vec()) } Ok(data) => { @@ -1576,8 +1556,7 @@ impl Session { let mut data_buf = Vec::with_capacity(FUSE_OUT_HEADER_SIZE); - let config = get_bincode_config(); - encode_into_std_write(&out_header, &mut data_buf, config).unwrap(); + out_header.write_to_io(&mut data_buf).unwrap(); Either::Right((data_buf, data.data)) } @@ -1644,8 +1623,7 @@ impl Session { unique: request.unique, }; - encode_to_vec(&out_header, get_bincode_config()) - .expect("won't happened") + out_header.as_bytes().to_vec() } Ok(entry) => { @@ -1659,9 +1637,8 @@ impl Session { let mut data = Vec::with_capacity(FUSE_OUT_HEADER_SIZE + FUSE_ENTRY_OUT_SIZE); - let config = get_bincode_config(); - encode_into_std_write(&out_header, &mut data, config).unwrap(); - encode_into_std_write(&entry_out, &mut data, config).unwrap(); + out_header.write_to_io(&mut data).unwrap(); + entry_out.write_to_io(&mut data).unwrap(); data } @@ -1676,10 +1653,10 @@ impl Session { &mut self, request: Request, in_header: fuse_in_header, - mut data: &[u8], + data: &[u8], fs: &Arc, ) { - let mknod_in = match decode_from_slice::(data, get_bincode_config()) { + let (mknod_in, data) = match fuse_mknod_in::read_from_prefix(data) { Err(err) => { error!( "deserialize fuse_mknod_in failed {}, request unique {}", @@ -1691,11 +1668,9 @@ impl Session { return; } - Ok((mknod_in, _)) => mknod_in, + Ok(r) => r, }; - data = &data[FUSE_MKNOD_IN_SIZE..]; - let name = match get_first_null_position(data) { None => { error!( @@ -1745,9 +1720,8 @@ impl Session { let mut data = Vec::with_capacity(FUSE_OUT_HEADER_SIZE + FUSE_ENTRY_OUT_SIZE); - let config = get_bincode_config(); - encode_into_std_write(&out_header, &mut data, config).unwrap(); - encode_into_std_write(&entry_out, &mut data, config).unwrap(); + out_header.write_to_io(&mut data).unwrap(); + entry_out.write_to_io(&mut data).unwrap(); let _ = resp_sender.send(Either::Left(data)).await; } @@ -1760,10 +1734,10 @@ impl Session { &mut self, request: Request, in_header: fuse_in_header, - mut data: &[u8], + data: &[u8], fs: &Arc, ) { - let mkdir_in = match decode_from_slice::(data, get_bincode_config()) { + let (mkdir_in, data) = match fuse_mkdir_in::read_from_prefix(data) { Err(err) => { error!( "deserialize fuse_mknod_in failed {}, request unique {}", @@ -1775,11 +1749,9 @@ impl Session { return; } - Ok((mkdir_in, _)) => mkdir_in, + Ok(r) => r, }; - data = &data[FUSE_MKDIR_IN_SIZE..]; - let name = match get_first_null_position(data) { None => { error!( @@ -1829,9 +1801,8 @@ impl Session { let mut data = Vec::with_capacity(FUSE_OUT_HEADER_SIZE + FUSE_ENTRY_OUT_SIZE); - let config = get_bincode_config(); - encode_into_std_write(&out_header, &mut data, config).unwrap(); - encode_into_std_write(&entry_out, &mut data, config).unwrap(); + out_header.write_to_io(&mut data).unwrap(); + entry_out.write_to_io(&mut data).unwrap(); let _ = resp_sender.send(Either::Left(data)).await; } @@ -1883,9 +1854,7 @@ impl Session { unique: request.unique, }; - - let data = encode_to_vec(&out_header, get_bincode_config()) - .expect("won't happened"); + let data = out_header.as_bytes().to_vec(); let _ = resp_sender.send(Either::Left(data)).await; }); @@ -1935,8 +1904,7 @@ impl Session { unique: request.unique, }; - let data = encode_to_vec(&out_header, get_bincode_config()) - .expect("won't happened"); + let data = out_header.as_bytes().to_vec(); let _ = resp_sender.send(Either::Left(data)).await; }); @@ -1947,10 +1915,10 @@ impl Session { &mut self, request: Request, in_header: fuse_in_header, - mut data: &[u8], + data: &[u8], fs: &Arc, ) { - let rename_in = match decode_from_slice::(data, get_bincode_config()) { + let (rename_in, data) = match fuse_rename_in::read_from_prefix(data) { Err(err) => { error!( "deserialize fuse_rename_in failed {}, request unique {}", @@ -1962,11 +1930,9 @@ impl Session { return; } - Ok((rename_in, _)) => rename_in, + Ok(r) => r, }; - data = &data[FUSE_RENAME_IN_SIZE..]; - let (name, first_null_index) = match get_first_null_position(data) { None => { error!( @@ -1982,7 +1948,7 @@ impl Session { Some(index) => (OsString::from_vec(data[..index].to_vec()), index), }; - data = &data[first_null_index + 1..]; + let data = &data[first_null_index + 1..]; let new_name = match get_first_null_position(data) { None => { @@ -2029,8 +1995,7 @@ impl Session { unique: request.unique, }; - let data = encode_to_vec(&out_header, get_bincode_config()) - .expect("won't happened"); + let data = out_header.as_bytes().to_vec(); let _ = resp_sender.send(Either::Left(data)).await; }); @@ -2041,10 +2006,10 @@ impl Session { &mut self, request: Request, in_header: fuse_in_header, - mut data: &[u8], + data: &[u8], fs: &Arc, ) { - let link_in = match decode_from_slice::(data, get_bincode_config()) { + let (link_in, data) = match fuse_link_in::read_from_prefix(data) { Err(err) => { error!( "deserialize fuse_link_in failed {}, request unique {}", @@ -2056,11 +2021,9 @@ impl Session { return; } - Ok((link_in, _)) => link_in, + Ok((link_in, data)) => (link_in, data), }; - data = &data[FUSE_LINK_IN_SIZE..]; - let name = match get_first_null_position(data) { None => { error!( @@ -2104,9 +2067,8 @@ impl Session { let mut data = Vec::with_capacity(FUSE_OUT_HEADER_SIZE + FUSE_ENTRY_OUT_SIZE); - let config = get_bincode_config(); - encode_into_std_write(&out_header, &mut data, config).unwrap(); - encode_into_std_write(&entry_out, &mut data, config).unwrap(); + out_header.write_to_io(&mut data).unwrap(); + entry_out.write_to_io(&mut data).unwrap(); let _ = resp_sender.send(Either::Left(data)).await; } @@ -2122,7 +2084,7 @@ impl Session { data: &[u8], fs: &Arc, ) { - let open_in = match decode_from_slice::(data, get_bincode_config()) { + let open_in = match fuse_open_in::read_from_prefix(data) { Err(err) => { error!( "deserialize fuse_open_in failed {}, request unique {}", @@ -2166,9 +2128,8 @@ impl Session { let mut data = Vec::with_capacity(FUSE_OUT_HEADER_SIZE + FUSE_OPEN_OUT_SIZE); - let config = get_bincode_config(); - encode_into_std_write(&out_header, &mut data, config).unwrap(); - encode_into_std_write(&open_out, &mut data, config).unwrap(); + out_header.write_to_io(&mut data).unwrap(); + open_out.write_to_io(&mut data).unwrap(); let _ = resp_sender.send(Either::Left(data)).await; }); @@ -2182,7 +2143,7 @@ impl Session { data: &[u8], fs: &Arc, ) { - let read_in = match decode_from_slice::(data, get_bincode_config()) { + let read_in = match fuse_read_in::read_from_prefix(data) { Err(err) => { error!( "deserialize fuse_read_in failed {}, request unique {}", @@ -2237,8 +2198,7 @@ impl Session { let mut data_buf = Vec::with_capacity(FUSE_OUT_HEADER_SIZE); - let config = get_bincode_config(); - encode_into_std_write(&out_header, &mut data_buf, config).unwrap(); + out_header.write_to_io(&mut data_buf).unwrap(); let _ = resp_sender .send(Either::Right((data_buf, reply_data))) @@ -2251,10 +2211,10 @@ impl Session { &mut self, request: Request, in_header: fuse_in_header, - mut data: &[u8], + data: &[u8], fs: &Arc, ) { - let write_in = match decode_from_slice::(data, get_bincode_config()) { + let (write_in, data) = match fuse_write_in::read_from_prefix(data) { Err(err) => { error!( "deserialize fuse_write_in failed {}, request unique {}", @@ -2266,11 +2226,9 @@ impl Session { return; } - Ok((write_in, _)) => write_in, + Ok(r) => r, }; - data = &data[FUSE_WRITE_IN_SIZE..]; - if write_in.size as usize != data.len() { error!("fuse_write_in body len is invalid"); @@ -2321,9 +2279,8 @@ impl Session { let mut data = Vec::with_capacity(FUSE_OUT_HEADER_SIZE + FUSE_WRITE_OUT_SIZE); - let config = get_bincode_config(); - encode_into_std_write(&out_header, &mut data, config).unwrap(); - encode_into_std_write(&write_out, &mut data, config).unwrap(); + out_header.write_to_io(&mut data).unwrap(); + write_out.write_to_io(&mut data).unwrap(); let _ = resp_sender.send(Either::Left(data)).await; }); @@ -2360,9 +2317,8 @@ impl Session { let mut data = Vec::with_capacity(FUSE_OUT_HEADER_SIZE + FUSE_STATFS_OUT_SIZE); - let config = get_bincode_config(); - encode_into_std_write(&out_header, &mut data, config).unwrap(); - encode_into_std_write(&statfs_out, &mut data, config).unwrap(); + out_header.write_to_io(&mut data).unwrap(); + statfs_out.write_to_io(&mut data).unwrap(); let _ = resp_sender.send(Either::Left(data)).await; }); @@ -2376,7 +2332,7 @@ impl Session { data: &[u8], fs: &Arc, ) { - let release_in = match decode_from_slice::(data, get_bincode_config()) { + let release_in = match fuse_release_in::read_from_prefix(data) { Err(err) => { error!( "deserialize fuse_release_in failed {}, request unique {}", @@ -2429,8 +2385,7 @@ impl Session { unique: request.unique, }; - let data = encode_to_vec(&out_header, get_bincode_config()) - .expect("won't happened"); + let data = out_header.as_bytes().to_vec(); let _ = resp_sender.send(Either::Left(data)).await; }); @@ -2444,7 +2399,7 @@ impl Session { data: &[u8], fs: &Arc, ) { - let fsync_in = match decode_from_slice::(data, get_bincode_config()) { + let fsync_in = match fuse_fsync_in::read_from_prefix(data) { Err(err) => { error!( "deserialize fuse_fsync_in failed {}, request unique {}", @@ -2485,8 +2440,7 @@ impl Session { unique: request.unique, }; - let data = encode_to_vec(&out_header, get_bincode_config()) - .expect("won't happened"); + let data = out_header.as_bytes().to_vec(); let _ = resp_sender.send(Either::Left(data)).await; }); @@ -2497,10 +2451,10 @@ impl Session { &mut self, request: Request, in_header: fuse_in_header, - mut data: &[u8], + data: &[u8], fs: &Arc, ) { - let setxattr_in = match decode_from_slice::(data, get_bincode_config()) { + let (setxattr_in, data) = match fuse_setxattr_in::read_from_prefix(data) { Err(err) => { error!( "deserialize fuse_setxattr_in failed {}, request unique {}", @@ -2512,11 +2466,9 @@ impl Session { return; } - Ok((setxattr_in, _)) => setxattr_in, + Ok(r) => r, }; - data = &data[FUSE_SETXATTR_IN_SIZE..]; - let (name, first_null_index) = match get_first_null_position(data) { None => { error!( @@ -2532,7 +2484,7 @@ impl Session { Some(index) => (OsString::from_vec(data[..index].to_vec()), index), }; - data = &data[first_null_index + 1..]; + let data = &data[first_null_index + 1..]; // setxattr "size" field specifies size of only "Value" part of data if setxattr_in.size as usize != data.len() { @@ -2578,8 +2530,7 @@ impl Session { unique: request.unique, }; - let data = encode_to_vec(&out_header, get_bincode_config()) - .expect("won't happened"); + let data = out_header.as_bytes().to_vec(); let _ = resp_sender.send(Either::Left(data)).await; }); @@ -2590,10 +2541,10 @@ impl Session { &mut self, request: Request, in_header: fuse_in_header, - mut data: &[u8], + data: &[u8], fs: &Arc, ) { - let getxattr_in = match decode_from_slice::(data, get_bincode_config()) { + let (getxattr_in, data) = match fuse_getxattr_in::read_from_prefix(data) { Err(err) => { error!( "deserialize fuse_getxattr_in failed {}, request unique {}", @@ -2605,11 +2556,9 @@ impl Session { return; } - Ok((getxattr_in, _)) => getxattr_in, + Ok(r) => r, }; - data = &data[FUSE_GETXATTR_IN_SIZE..]; - let name = match get_first_null_position(data) { None => { error!("fuse_getxattr_in body has no null {}", request.unique); @@ -2656,9 +2605,8 @@ impl Session { let mut data = Vec::with_capacity(FUSE_OUT_HEADER_SIZE + FUSE_STATFS_OUT_SIZE); - let config = get_bincode_config(); - encode_into_std_write(&out_header, &mut data, config).unwrap(); - encode_into_std_write(&getxattr_out, &mut data, config).unwrap(); + out_header.write_to_io(&mut data).unwrap(); + getxattr_out.write_to_io(&mut data).unwrap(); Either::Left(data) } @@ -2674,8 +2622,7 @@ impl Session { let mut data = Vec::with_capacity(FUSE_OUT_HEADER_SIZE); - let config = get_bincode_config(); - encode_into_std_write(&out_header, &mut data, config).unwrap(); + out_header.write_to_io(&mut data).unwrap(); Either::Right((data, xattr_data)) } @@ -2693,7 +2640,7 @@ impl Session { data: &[u8], fs: &Arc, ) { - let listxattr_in = match decode_from_slice::(data, get_bincode_config()) { + let listxattr_in = match fuse_getxattr_in::read_from_prefix(data) { Err(err) => { error!( "deserialize fuse_getxattr_in in listxattr failed {}, request unique {}", @@ -2742,9 +2689,8 @@ impl Session { let mut data = Vec::with_capacity(FUSE_OUT_HEADER_SIZE + FUSE_STATFS_OUT_SIZE); - let config = get_bincode_config(); - encode_into_std_write(&out_header, &mut data, config).unwrap(); - encode_into_std_write(&getxattr_out, &mut data, config).unwrap(); + out_header.write_to_io(&mut data).unwrap(); + getxattr_out.write_to_io(&mut data).unwrap(); Either::Left(data) } @@ -2760,8 +2706,7 @@ impl Session { let mut data = Vec::with_capacity(FUSE_OUT_HEADER_SIZE); - let config = get_bincode_config(); - encode_into_std_write(&out_header, &mut data, config).unwrap(); + out_header.write_to_io(&mut data).unwrap(); Either::Right((data, xattr_data)) } @@ -2816,8 +2761,7 @@ impl Session { unique: request.unique, }; - let data = encode_to_vec(&out_header, get_bincode_config()) - .expect("won't happened"); + let data = out_header.as_bytes().to_vec(); let _ = resp_sender.send(Either::Left(data)).await; }); @@ -2831,7 +2775,7 @@ impl Session { data: &[u8], fs: &Arc, ) { - let flush_in = match decode_from_slice::(data, get_bincode_config()) { + let flush_in = match fuse_flush_in::read_from_prefix(data) { Err(err) => { error!( "deserialize fuse_flush_in failed {}, request unique {}", @@ -2870,8 +2814,7 @@ impl Session { unique: request.unique, }; - let data = encode_to_vec(&out_header, get_bincode_config()) - .expect("won't happened"); + let data = out_header.as_bytes().to_vec(); let _ = resp_sender.send(Either::Left(data)).await; }); @@ -2885,7 +2828,7 @@ impl Session { data: &[u8], fs: &Arc, ) { - let open_in = match decode_from_slice::(data, get_bincode_config()) { + let open_in = match fuse_open_in::read_from_prefix(data) { Err(err) => { error!( "deserialize fuse_open_in in opendir failed {}, request unique {}", @@ -2929,9 +2872,8 @@ impl Session { let mut data = Vec::with_capacity(FUSE_OUT_HEADER_SIZE + FUSE_OPEN_OUT_SIZE); - let config = get_bincode_config(); - encode_into_std_write(&out_header, &mut data, config).unwrap(); - encode_into_std_write(&open_out, &mut data, config).unwrap(); + out_header.write_to_io(&mut data).unwrap(); + open_out.write_to_io(&mut data).unwrap(); let _ = resp_sender.send(Either::Left(data)).await; }); @@ -2951,7 +2893,7 @@ impl Session { return; } - let read_in = match decode_from_slice::(data, get_bincode_config()) { + let read_in = match fuse_read_in::read_from_prefix(data) { Err(err) => { error!( "deserialize fuse_read_in in readdir failed {}, request unique {}", @@ -3024,8 +2966,7 @@ impl Session { r#type: mode_from_kind_and_perm(entry.kind, 0) >> 12, }; - let config = get_bincode_config(); - encode_into_std_write(&dir_entry, &mut entry_data, config).unwrap(); + dir_entry.write_to_io(&mut entry_data).unwrap(); entry_data.extend_from_slice(name.as_bytes()); @@ -3043,8 +2984,7 @@ impl Session { let mut data = Vec::with_capacity(FUSE_OUT_HEADER_SIZE); - let config = get_bincode_config(); - encode_into_std_write(&out_header, &mut data, config).unwrap(); + out_header.write_to_io(&mut data).unwrap(); let _ = resp_sender .send(Either::Right((data, entry_data.into()))) @@ -3060,7 +3000,7 @@ impl Session { data: &[u8], fs: &Arc, ) { - let release_in = match decode_from_slice::(data, get_bincode_config()) { + let release_in = match fuse_release_in::read_from_prefix(data) { Err(err) => { error!( "deserialize fuse_release_in in releasedir failed {}, request unique {}", @@ -3099,8 +3039,7 @@ impl Session { unique: request.unique, }; - let data = encode_to_vec(&out_header, get_bincode_config()) - .expect("won't happened"); + let data = out_header.as_bytes().to_vec(); let _ = resp_sender.send(Either::Left(data)).await; }); @@ -3114,7 +3053,7 @@ impl Session { data: &[u8], fs: &Arc, ) { - let fsync_in = match decode_from_slice::(data, get_bincode_config()) { + let fsync_in = match fuse_fsync_in::read_from_prefix(data) { Err(err) => { error!( "deserialize fuse_fsync_in in fsyncdir failed {}, request unique {}", @@ -3155,8 +3094,7 @@ impl Session { unique: request.unique, }; - let data = encode_to_vec(&out_header, get_bincode_config()) - .expect("won't happened"); + let data = out_header.as_bytes().to_vec(); let _ = resp_sender.send(Either::Left(data)).await; }); @@ -3171,7 +3109,7 @@ impl Session { data: &[u8], fs: &Arc, ) { - let getlk_in = match decode_from_slice::(data, get_bincode_config()) { + let getlk_in = match fuse_lk_in::read_from_prefix(data) { Err(err) => { error!( "deserialize fuse_lk_in in getlk failed {}, request unique {}", @@ -3183,7 +3121,7 @@ impl Session { return; } - Ok((getlk_in, _)) => getlk_in, + Ok(getlk_in) => getlk_in, }; let mut resp_sender = self.response_sender.clone(); @@ -3227,9 +3165,8 @@ impl Session { let mut data = Vec::with_capacity(FUSE_OUT_HEADER_SIZE + FUSE_LK_OUT_SIZE); - let config = get_bincode_config(); - encode_into_std_write(&out_header, &mut data, config).unwrap(); - encode_into_std_write(&getlk_out, &mut data, config).unwrap(); + out_header.write_to_io(&mut data).unwrap(); + getlk_out.write_to_io(&mut data).unwrap(); let _ = resp_sender.send(Either::Left(data)).await; }); @@ -3245,7 +3182,7 @@ impl Session { block: bool, fs: &Arc, ) { - let setlk_in = match decode_from_slice::(data, get_bincode_config()) { + let setlk_in = match fuse_lk_in::read_from_prefix(data) { Err(err) => { let opcode = if block { fuse_opcode::FUSE_SETLKW @@ -3263,7 +3200,7 @@ impl Session { return; } - Ok((setlk_in, _)) => setlk_in, + Ok(setlk_in) => setlk_in, }; let mut resp_sender = self.response_sender.clone(); @@ -3300,8 +3237,7 @@ impl Session { unique: request.unique, }; - let data = encode_to_vec(&out_header, get_bincode_config()) - .expect("can't serialize into vec"); + let data = out_header.as_bytes().to_vec(); let _ = resp_sender.send(Either::Left(data)).await; }); @@ -3315,7 +3251,7 @@ impl Session { data: &[u8], fs: &Arc, ) { - let access_in = match decode_from_slice::(data, get_bincode_config()) { + let access_in = match fuse_access_in::read_from_prefix(data) { Err(err) => { error!( "deserialize fuse_access_in failed {}, request unique {}", @@ -3354,8 +3290,7 @@ impl Session { debug!("access response {}", resp_value); - let data = encode_to_vec(&out_header, get_bincode_config()) - .expect("won't happened"); + let data = out_header.as_bytes().to_vec(); let _ = resp_sender.send(Either::Left(data)).await; }); @@ -3366,10 +3301,10 @@ impl Session { &mut self, request: Request, in_header: fuse_in_header, - mut data: &[u8], + data: &[u8], fs: &Arc, ) { - let create_in = match decode_from_slice::(data, get_bincode_config()) { + let (create_in, data) = match fuse_create_in::read_from_prefix(data) { Err(err) => { error!( "deserialize fuse_create_in failed {}, request unique {}", @@ -3381,11 +3316,9 @@ impl Session { return; } - Ok((create_in, _)) => create_in, + Ok(r) => r, }; - data = &data[FUSE_CREATE_IN_SIZE..]; - let name = match get_first_null_position(data) { None => { error!( @@ -3440,10 +3373,9 @@ impl Session { let mut data = Vec::with_capacity(FUSE_OUT_HEADER_SIZE + FUSE_ENTRY_OUT_SIZE + FUSE_OPEN_OUT_SIZE); - let config = get_bincode_config(); - encode_into_std_write(&out_header, &mut data, config).unwrap(); - encode_into_std_write(&entry_out, &mut data, config).unwrap(); - encode_into_std_write(&open_out, &mut data, config).unwrap(); + out_header.write_to_io(&mut data).unwrap(); + entry_out.write_to_io(&mut data).unwrap(); + open_out.write_to_io(&mut data).unwrap(); let _ = resp_sender.send(Either::Left(data)).await; }); @@ -3451,7 +3383,7 @@ impl Session { #[instrument(skip(self, data, fs))] async fn handle_interrupt(&mut self, request: Request, data: &[u8], fs: &Arc) { - let interrupt_in = match decode_from_slice::(data, get_bincode_config()) { + let interrupt_in = match fuse_interrupt_in::read_from_prefix(data) { Err(err) => { error!( "deserialize fuse_interrupt_in failed {}, request unique {}", @@ -3487,8 +3419,7 @@ impl Session { unique: request.unique, }; - let data = encode_to_vec(&out_header, get_bincode_config()) - .expect("won't happened"); + let data = out_header.as_bytes().to_vec(); let _ = resp_sender.send(Either::Left(data)).await; }); @@ -3502,7 +3433,7 @@ impl Session { data: &[u8], fs: &Arc, ) { - let bmap_in = match decode_from_slice::(data, get_bincode_config()) { + let bmap_in = match fuse_bmap_in::read_from_prefix(data) { Err(err) => { error!( "deserialize fuse_bmap_in failed {}, request unique {}", @@ -3549,9 +3480,8 @@ impl Session { let mut data = Vec::with_capacity(FUSE_OUT_HEADER_SIZE + FUSE_BMAP_OUT_SIZE); - let config = get_bincode_config(); - encode_into_std_write(&out_header, &mut data, config).unwrap(); - encode_into_std_write(&bmap_out, &mut data, config).unwrap(); + out_header.write_to_io(&mut data).unwrap(); + bmap_out.write_to_io(&mut data).unwrap(); let _ = resp_sender.send(Either::Left(data)).await; }); @@ -3565,7 +3495,7 @@ impl Session { data: &[u8], fs: &Arc, ) { - let poll_in = match decode_from_slice::(data, get_bincode_config()) { + let poll_in = match fuse_poll_in::read_from_prefix(data) { Err(err) => { error!( "deserialize fuse_poll_in failed {}, request unique {}", @@ -3628,9 +3558,8 @@ impl Session { let mut data = Vec::with_capacity(FUSE_OUT_HEADER_SIZE + FUSE_POLL_OUT_SIZE); - let config = get_bincode_config(); - encode_into_std_write(&out_header, &mut data, config).unwrap(); - encode_into_std_write(&poll_out, &mut data, config).unwrap(); + out_header.write_to_io(&mut data).unwrap(); + poll_out.write_to_io(&mut data).unwrap(); let _ = resp_sender.send(Either::Left(data)).await; }); @@ -3641,26 +3570,24 @@ impl Session { &mut self, request: Request, in_header: fuse_in_header, - mut data: &[u8], + data: &[u8], fs: &Arc, ) { let resp_sender = self.response_sender.clone(); - let notify_retrieve_in: fuse_notify_retrieve_in = match decode_from_slice(data, get_bincode_config()) { - Err(err) => { - error!( - "deserialize fuse_notify_retrieve_in failed {}, request unique {}", - err, request.unique - ); - - // TODO need to reply or not? - return; - } + let (notify_retrieve_in, data) = match fuse_notify_retrieve_in::read_from_prefix(data) { + Err(err) => { + error!( + "deserialize fuse_notify_retrieve_in failed {}, request unique {}", + err, request.unique + ); - Ok((notify_retrieve_in, _)) => notify_retrieve_in, - }; + // TODO need to reply or not? + return; + } - data = &data[FUSE_NOTIFY_RETRIEVE_IN_SIZE..]; + Ok(r) => r, + }; if data.len() < notify_retrieve_in.size as usize { error!( @@ -3691,15 +3618,15 @@ impl Session { }); } - #[instrument(skip(self, data, fs))] + #[instrument(level = "debug", skip(self, data, fs))] async fn handle_batch_forget( &mut self, request: Request, _in_header: fuse_in_header, - mut data: &[u8], + data: &[u8], fs: &Arc, ) { - let batch_forget_in: fuse_batch_forget_in = match decode_from_slice(data, get_bincode_config()) { + let (batch_forget_in, mut data) = match fuse_batch_forget_in::read_from_prefix(data) { Err(err) => { error!( "deserialize fuse_batch_forget_in failed {}, request unique {}", @@ -3710,16 +3637,14 @@ impl Session { return; } - Ok((batch_forget_in, _)) => batch_forget_in, + Ok(r) => r, }; let mut forgets = vec![]; - data = &data[FUSE_BATCH_FORGET_IN_SIZE..]; - // TODO if has less data, should I return error? while data.len() >= FUSE_FORGET_ONE_SIZE { - match decode_from_slice::(data, get_bincode_config()) { + match fuse_forget_one::read_from_prefix(data) { Err(err) => { error!("deserialize fuse_batch_forget_in body fuse_forget_one failed {}, request unique {}", err, request.unique); @@ -3727,8 +3652,8 @@ impl Session { return; } - Ok((forget_one, _)) => { - data = &data[FUSE_FORGET_ONE_SIZE..]; + Ok((forget_one, remaining_data)) => { + data = remaining_data; forgets.push(forget_one); } @@ -3766,7 +3691,7 @@ impl Session { data: &[u8], fs: &Arc, ) { - let fallocate_in: fuse_fallocate_in = match decode_from_slice(data, get_bincode_config()) { + let fallocate_in: fuse_fallocate_in = match fuse_fallocate_in::read_from_prefix(data) { Err(err) => { error!( "deserialize fuse_fallocate_in failed {}, request unique {}", @@ -3812,9 +3737,7 @@ impl Session { unique: request.unique, }; - let config = get_bincode_config(); - let data = encode_to_vec(&out_header, config) - .expect("won't happened"); + let data = out_header.as_bytes().to_vec(); let _ = resp_sender.send(Either::Left(data)).await; }); @@ -3828,7 +3751,7 @@ impl Session { data: &[u8], fs: &Arc, ) { - let readdirplus_in: fuse_read_in = match decode_from_slice(data, get_bincode_config()) { + let readdirplus_in: fuse_read_in = match fuse_read_in::read_from_prefix(data) { Err(err) => { error!( "deserialize fuse_read_in in readdirplus failed {}, request unique {}", @@ -3920,9 +3843,7 @@ impl Session { }, }; - let config = get_bincode_config(); - encode_into_std_write(&dir_entry, &mut entry_data, config) - .expect("won't happened"); + dir_entry.write_to_io(&mut entry_data).unwrap(); entry_data.extend_from_slice(name.as_bytes()); @@ -3940,9 +3861,7 @@ impl Session { let mut data = Vec::with_capacity(FUSE_OUT_HEADER_SIZE); - let config = get_bincode_config(); - encode_into_std_write(&out_header, &mut data, config) - .expect("won't happened"); + out_header.write_to_io(&mut data).unwrap(); let _ = resp_sender .send(Either::Right((data, entry_data.into()))) @@ -3955,10 +3874,10 @@ impl Session { &mut self, request: Request, in_header: fuse_in_header, - mut data: &[u8], + data: &[u8], fs: &Arc, ) { - let rename2_in: fuse_rename2_in = match decode_from_slice(data, get_bincode_config()) { + let (rename2_in, data) = match fuse_rename2_in::read_from_prefix(data) { Err(err) => { error!( "deserialize fuse_rename2_in failed {}, request unique {}", @@ -3970,11 +3889,9 @@ impl Session { return; } - Ok((rename2_in, _)) => rename2_in, + Ok(r) => r, }; - data = &data[FUSE_RENAME2_IN_SIZE..]; - let (old_name, index) = match get_first_null_position(data) { None => { error!( @@ -3990,7 +3907,7 @@ impl Session { Some(index) => (OsString::from_vec(data[..index].to_vec()), index), }; - data = &data[index + 1..]; + let data = &data[index + 1..]; let new_name = match get_first_null_position(data) { None => { @@ -4043,8 +3960,7 @@ impl Session { unique: request.unique, }; - let config = get_bincode_config(); - let data = encode_to_vec(&out_header, config).unwrap(); + let data = out_header.as_bytes().to_vec(); let _ = resp_sender.send(Either::Left(data)).await; }); @@ -4060,7 +3976,7 @@ impl Session { ) { let mut resp_sender = self.response_sender.clone(); - let lseek_in = match decode_from_slice::(data, get_bincode_config()) { + let lseek_in = match fuse_lseek_in::read_from_prefix(data) { Err(err) => { error!( "deserialize fuse_lseek_in failed {}, request unique {}", @@ -4112,9 +4028,8 @@ impl Session { let mut data = Vec::with_capacity(FUSE_OUT_HEADER_SIZE + FUSE_OPEN_OUT_SIZE); - let config = get_bincode_config(); - encode_into_std_write(&out_header, &mut data, config).unwrap(); - encode_into_std_write(&lseek_out, &mut data, config).unwrap(); + out_header.write_to_io(&mut data).unwrap(); + lseek_out.write_to_io(&mut data).unwrap(); let _ = resp_sender.send(Either::Left(data)).await; }); @@ -4130,20 +4045,20 @@ impl Session { ) { let mut resp_sender = self.response_sender.clone(); - let copy_file_range_in: fuse_copy_file_range_in = match decode_from_slice(data, get_bincode_config()) { - Err(err) => { - error!( - "deserialize fuse_copy_file_range_in failed {}, request unique {}", - err, request.unique - ); + let copy_file_range_in = match fuse_copy_file_range_in::read_from_prefix(data) { + Err(err) => { + error!( + "deserialize fuse_copy_file_range_in failed {}, request unique {}", + err, request.unique + ); - reply_error_in_place(libc::EINVAL.into(), request, &self.response_sender).await; + reply_error_in_place(libc::EINVAL.into(), request, &self.response_sender).await; - return; - } + return; + } - Ok((copy_file_range_in, _)) => copy_file_range_in, - }; + Ok((copy_file_range_in, _)) => copy_file_range_in, + }; let fs = fs.clone(); @@ -4186,9 +4101,8 @@ impl Session { let mut data = Vec::with_capacity(FUSE_OUT_HEADER_SIZE + FUSE_WRITE_OUT_SIZE); - let config = get_bincode_config(); - encode_into_std_write(&out_header, &mut data, config).unwrap(); - encode_into_std_write(&write_out, &mut data, config).unwrap(); + out_header.write_to_io(&mut data).unwrap(); + write_out.write_to_io(&mut data).unwrap(); let _ = resp_sender.send(Either::Left(data)).await; }); @@ -4205,8 +4119,7 @@ where unique: request.unique, }; - let data = encode_to_vec(&out_header, get_bincode_config()) - .expect("won't happened"); + let data = out_header.as_bytes().to_vec(); let _ = pin!(sender).send(Either::Left(data)).await; } From 494858ef573352d35cc6925d69a7c01ca12dc674 Mon Sep 17 00:00:00 2001 From: Jakob Truelsen Date: Fri, 27 Feb 2026 09:31:27 +0100 Subject: [PATCH 02/13] Save allocation of vector when sending init --- src/raw/session.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/raw/session.rs b/src/raw/session.rs index 29a3e44..6266e6e 100644 --- a/src/raw/session.rs +++ b/src/raw/session.rs @@ -1253,13 +1253,8 @@ impl Session { unique: request.unique, }; - let mut data = Vec::with_capacity(FUSE_OUT_HEADER_SIZE + FUSE_INIT_OUT_SIZE); - - out_header.write_to_io(&mut data).unwrap(); - init_out.write_to_io(&mut data).unwrap(); - if let Err(err) = fuse_connection - .write_vectored::<_, Vec>(data, None) + .write_vectored(out_header.as_bytes(), Some(init_out.as_bytes())) .await .1 { From bc41efe6fcdc2d4b456942099529151b51bd2bd4 Mon Sep 17 00:00:00 2001 From: Jakob Truelsen Date: Mon, 2 Mar 2026 15:59:52 +0100 Subject: [PATCH 03/13] rework response sending. Move the sending of responses from the mount task into the the responding tasks. This allows us to borrow references to the constructed structs so that we do not need to allocate vectors to send around. Add a new notify instance, to stop the mount task in case of a write error --- src/notify.rs | 103 +----- src/raw/mod.rs | 4 - src/raw/session.rs | 850 ++++++++++++++++++++------------------------- 3 files changed, 403 insertions(+), 554 deletions(-) diff --git a/src/notify.rs b/src/notify.rs index 284967d..cd945e6 100644 --- a/src/notify.rs +++ b/src/notify.rs @@ -1,12 +1,9 @@ //! notify kernel. use std::ffi::OsString; -use std::os::unix::ffi::OsStrExt; +use std::sync::Arc; use bytes::{Buf, Bytes}; -use futures_channel::mpsc::UnboundedSender; -use futures_util::future::Either; -use futures_util::sink::SinkExt; use zerocopy::IntoBytes; use crate::raw::abi::{ @@ -17,23 +14,23 @@ use crate::raw::abi::{ FUSE_NOTIFY_POLL_WAKEUP_OUT_SIZE, FUSE_NOTIFY_RETRIEVE_OUT_SIZE, FUSE_NOTIFY_STORE_OUT_SIZE, FUSE_OUT_HEADER_SIZE, }; -use crate::raw::FuseData; +use crate::raw::session::ResponseSender; #[derive(Debug, Clone)] /// notify kernel there are something need to handle. pub struct Notify { - sender: UnboundedSender, + sender: Arc, } impl Notify { - pub(crate) fn new(sender: UnboundedSender) -> Self { + pub(crate) fn new(sender: Arc) -> Self { Self { sender } } /// notify kernel there are something need to handle. If notify failed, the `kind` will be /// return in `Err`. - async fn notify(&mut self, kind: NotifyKind) -> Result<(), NotifyKind> { - let data = match &kind { + async fn notify(&mut self, kind: NotifyKind) { + match &kind { NotifyKind::Wakeup { kh } => { let out_header = fuse_out_header { len: (FUSE_OUT_HEADER_SIZE + FUSE_NOTIFY_POLL_WAKEUP_OUT_SIZE) as u32, @@ -43,17 +40,7 @@ impl Notify { let wakeup_out = fuse_notify_poll_wakeup_out { kh: *kh }; - let mut data = - Vec::with_capacity(FUSE_OUT_HEADER_SIZE + FUSE_NOTIFY_POLL_WAKEUP_OUT_SIZE); - - out_header - .write_to_io(&mut data) - .expect("vec size is not enough"); - wakeup_out - .write_to_io(&mut data) - .expect("vec size is not enough"); - - Either::Left(data) + self.sender.send2(&out_header, wakeup_out.as_bytes()).await; } NotifyKind::InvalidInode { inode, offset, len } => { @@ -69,17 +56,7 @@ impl Notify { len: *len, }; - let mut data = - Vec::with_capacity(FUSE_OUT_HEADER_SIZE + FUSE_NOTIFY_INVAL_INODE_OUT_SIZE); - - out_header - .write_to_io(&mut data) - .expect("vec size is not enough"); - invalid_inode_out - .write_to_io(&mut data) - .expect("vec size is not enough"); - - Either::Left(data) + self.sender.send2(&out_header, invalid_inode_out.as_bytes()).await; } NotifyKind::InvalidEntry { parent, name } => { @@ -95,19 +72,8 @@ impl Notify { _padding: 0, }; - let mut data = - Vec::with_capacity(FUSE_OUT_HEADER_SIZE + FUSE_NOTIFY_INVAL_ENTRY_OUT_SIZE); - - out_header - .write_to_io(&mut data) - .expect("vec size is not enough"); - invalid_entry_out - .write_to_io(&mut data) - .expect("vec size is not enough"); - // TODO should I add null at the end? - - Either::Right((data, Bytes::copy_from_slice(name.as_bytes()))) + self.sender.send2(&out_header, invalid_entry_out.as_bytes()).await; } NotifyKind::Delete { @@ -128,19 +94,8 @@ impl Notify { _padding: 0, }; - let mut data = - Vec::with_capacity(FUSE_OUT_HEADER_SIZE + FUSE_NOTIFY_DELETE_OUT_SIZE); - - out_header - .write_to_io(&mut data) - .expect("vec size is not enough"); - delete_out - .write_to_io(&mut data) - .expect("vec size is not enough"); - // TODO should I add null at the end? - - Either::Right((data, Bytes::copy_from_slice(name.as_bytes()))) + self.sender.send2(&out_header, delete_out.as_bytes()).await; } NotifyKind::Store { @@ -161,17 +116,7 @@ impl Notify { _padding: 0, }; - let mut data_buf = - Vec::with_capacity(FUSE_OUT_HEADER_SIZE + FUSE_NOTIFY_STORE_OUT_SIZE); - - out_header - .write_to_io(&mut data_buf) - .expect("vec size is not enough"); - store_out - .write_to_io(&mut data_buf) - .expect("vec size is not enough"); - - Either::Right((data_buf, data.clone())) + self.sender.send2(&out_header, store_out.as_bytes()).await; } NotifyKind::Retrieve { @@ -194,43 +139,31 @@ impl Notify { _padding: 0, }; - let mut data = - Vec::with_capacity(FUSE_OUT_HEADER_SIZE + FUSE_NOTIFY_RETRIEVE_OUT_SIZE); - - out_header - .write_to_io(&mut data) - .expect("vec size is not enough"); - retrieve_out - .write_to_io(&mut data) - .expect("vec size is not enough"); - - Either::Left(data) + self.sender.send2(&out_header, retrieve_out.as_bytes()).await; } }; - - self.sender.send(data).await.or(Err(kind)) } /// try to notify kernel the IO is ready, kernel can wakeup the waiting program. pub async fn wakeup(mut self, kh: u64) { - let _ = self.notify(NotifyKind::Wakeup { kh }).await; + self.notify(NotifyKind::Wakeup { kh }).await; } /// try to notify the cache invalidation about an inode. pub async fn invalid_inode(mut self, inode: u64, offset: i64, len: i64) { - let _ = self + self .notify(NotifyKind::InvalidInode { inode, offset, len }) .await; } /// try to notify the invalidation about a directory entry. pub async fn invalid_entry(mut self, parent: u64, name: OsString) { - let _ = self.notify(NotifyKind::InvalidEntry { parent, name }).await; + self.notify(NotifyKind::InvalidEntry { parent, name }).await; } /// try to notify a directory entry has been deleted. pub async fn delete(mut self, parent: u64, child: u64, name: OsString) { - let _ = self + self .notify(NotifyKind::Delete { parent, child, @@ -241,7 +174,7 @@ impl Notify { /// try to push the data in an inode for updating the kernel cache. pub async fn store(mut self, inode: u64, offset: u64, mut data: impl Buf) { - let _ = self + self .notify(NotifyKind::Store { inode, offset, @@ -252,7 +185,7 @@ impl Notify { /// try to retrieve data in an inode from the kernel cache. pub async fn retrieve(mut self, notify_unique: u64, inode: u64, offset: u64, size: u32) { - let _ = self + self .notify(NotifyKind::Retrieve { notify_unique, inode, diff --git a/src/raw/mod.rs b/src/raw/mod.rs index 064878b..a174801 100644 --- a/src/raw/mod.rs +++ b/src/raw/mod.rs @@ -6,15 +6,11 @@ //! want to control the inode or do the path<->inode map on yourself, [`Filesystem`] is the only one //! choose. -use bytes::Bytes; pub use filesystem::Filesystem; -use futures_util::future::Either; pub use request::Request; #[cfg(any(feature = "async-io-runtime", feature = "tokio-runtime"))] pub use session::{MountHandle, Session}; -pub(crate) type FuseData = Either, (Vec, Bytes)>; - pub(crate) mod abi; mod connection; mod filesystem; diff --git a/src/raw/session.rs b/src/raw/session.rs index 6266e6e..59e73a4 100644 --- a/src/raw/session.rs +++ b/src/raw/session.rs @@ -28,11 +28,8 @@ use async_global_executor::{self as task, Task as JoinHandle}; feature = "unprivileged" ))] use async_process::Command; -use bytes::Bytes; -use futures_channel::mpsc::{unbounded, UnboundedReceiver, UnboundedSender}; -use futures_util::future::{Either, FutureExt}; +use futures_util::future::FutureExt; use futures_util::select; -use futures_util::sink::{Sink, SinkExt}; use futures_util::stream::StreamExt; use nix::mount; #[cfg(any(target_os = "freebsd", target_os = "macos"))] @@ -61,7 +58,6 @@ use crate::raw::connection::FuseConnection; use crate::raw::filesystem::Filesystem; use crate::raw::reply::ReplyXAttr; use crate::raw::request::Request; -use crate::raw::FuseData; use crate::MountOptions; use crate::{Errno, SetAttr}; @@ -104,6 +100,92 @@ impl Drop for MountHandle { } } +/// A sender for sending response to kernel, it will send response immediately when call send method, and notify session when send failed. +#[derive(Debug)] +pub (crate) struct ResponseSender { + /// notify session when send failed, session will stop and unmount when receive this notify + send_failed: Arc, + /// connection to write response + connection: Arc, +} + +impl ResponseSender { + /// send response with only header, no data + pub (crate) async fn send1(&self, header: &fuse_out_header) { + if let Err(err) = self + .connection + .write_vectored::<_, &[u8]>(header.as_bytes(), None) + .await + .1 + { + if err.kind() == ErrorKind::NotFound { + warn!( + "may reply interrupted fuse request, ignore this error {}", + err + ); + } else { + error!("reply fuse failed {}", err); + self.send_failed.notify(); + } + } + } + + /// send response with header and data + pub (crate) async fn send2(&self, header: &fuse_out_header, data: &[u8]) { + if let Err(err) = self + .connection + .write_vectored::<_, &[u8]>(header.as_bytes(), Some(data)) + .await + .1 + { + if err.kind() == ErrorKind::NotFound { + warn!( + "may reply interrupted fuse request, ignore this error {}", + err + ); + } else { + error!("reply fuse failed {}", err); + self.send_failed.notify(); + } + } + } + + /// send response with header and two parts of data. + pub (crate) async fn send3(&self, header: &fuse_out_header, d1: &[u8], d2: &[u8]) { + // TODO: Implement a write_vectored in FuseConnection to avoid this copy + let mut data = Vec::with_capacity(d1.len() + d2.len()); + data.extend_from_slice(d1); + data.extend_from_slice(d2); + if let Err(err) = self + .connection + .write_vectored::<_, &[u8]>(header.as_bytes(), Some(&data)) + .await + .1 + { + if err.kind() == ErrorKind::NotFound { + warn!( + "may reply interrupted fuse request, ignore this error {}", + err + ); + } else { + error!("reply fuse failed {}", err); + self.send_failed.notify(); + } + } + } + + /// send error response + #[inline] + async fn send_err(&self, request: &Request, err: Errno) { + let out_header = fuse_out_header { + len: FUSE_OUT_HEADER_SIZE as u32, + error: err.into(), + unique: request.unique, + }; + self.send1(&out_header).await + } +} + #[derive(Debug)] struct MountHandleInner { task: JoinHandle>, @@ -239,8 +321,7 @@ impl Future for MountHandle { pub struct Session { fuse_connection: Option>, filesystem: Option>, - response_sender: UnboundedSender, - response_receiver: Option>, + response_sender: Option>, mount_options: MountOptions, } @@ -269,27 +350,24 @@ impl Debug for ReadResult { impl Session { /// new a fuse filesystem session. pub fn new(mount_options: MountOptions) -> Self { - let (sender, receiver) = unbounded(); - Self { fuse_connection: None, filesystem: None, - response_sender: sender, - response_receiver: Some(receiver), + response_sender: None, mount_options, } } +} +#[cfg(any(feature = "async-io-runtime", feature = "tokio-runtime"))] +impl Session { /// get a [`notify`]. /// /// [`notify`]: Notify fn get_notify(&self) -> Notify { - Notify::new(self.response_sender.clone()) + Notify::new(self.response_sender().clone()) } -} -#[cfg(any(feature = "async-io-runtime", feature = "tokio-runtime"))] -impl Session { async fn mount_empty_check(&self, mount_path: &Path) -> IoResult<()> { #[cfg(all(not(feature = "async-io-runtime"), feature = "tokio-runtime"))] if !self.mount_options.nonempty @@ -492,28 +570,31 @@ impl Session { self.mount_with_unprivileged(fs, mount_path).await } + /// get response sender, it should be called after mount, otherwise it will panic + fn response_sender(&self) -> &Arc { + self.response_sender + .as_ref() + .expect("response_sender should be Some()") + } + async fn inner_mount(mut self) -> IoResult<()> { let fuse_write_connection = self.fuse_connection.as_ref().unwrap().clone(); - let receiver = self.response_receiver.take().unwrap(); + let send_failed = Arc::new(async_notify::Notify::new()); + self.response_sender.replace(Arc::new(ResponseSender { + send_failed: send_failed.clone(), + connection: fuse_write_connection, + })); let dispatch_task = self.dispatch().fuse(); let mut dispatch_task = pin!(dispatch_task); - #[cfg(all(not(feature = "tokio-runtime"), feature = "async-io-runtime"))] - let reply_task = - task::spawn(async move { Self::reply_fuse(fuse_write_connection, receiver).await }) - .fuse(); - #[cfg(all(not(feature = "async-io-runtime"), feature = "tokio-runtime"))] - let reply_task = task::spawn(Self::reply_fuse(fuse_write_connection, receiver)) - .map(Result::unwrap) - .fuse(); - - let mut reply_task = pin!(reply_task); + let send_failed = send_failed.notified().fuse(); + let mut send_failed = pin!(send_failed); select! { - reply_result = reply_task => { - reply_result?; + _ = send_failed => { + return Err(std::io::Error::new(ErrorKind::Other, "send response failed")) } dispatch_result = dispatch_task => { @@ -524,34 +605,6 @@ impl Session { Ok(()) } - async fn reply_fuse( - fuse_connection: Arc, - mut response_receiver: UnboundedReceiver, - ) -> IoResult<()> { - while let Some(response) = response_receiver.next().await { - let (data, extend_data) = match response { - Either::Left(data) => (data, None), - Either::Right((data, extend_data)) => (data, Some(extend_data)), - }; - if let Err(err) = fuse_connection.write_vectored(data, extend_data).await.1 { - if err.kind() == ErrorKind::NotFound { - warn!( - "may reply interrupted fuse request, ignore this error {}", - err - ); - - continue; - } - - error!("reply fuse failed {}", err); - - return Err(err); - } - } - - Ok(()) - } - #[instrument(level = "debug", skip(self, fs), ret, err)] async fn init_filesystem( &mut self, @@ -588,7 +641,9 @@ impl Session { Err(err) => { debug!("receive unknown opcode {}", err.0); - reply_error_in_place(libc::ENOSYS.into(), request, &self.response_sender).await; + self.response_sender() + .send_err(&request, libc::ENOSYS.into()) + .await; return Err(IoError::other(format!("receive unknown opcode {}", err.0))); } @@ -740,7 +795,9 @@ impl Session { Err(err) => { debug!("receive unknown opcode {}", err.0); - reply_error_in_place(libc::ENOSYS.into(), request, &self.response_sender).await; + self.response_sender() + .send_err(&request, libc::ENOSYS.into()) + .await; continue; } @@ -919,13 +976,13 @@ impl Session { } /*fuse_opcode::FUSE_IOCTL => { - let mut resp_sender = self.response_sender.clone(); + let mut resp_sender = self.response_sender().clone(); let ioctl_in = match fuse_ioctl_in::read_from_prefix(data) { Err(err) => { error!("deserialize fuse_ioctl_in failed {}", err); - reply_error_in_place(libc::EINVAL.into(), request, &self.response_sender).await; + self.response_sender2.send_err(&request, libc::EINVAL.into()).await; continue; } @@ -1280,7 +1337,9 @@ impl Session { None => { error!("lookup body has no null, request unique {}", request.unique); - reply_error_in_place(libc::EINVAL.into(), request, &self.response_sender).await; + self.response_sender() + .send_err(&request, libc::EINVAL.into()) + .await; return; } @@ -1288,7 +1347,7 @@ impl Session { Some(index) => OsString::from_vec(data[..index].to_vec()), }; - let mut resp_sender = self.response_sender.clone(); + let resp_sender = self.response_sender().clone(); let fs = fs.clone(); spawn(debug_span!("fuse_lookup"), async move { @@ -1297,17 +1356,10 @@ impl Session { request.unique, name, in_header.nodeid ); - let data = match fs.lookup(request, in_header.nodeid, &name).await { + match fs.lookup(request, in_header.nodeid, &name).await { Err(err) => { - let out_header = fuse_out_header { - len: FUSE_OUT_HEADER_SIZE as u32, - error: err.into(), - unique: request.unique, - }; - - out_header.as_bytes().to_vec() + resp_sender.send_err(&request, err).await; } - Ok(entry) => { let entry_out: fuse_entry_out = entry.into(); @@ -1319,16 +1371,9 @@ impl Session { unique: request.unique, }; - let mut data = Vec::with_capacity(FUSE_OUT_HEADER_SIZE + FUSE_ENTRY_OUT_SIZE); - - out_header.write_to_io(&mut data).unwrap(); - entry_out.write_to_io(&mut data).unwrap(); - - data + resp_sender.send2(&out_header, entry_out.as_bytes()).await; } }; - - let _ = resp_sender.send(Either::Left(data)).await; }); } @@ -1383,7 +1428,9 @@ impl Session { err, request.unique ); - reply_error_in_place(libc::EINVAL.into(), request, &self.response_sender).await; + self.response_sender() + .send_err(&request, libc::EINVAL.into()) + .await; return; } @@ -1391,7 +1438,7 @@ impl Session { Ok((getattr_in, _)) => getattr_in, }; - let mut resp_sender = self.response_sender.clone(); + let resp_sender = self.response_sender().clone(); let fs = fs.clone(); spawn(debug_span!("fuse_getattr"), async move { @@ -1406,20 +1453,13 @@ impl Session { None }; - let data = match fs + match fs .getattr(request, in_header.nodeid, fh, getattr_in.getattr_flags) .await { Err(err) => { - let out_header = fuse_out_header { - len: FUSE_OUT_HEADER_SIZE as u32, - error: err.into(), - unique: request.unique, - }; - - out_header.as_bytes().to_vec() + resp_sender.send_err(&request, err).await; } - Ok(attr) => { let attr_out = fuse_attr_out { attr_valid: attr.ttl.as_secs(), @@ -1434,16 +1474,9 @@ impl Session { unique: request.unique, }; - let mut data = Vec::with_capacity(FUSE_OUT_HEADER_SIZE + FUSE_ATTR_OUT_SIZE); - - out_header.write_to_io(&mut data).unwrap(); - attr_out.write_to_io(&mut data).unwrap(); - - data + resp_sender.send2(&out_header, attr_out.as_bytes()).await; } }; - - let _ = resp_sender.send(Either::Left(data)).await; }); } @@ -1462,7 +1495,9 @@ impl Session { err, request.unique ); - reply_error_in_place(libc::EINVAL.into(), request, &self.response_sender).await; + self.response_sender() + .send_err(&request, libc::EINVAL.into()) + .await; return; } @@ -1470,7 +1505,7 @@ impl Session { Ok((setattr_in, _)) => setattr_in, }; - let mut resp_sender = self.response_sender.clone(); + let resp_sender = self.response_sender().clone(); let fs = fs.clone(); spawn(debug_span!("fuse_setattr"), async move { @@ -1487,17 +1522,10 @@ impl Session { request.unique, in_header.nodeid, set_attr ); - let data = match fs.setattr(request, in_header.nodeid, fh, set_attr).await { + match fs.setattr(request, in_header.nodeid, fh, set_attr).await { Err(err) => { - let out_header = fuse_out_header { - len: FUSE_OUT_HEADER_SIZE as u32, - error: err.into(), - unique: request.unique, - }; - - out_header.as_bytes().to_vec() + resp_sender.send_err(&request, err).await; } - Ok(attr) => { let attr_out: fuse_attr_out = attr.into(); @@ -1507,22 +1535,15 @@ impl Session { unique: request.unique, }; - let mut data = Vec::with_capacity(FUSE_OUT_HEADER_SIZE + FUSE_ATTR_OUT_SIZE); - - out_header.write_to_io(&mut data).unwrap(); - attr_out.write_to_io(&mut data).unwrap(); - - data + resp_sender.send2(&out_header, attr_out.as_bytes()).await; } }; - - let _ = resp_sender.send(Either::Left(data)).await; }); } #[instrument(skip(self, fs))] async fn handle_readlink(&mut self, request: Request, in_header: fuse_in_header, fs: &Arc) { - let mut resp_sender = self.response_sender.clone(); + let resp_sender = self.response_sender().clone(); let fs = fs.clone(); spawn(debug_span!("fuse_readlink"), async move { @@ -1531,17 +1552,10 @@ impl Session { request.unique, in_header.nodeid ); - let data = match fs.readlink(request, in_header.nodeid).await { + match fs.readlink(request, in_header.nodeid).await { Err(err) => { - let out_header = fuse_out_header { - len: FUSE_OUT_HEADER_SIZE as u32, - error: err.into(), - unique: request.unique, - }; - - Either::Left(out_header.as_bytes().to_vec()) + resp_sender.send_err(&request, err).await; } - Ok(data) => { let out_header = fuse_out_header { len: (FUSE_OUT_HEADER_SIZE + data.data.len()) as u32, @@ -1549,15 +1563,9 @@ impl Session { unique: request.unique, }; - let mut data_buf = Vec::with_capacity(FUSE_OUT_HEADER_SIZE); - - out_header.write_to_io(&mut data_buf).unwrap(); - - Either::Right((data_buf, data.data)) + resp_sender.send2(&out_header, &data.data).await; } }; - - let _ = resp_sender.send(data).await; }); } @@ -1573,7 +1581,9 @@ impl Session { None => { error!("symlink has no null, request unique {}", request.unique); - reply_error_in_place(libc::EINVAL.into(), request, &self.response_sender).await; + self.response_sender() + .send_err(&request, libc::EINVAL.into()) + .await; return; } @@ -1590,7 +1600,9 @@ impl Session { request.unique ); - reply_error_in_place(libc::EINVAL.into(), request, &self.response_sender).await; + self.response_sender() + .send_err(&request, libc::EINVAL.into()) + .await; return; } @@ -1598,7 +1610,7 @@ impl Session { Some(index) => OsString::from_vec(data[..index].to_vec()), }; - let mut resp_sender = self.response_sender.clone(); + let resp_sender = self.response_sender().clone(); let fs = fs.clone(); spawn(debug_span!("fuse_symlink"), async move { @@ -1607,18 +1619,12 @@ impl Session { request.unique, in_header.nodeid, name, link_name ); - let data = match fs + match fs .symlink(request, in_header.nodeid, &name, &link_name) .await { Err(err) => { - let out_header = fuse_out_header { - len: FUSE_OUT_HEADER_SIZE as u32, - error: err.into(), - unique: request.unique, - }; - - out_header.as_bytes().to_vec() + resp_sender.send_err(&request, err).await; } Ok(entry) => { @@ -1630,16 +1636,9 @@ impl Session { unique: request.unique, }; - let mut data = Vec::with_capacity(FUSE_OUT_HEADER_SIZE + FUSE_ENTRY_OUT_SIZE); - - out_header.write_to_io(&mut data).unwrap(); - entry_out.write_to_io(&mut data).unwrap(); - - data + resp_sender.send2(&out_header, entry_out.as_bytes()).await; } }; - - let _ = resp_sender.send(Either::Left(data)).await; }); } @@ -1658,7 +1657,9 @@ impl Session { err, request.unique ); - reply_error_in_place(libc::EINVAL.into(), request, &self.response_sender).await; + self.response_sender() + .send_err(&request, libc::EINVAL.into()) + .await; return; } @@ -1673,7 +1674,9 @@ impl Session { request.unique ); - reply_error_in_place(libc::EINVAL.into(), request, &self.response_sender).await; + self.response_sender() + .send_err(&request, libc::EINVAL.into()) + .await; return; } @@ -1681,7 +1684,7 @@ impl Session { Some(index) => OsString::from_vec(data[..index].to_vec()), }; - let mut resp_sender = self.response_sender.clone(); + let resp_sender = self.response_sender().clone(); let fs = fs.clone(); spawn(debug_span!("fuse_mknod"), async move { @@ -1701,7 +1704,7 @@ impl Session { .await { Err(err) => { - reply_error_in_place(err, request, resp_sender).await; + resp_sender.send_err(&request, err).await; } Ok(entry) => { @@ -1713,12 +1716,7 @@ impl Session { unique: request.unique, }; - let mut data = Vec::with_capacity(FUSE_OUT_HEADER_SIZE + FUSE_ENTRY_OUT_SIZE); - - out_header.write_to_io(&mut data).unwrap(); - entry_out.write_to_io(&mut data).unwrap(); - - let _ = resp_sender.send(Either::Left(data)).await; + resp_sender.send2(&out_header, entry_out.as_bytes()).await; } } }); @@ -1739,7 +1737,9 @@ impl Session { err, request.unique ); - reply_error_in_place(libc::EINVAL.into(), request, &self.response_sender).await; + self.response_sender() + .send_err(&request, libc::EINVAL.into()) + .await; return; } @@ -1754,7 +1754,9 @@ impl Session { request.unique ); - reply_error_in_place(libc::EINVAL.into(), request, &self.response_sender).await; + self.response_sender() + .send_err(&request, libc::EINVAL.into()) + .await; return; } @@ -1762,7 +1764,7 @@ impl Session { Some(index) => OsString::from_vec(data[..index].to_vec()), }; - let mut resp_sender = self.response_sender.clone(); + let resp_sender = self.response_sender().clone(); let fs = fs.clone(); spawn(debug_span!("fuse_mkdir"), async move { @@ -1782,7 +1784,7 @@ impl Session { .await { Err(err) => { - reply_error_in_place(err, request, resp_sender).await; + resp_sender.send_err(&request, err).await; } Ok(entry) => { @@ -1799,7 +1801,7 @@ impl Session { out_header.write_to_io(&mut data).unwrap(); entry_out.write_to_io(&mut data).unwrap(); - let _ = resp_sender.send(Either::Left(data)).await; + resp_sender.send2(&out_header, entry_out.as_bytes()).await; } } }); @@ -1820,7 +1822,9 @@ impl Session { request.unique ); - reply_error_in_place(libc::EINVAL.into(), request, &self.response_sender).await; + self.response_sender() + .send_err(&request, libc::EINVAL.into()) + .await; return; } @@ -1828,7 +1832,7 @@ impl Session { Some(index) => OsString::from_vec(data[..index].to_vec()), }; - let mut resp_sender = self.response_sender.clone(); + let resp_sender = self.response_sender().clone(); let fs = fs.clone(); spawn(debug_span!("fuse_unlink"), async move { @@ -1849,9 +1853,7 @@ impl Session { unique: request.unique, }; - let data = out_header.as_bytes().to_vec(); - - let _ = resp_sender.send(Either::Left(data)).await; + let _ = resp_sender.send1(&out_header).await; }); } @@ -1870,7 +1872,9 @@ impl Session { request.unique ); - reply_error_in_place(libc::EINVAL.into(), request, &self.response_sender).await; + self.response_sender() + .send_err(&request, libc::EINVAL.into()) + .await; return; } @@ -1878,7 +1882,7 @@ impl Session { Some(index) => OsString::from_vec(data[..index].to_vec()), }; - let mut resp_sender = self.response_sender.clone(); + let resp_sender = self.response_sender().clone(); let fs = fs.clone(); spawn(debug_span!("fuse_rmdir"), async move { @@ -1899,9 +1903,7 @@ impl Session { unique: request.unique, }; - let data = out_header.as_bytes().to_vec(); - - let _ = resp_sender.send(Either::Left(data)).await; + let _ = resp_sender.send1(&out_header).await; }); } @@ -1920,7 +1922,9 @@ impl Session { err, request.unique ); - reply_error_in_place(libc::EINVAL.into(), request, &self.response_sender).await; + self.response_sender() + .send_err(&request, libc::EINVAL.into()) + .await; return; } @@ -1935,7 +1939,9 @@ impl Session { request.unique ); - reply_error_in_place(libc::EINVAL.into(), request, &self.response_sender).await; + self.response_sender() + .send_err(&request, libc::EINVAL.into()) + .await; return; } @@ -1952,7 +1958,9 @@ impl Session { request.unique ); - reply_error_in_place(libc::EINVAL.into(), request, &self.response_sender).await; + self.response_sender() + .send_err(&request, libc::EINVAL.into()) + .await; return; } @@ -1960,7 +1968,7 @@ impl Session { Some(index) => OsString::from_vec(data[..index].to_vec()), }; - let mut resp_sender = self.response_sender.clone(); + let resp_sender = self.response_sender().clone(); let fs = fs.clone(); spawn(debug_span!("fuse_rename"), async move { @@ -1990,9 +1998,7 @@ impl Session { unique: request.unique, }; - let data = out_header.as_bytes().to_vec(); - - let _ = resp_sender.send(Either::Left(data)).await; + let _ = resp_sender.send1(&out_header).await; }); } @@ -2011,7 +2017,9 @@ impl Session { err, request.unique ); - reply_error_in_place(libc::EINVAL.into(), request, &self.response_sender).await; + self.response_sender() + .send_err(&request, libc::EINVAL.into()) + .await; return; } @@ -2026,7 +2034,9 @@ impl Session { request.unique ); - reply_error_in_place(libc::EINVAL.into(), request, &self.response_sender).await; + self.response_sender() + .send_err(&request, libc::EINVAL.into()) + .await; return; } @@ -2034,7 +2044,7 @@ impl Session { Some(index) => OsString::from_vec(data[..index].to_vec()), }; - let mut resp_sender = self.response_sender.clone(); + let resp_sender = self.response_sender().clone(); let fs = fs.clone(); spawn(debug_span!("fuse_link"), async move { @@ -2048,7 +2058,7 @@ impl Session { .await { Err(err) => { - reply_error_in_place(err, request, resp_sender).await; + resp_sender.send_err(&request, err).await; } Ok(entry) => { @@ -2060,12 +2070,7 @@ impl Session { unique: request.unique, }; - let mut data = Vec::with_capacity(FUSE_OUT_HEADER_SIZE + FUSE_ENTRY_OUT_SIZE); - - out_header.write_to_io(&mut data).unwrap(); - entry_out.write_to_io(&mut data).unwrap(); - - let _ = resp_sender.send(Either::Left(data)).await; + resp_sender.send2(&out_header, entry_out.as_bytes()).await; } } }); @@ -2086,7 +2091,9 @@ impl Session { err, request.unique ); - reply_error_in_place(libc::EINVAL.into(), request, &self.response_sender).await; + self.response_sender() + .send_err(&request, libc::EINVAL.into()) + .await; return; } @@ -2094,7 +2101,7 @@ impl Session { Ok((open_in, _)) => open_in, }; - let mut resp_sender = self.response_sender.clone(); + let resp_sender = self.response_sender().clone(); let fs = fs.clone(); spawn(debug_span!("fuse_open"), async move { @@ -2105,8 +2112,7 @@ impl Session { let opened = match fs.open(request, in_header.nodeid, open_in.flags).await { Err(err) => { - reply_error_in_place(err, request, resp_sender).await; - + resp_sender.send_err(&request, err).await; return; } @@ -2121,12 +2127,7 @@ impl Session { unique: request.unique, }; - let mut data = Vec::with_capacity(FUSE_OUT_HEADER_SIZE + FUSE_OPEN_OUT_SIZE); - - out_header.write_to_io(&mut data).unwrap(); - open_out.write_to_io(&mut data).unwrap(); - - let _ = resp_sender.send(Either::Left(data)).await; + resp_sender.send2(&out_header, open_out.as_bytes()).await; }); } @@ -2145,7 +2146,9 @@ impl Session { err, request.unique ); - reply_error_in_place(libc::EINVAL.into(), request, &self.response_sender).await; + self.response_sender() + .send_err(&request, libc::EINVAL.into()) + .await; return; } @@ -2153,7 +2156,7 @@ impl Session { Ok((read_in, _)) => read_in, }; - let mut resp_sender = self.response_sender.clone(); + let resp_sender = self.response_sender().clone(); let fs = fs.clone(); spawn(debug_span!("fuse_read"), async move { @@ -2173,8 +2176,7 @@ impl Session { .await { Err(err) => { - reply_error_in_place(err, request, resp_sender).await; - + resp_sender.send_err(&request, err).await; return; } @@ -2191,13 +2193,7 @@ impl Session { unique: request.unique, }; - let mut data_buf = Vec::with_capacity(FUSE_OUT_HEADER_SIZE); - - out_header.write_to_io(&mut data_buf).unwrap(); - - let _ = resp_sender - .send(Either::Right((data_buf, reply_data))) - .await; + resp_sender.send2(&out_header, &reply_data).await; }); } @@ -2216,7 +2212,9 @@ impl Session { err, request.unique ); - reply_error_in_place(libc::EINVAL.into(), request, &self.response_sender).await; + self.response_sender() + .send_err(&request, libc::EINVAL.into()) + .await; return; } @@ -2227,14 +2225,16 @@ impl Session { if write_in.size as usize != data.len() { error!("fuse_write_in body len is invalid"); - reply_error_in_place(libc::EINVAL.into(), request, &self.response_sender).await; + self.response_sender() + .send_err(&request, libc::EINVAL.into()) + .await; return; } let data = data.to_vec(); - let mut resp_sender = self.response_sender.clone(); + let resp_sender = self.response_sender().clone(); let fs = fs.clone(); spawn(debug_span!("fuse_write"), async move { @@ -2256,8 +2256,7 @@ impl Session { .await { Err(err) => { - reply_error_in_place(err, request, resp_sender).await; - + resp_sender.send_err(&request, err).await; return; } @@ -2272,18 +2271,13 @@ impl Session { unique: request.unique, }; - let mut data = Vec::with_capacity(FUSE_OUT_HEADER_SIZE + FUSE_WRITE_OUT_SIZE); - - out_header.write_to_io(&mut data).unwrap(); - write_out.write_to_io(&mut data).unwrap(); - - let _ = resp_sender.send(Either::Left(data)).await; + resp_sender.send2(&out_header, write_out.as_bytes()).await; }); } #[instrument(skip(self, fs))] async fn handle_statfs(&mut self, request: Request, in_header: fuse_in_header, fs: &Arc) { - let mut resp_sender = self.response_sender.clone(); + let resp_sender = self.response_sender().clone(); let fs = fs.clone(); spawn(debug_span!("fuse_statfs"), async move { @@ -2294,8 +2288,7 @@ impl Session { let fs_stat = match fs.statfs(request, in_header.nodeid).await { Err(err) => { - reply_error_in_place(err, request, resp_sender).await; - + resp_sender.send_err(&request, err).await; return; } @@ -2310,12 +2303,7 @@ impl Session { unique: request.unique, }; - let mut data = Vec::with_capacity(FUSE_OUT_HEADER_SIZE + FUSE_STATFS_OUT_SIZE); - - out_header.write_to_io(&mut data).unwrap(); - statfs_out.write_to_io(&mut data).unwrap(); - - let _ = resp_sender.send(Either::Left(data)).await; + let _ = resp_sender.send2(&out_header, statfs_out.as_bytes()).await; }); } @@ -2334,7 +2322,9 @@ impl Session { err, request.unique ); - reply_error_in_place(libc::EINVAL.into(), request, &self.response_sender).await; + self.response_sender() + .send_err(&request, libc::EINVAL.into()) + .await; return; } @@ -2342,7 +2332,7 @@ impl Session { Ok((release_in, _)) => release_in, }; - let mut resp_sender = self.response_sender.clone(); + let resp_sender = self.response_sender().clone(); let fs = fs.clone(); spawn(debug_span!("fuse_release"), async move { @@ -2380,9 +2370,7 @@ impl Session { unique: request.unique, }; - let data = out_header.as_bytes().to_vec(); - - let _ = resp_sender.send(Either::Left(data)).await; + let _ = resp_sender.send1(&out_header).await; }); } @@ -2401,7 +2389,9 @@ impl Session { err, request.unique ); - reply_error_in_place(libc::EINVAL.into(), request, &self.response_sender).await; + self.response_sender() + .send_err(&request, libc::EINVAL.into()) + .await; return; } @@ -2409,7 +2399,7 @@ impl Session { Ok((fsync_in, _)) => fsync_in, }; - let mut resp_sender = self.response_sender.clone(); + let resp_sender = self.response_sender().clone(); let fs = fs.clone(); spawn(debug_span!("fuse_fsync"), async move { @@ -2435,9 +2425,7 @@ impl Session { unique: request.unique, }; - let data = out_header.as_bytes().to_vec(); - - let _ = resp_sender.send(Either::Left(data)).await; + let _ = resp_sender.send1(&out_header).await; }); } @@ -2456,7 +2444,9 @@ impl Session { err, request.unique ); - reply_error_in_place(libc::EINVAL.into(), request, &self.response_sender).await; + self.response_sender() + .send_err(&request, libc::EINVAL.into()) + .await; return; } @@ -2471,7 +2461,9 @@ impl Session { request.unique ); - reply_error_in_place(libc::EINVAL.into(), request, &self.response_sender).await; + self.response_sender() + .send_err(&request, libc::EINVAL.into()) + .await; return; } @@ -2486,14 +2478,16 @@ impl Session { error!( "fuse_setxattr_in value field data length is not right, request unique {} setxattr_in.size={} data.len={}", request.unique, setxattr_in.size, data.len()); - reply_error_in_place(libc::EINVAL.into(), request, &self.response_sender).await; + self.response_sender() + .send_err(&request, libc::EINVAL.into()) + .await; return; } let data = data.to_vec(); - let mut resp_sender = self.response_sender.clone(); + let resp_sender = self.response_sender().clone(); let fs = fs.clone(); spawn(debug_span!("fuse_setxattr"), async move { @@ -2525,9 +2519,7 @@ impl Session { unique: request.unique, }; - let data = out_header.as_bytes().to_vec(); - - let _ = resp_sender.send(Either::Left(data)).await; + let _ = resp_sender.send1(&out_header).await; }); } @@ -2546,7 +2538,9 @@ impl Session { err, request.unique ); - reply_error_in_place(libc::EINVAL.into(), request, &self.response_sender).await; + self.response_sender() + .send_err(&request, libc::EINVAL.into()) + .await; return; } @@ -2558,7 +2552,9 @@ impl Session { None => { error!("fuse_getxattr_in body has no null {}", request.unique); - reply_error_in_place(libc::EINVAL.into(), request, &self.response_sender).await; + self.response_sender() + .send_err(&request, libc::EINVAL.into()) + .await; return; } @@ -2566,7 +2562,7 @@ impl Session { Some(index) => OsString::from_vec(data[..index].to_vec()), }; - let mut resp_sender = self.response_sender.clone(); + let resp_sender = self.response_sender().clone(); let fs = fs.clone(); spawn(debug_span!("fuse_getxattr"), async move { @@ -2580,15 +2576,14 @@ impl Session { .await { Err(err) => { - reply_error_in_place(err, request, resp_sender).await; - + resp_sender.send_err(&request, err).await; return; } Ok(xattr) => xattr, }; - let data = match xattr { + match xattr { ReplyXAttr::Size(size) => { let getxattr_out = fuse_getxattr_out { size, _padding: 0 }; @@ -2598,12 +2593,9 @@ impl Session { unique: request.unique, }; - let mut data = Vec::with_capacity(FUSE_OUT_HEADER_SIZE + FUSE_STATFS_OUT_SIZE); - - out_header.write_to_io(&mut data).unwrap(); - getxattr_out.write_to_io(&mut data).unwrap(); - - Either::Left(data) + resp_sender + .send2(&out_header, getxattr_out.as_bytes()) + .await; } ReplyXAttr::Data(xattr_data) => { @@ -2614,16 +2606,9 @@ impl Session { error: 0, unique: request.unique, }; - - let mut data = Vec::with_capacity(FUSE_OUT_HEADER_SIZE); - - out_header.write_to_io(&mut data).unwrap(); - - Either::Right((data, xattr_data)) + resp_sender.send2(&out_header, &xattr_data).await; } }; - - let _ = resp_sender.send(data).await; }); } @@ -2642,7 +2627,9 @@ impl Session { err, request.unique ); - reply_error_in_place(libc::EINVAL.into(), request, &self.response_sender).await; + self.response_sender() + .send_err(&request, libc::EINVAL.into()) + .await; return; } @@ -2650,7 +2637,7 @@ impl Session { Ok((listxattr_in, _)) => listxattr_in, }; - let mut resp_sender = self.response_sender.clone(); + let resp_sender = self.response_sender().clone(); let fs = fs.clone(); spawn(debug_span!("fuse_listxattr"), async move { @@ -2664,15 +2651,14 @@ impl Session { .await { Err(err) => { - reply_error_in_place(err, request, resp_sender).await; - + resp_sender.send_err(&request, err).await; return; } Ok(xattr) => xattr, }; - let data = match xattr { + match xattr { ReplyXAttr::Size(size) => { let getxattr_out = fuse_getxattr_out { size, _padding: 0 }; @@ -2682,12 +2668,9 @@ impl Session { unique: request.unique, }; - let mut data = Vec::with_capacity(FUSE_OUT_HEADER_SIZE + FUSE_STATFS_OUT_SIZE); - - out_header.write_to_io(&mut data).unwrap(); - getxattr_out.write_to_io(&mut data).unwrap(); - - Either::Left(data) + resp_sender + .send2(&out_header, getxattr_out.as_bytes()) + .await; } ReplyXAttr::Data(xattr_data) => { @@ -2699,15 +2682,9 @@ impl Session { unique: request.unique, }; - let mut data = Vec::with_capacity(FUSE_OUT_HEADER_SIZE); - - out_header.write_to_io(&mut data).unwrap(); - - Either::Right((data, xattr_data)) + resp_sender.send2(&out_header, &xattr_data).await; } }; - - let _ = resp_sender.send(data).await; }); } @@ -2726,7 +2703,9 @@ impl Session { request.unique ); - reply_error_in_place(libc::EINVAL.into(), request, &self.response_sender).await; + self.response_sender() + .send_err(&request, libc::EINVAL.into()) + .await; return; } @@ -2734,7 +2713,7 @@ impl Session { Some(index) => OsString::from_vec(data[..index].to_vec()), }; - let mut resp_sender = self.response_sender.clone(); + let resp_sender = self.response_sender().clone(); let fs = fs.clone(); spawn(debug_span!("fuse_removexattr"), async move { @@ -2756,9 +2735,7 @@ impl Session { unique: request.unique, }; - let data = out_header.as_bytes().to_vec(); - - let _ = resp_sender.send(Either::Left(data)).await; + let _ = resp_sender.send1(&out_header).await; }); } @@ -2777,7 +2754,9 @@ impl Session { err, request.unique ); - reply_error_in_place(libc::EINVAL.into(), request, &self.response_sender).await; + self.response_sender() + .send_err(&request, libc::EINVAL.into()) + .await; return; } @@ -2785,7 +2764,7 @@ impl Session { Ok((flush_in, _)) => flush_in, }; - let mut resp_sender = self.response_sender.clone(); + let resp_sender = self.response_sender().clone(); let fs = fs.clone(); spawn(debug_span!("fuse_flush"), async move { @@ -2809,9 +2788,7 @@ impl Session { unique: request.unique, }; - let data = out_header.as_bytes().to_vec(); - - let _ = resp_sender.send(Either::Left(data)).await; + resp_sender.send1(&out_header).await; }); } @@ -2830,7 +2807,9 @@ impl Session { err, request.unique ); - reply_error_in_place(libc::EINVAL.into(), request, &self.response_sender).await; + self.response_sender() + .send_err(&request, libc::EINVAL.into()) + .await; return; } @@ -2838,7 +2817,7 @@ impl Session { Ok((open_in, _)) => open_in, }; - let mut resp_sender = self.response_sender.clone(); + let resp_sender = self.response_sender().clone(); let fs = fs.clone(); spawn(debug_span!("fuse_opendir"), async move { @@ -2849,8 +2828,7 @@ impl Session { let reply_open = match fs.opendir(request, in_header.nodeid, open_in.flags).await { Err(err) => { - reply_error_in_place(err, request, resp_sender).await; - + resp_sender.send_err(&request, err).await; return; } @@ -2865,12 +2843,7 @@ impl Session { unique: request.unique, }; - let mut data = Vec::with_capacity(FUSE_OUT_HEADER_SIZE + FUSE_OPEN_OUT_SIZE); - - out_header.write_to_io(&mut data).unwrap(); - open_out.write_to_io(&mut data).unwrap(); - - let _ = resp_sender.send(Either::Left(data)).await; + let _ = resp_sender.send2(&out_header, open_out.as_bytes()).await; }); } @@ -2883,7 +2856,9 @@ impl Session { fs: &Arc, ) { if self.mount_options.force_readdir_plus { - reply_error_in_place(libc::ENOSYS.into(), request, &self.response_sender).await; + self.response_sender() + .send_err(&request, libc::ENOSYS.into()) + .await; return; } @@ -2895,15 +2870,16 @@ impl Session { err, request.unique ); - reply_error_in_place(libc::EINVAL.into(), request, &self.response_sender).await; - + self.response_sender() + .send_err(&request, libc::EINVAL.into()) + .await; return; } Ok((read_in, _)) => read_in, }; - let mut resp_sender = self.response_sender.clone(); + let resp_sender = self.response_sender().clone(); let fs = fs.clone(); spawn(debug_span!("fuse_readdir"), async move { @@ -2917,8 +2893,7 @@ impl Session { .await { Err(err) => { - reply_error_in_place(err, request, resp_sender).await; - + resp_sender.send_err(&request, err).await; return; } @@ -2935,8 +2910,7 @@ impl Session { while let Some(entry) = entries.next().await { let entry = match entry { Err(err) => { - reply_error_in_place(err, request, resp_sender).await; - + resp_sender.send_err(&request, err).await; return; } @@ -2969,21 +2943,13 @@ impl Session { entry_data.resize(entry_data.len() + padding_size, 0); } - // TODO find a way to avoid multi allocate - let out_header = fuse_out_header { len: (FUSE_OUT_HEADER_SIZE + entry_data.len()) as u32, error: 0, unique: request.unique, }; - let mut data = Vec::with_capacity(FUSE_OUT_HEADER_SIZE); - - out_header.write_to_io(&mut data).unwrap(); - - let _ = resp_sender - .send(Either::Right((data, entry_data.into()))) - .await; + let _ = resp_sender.send2(&out_header, &entry_data).await; }); } @@ -3002,7 +2968,9 @@ impl Session { err, request.unique ); - reply_error_in_place(libc::EINVAL.into(), request, &self.response_sender).await; + self.response_sender() + .send_err(&request, libc::EINVAL.into()) + .await; return; } @@ -3010,7 +2978,7 @@ impl Session { Ok((release_in, _)) => release_in, }; - let mut resp_sender = self.response_sender.clone(); + let resp_sender = self.response_sender().clone(); let fs = fs.clone(); spawn(debug_span!("fuse_releasedir"), async move { @@ -3034,9 +3002,7 @@ impl Session { unique: request.unique, }; - let data = out_header.as_bytes().to_vec(); - - let _ = resp_sender.send(Either::Left(data)).await; + let _ = resp_sender.send1(&out_header).await; }); } @@ -3055,7 +3021,9 @@ impl Session { err, request.unique ); - reply_error_in_place(libc::EINVAL.into(), request, &self.response_sender).await; + self.response_sender() + .send_err(&request, libc::EINVAL.into()) + .await; return; } @@ -3063,7 +3031,7 @@ impl Session { Ok((fsync_in, _)) => fsync_in, }; - let mut resp_sender = self.response_sender.clone(); + let resp_sender = self.response_sender().clone(); let fs = fs.clone(); spawn(debug_span!("fuse_fsyncdir"), async move { @@ -3089,9 +3057,7 @@ impl Session { unique: request.unique, }; - let data = out_header.as_bytes().to_vec(); - - let _ = resp_sender.send(Either::Left(data)).await; + resp_sender.send1(&out_header).await; }); } @@ -3111,15 +3077,17 @@ impl Session { err, request.unique ); - reply_error_in_place(libc::EINVAL.into(), request, &self.response_sender).await; + self.response_sender() + .send_err(&request, libc::EINVAL.into()) + .await; return; } - Ok(getlk_in) => getlk_in, + Ok((getlk_in, _)) => getlk_in, }; - let mut resp_sender = self.response_sender.clone(); + let resp_sender = self.response_sender().clone(); let fs = fs.clone(); spawn(debug_span!("fuse_getlk"), async move { @@ -3142,8 +3110,7 @@ impl Session { .await { Err(err) => { - reply_error_in_place(err, request, resp_sender).await; - + resp_sender.send_err(&request, err).await; return; } @@ -3158,12 +3125,7 @@ impl Session { unique: request.unique, }; - let mut data = Vec::with_capacity(FUSE_OUT_HEADER_SIZE + FUSE_LK_OUT_SIZE); - - out_header.write_to_io(&mut data).unwrap(); - getlk_out.write_to_io(&mut data).unwrap(); - - let _ = resp_sender.send(Either::Left(data)).await; + resp_sender.send2(&out_header, getlk_out.as_bytes()).await; }); } @@ -3190,15 +3152,17 @@ impl Session { opcode, err, request.unique ); - reply_error_in_place(libc::EINVAL.into(), request, &self.response_sender).await; + self.response_sender() + .send_err(&request, libc::EINVAL.into()) + .await; return; } - Ok(setlk_in) => setlk_in, + Ok((setlk_in, _)) => setlk_in, }; - let mut resp_sender = self.response_sender.clone(); + let resp_sender = self.response_sender().clone(); let fs = fs.clone(); spawn(debug_span!("fuse_setlk"), async move { @@ -3232,9 +3196,7 @@ impl Session { unique: request.unique, }; - let data = out_header.as_bytes().to_vec(); - - let _ = resp_sender.send(Either::Left(data)).await; + let _ = resp_sender.send1(&out_header).await; }); } @@ -3253,7 +3215,9 @@ impl Session { err, request.unique ); - reply_error_in_place(libc::EINVAL.into(), request, &self.response_sender).await; + self.response_sender() + .send_err(&request, libc::EINVAL.into()) + .await; return; } @@ -3261,7 +3225,7 @@ impl Session { Ok((access_in, _)) => access_in, }; - let mut resp_sender = self.response_sender.clone(); + let resp_sender = self.response_sender().clone(); let fs = fs.clone(); spawn(debug_span!("fuse_access"), async move { @@ -3285,9 +3249,7 @@ impl Session { debug!("access response {}", resp_value); - let data = out_header.as_bytes().to_vec(); - - let _ = resp_sender.send(Either::Left(data)).await; + let _ = resp_sender.send1(&out_header).await; }); } @@ -3306,7 +3268,9 @@ impl Session { err, request.unique ); - reply_error_in_place(libc::EINVAL.into(), request, &self.response_sender).await; + self.response_sender() + .send_err(&request, libc::EINVAL.into()) + .await; return; } @@ -3321,7 +3285,9 @@ impl Session { request.unique ); - reply_error_in_place(libc::EINVAL.into(), request, &self.response_sender).await; + self.response_sender() + .send_err(&request, libc::EINVAL.into()) + .await; return; } @@ -3329,7 +3295,7 @@ impl Session { Some(index) => OsString::from_vec(data[..index].to_vec()), }; - let mut resp_sender = self.response_sender.clone(); + let resp_sender = self.response_sender().clone(); let fs = fs.clone(); spawn(debug_span!("fuse_create"), async move { @@ -3349,8 +3315,7 @@ impl Session { .await { Err(err) => { - reply_error_in_place(err, request, resp_sender).await; - + resp_sender.send_err(&request, err).await; return; } @@ -3365,14 +3330,9 @@ impl Session { unique: request.unique, }; - let mut data = - Vec::with_capacity(FUSE_OUT_HEADER_SIZE + FUSE_ENTRY_OUT_SIZE + FUSE_OPEN_OUT_SIZE); - - out_header.write_to_io(&mut data).unwrap(); - entry_out.write_to_io(&mut data).unwrap(); - open_out.write_to_io(&mut data).unwrap(); - - let _ = resp_sender.send(Either::Left(data)).await; + let _ = resp_sender + .send3(&out_header, entry_out.as_bytes(), open_out.as_bytes()) + .await; }); } @@ -3385,7 +3345,9 @@ impl Session { err, request.unique ); - reply_error_in_place(libc::EINVAL.into(), request, &self.response_sender).await; + self.response_sender() + .send_err(&request, libc::EINVAL.into()) + .await; return; } @@ -3393,7 +3355,7 @@ impl Session { Ok((interrupt_in, _)) => interrupt_in, }; - let mut resp_sender = self.response_sender.clone(); + let resp_sender = self.response_sender().clone(); let fs = fs.clone(); spawn(debug_span!("fuse_interrupt"), async move { @@ -3414,9 +3376,7 @@ impl Session { unique: request.unique, }; - let data = out_header.as_bytes().to_vec(); - - let _ = resp_sender.send(Either::Left(data)).await; + let _ = resp_sender.send1(&out_header).await; }); } @@ -3435,7 +3395,9 @@ impl Session { err, request.unique ); - reply_error_in_place(libc::EINVAL.into(), request, &self.response_sender).await; + self.response_sender() + .send_err(&request, libc::EINVAL.into()) + .await; return; } @@ -3443,7 +3405,7 @@ impl Session { Ok((bmap_in, _)) => bmap_in, }; - let mut resp_sender = self.response_sender.clone(); + let resp_sender = self.response_sender().clone(); let fs = fs.clone(); spawn(debug_span!("fuse_bmap"), async move { @@ -3457,8 +3419,7 @@ impl Session { .await { Err(err) => { - reply_error_in_place(err, request, resp_sender).await; - + resp_sender.send_err(&request, err).await; return; } @@ -3473,12 +3434,7 @@ impl Session { unique: request.unique, }; - let mut data = Vec::with_capacity(FUSE_OUT_HEADER_SIZE + FUSE_BMAP_OUT_SIZE); - - out_header.write_to_io(&mut data).unwrap(); - bmap_out.write_to_io(&mut data).unwrap(); - - let _ = resp_sender.send(Either::Left(data)).await; + let _ = resp_sender.send2(&out_header, bmap_out.as_bytes()).await; }); } @@ -3497,7 +3453,9 @@ impl Session { err, request.unique ); - reply_error_in_place(libc::EINVAL.into(), request, &self.response_sender).await; + self.response_sender() + .send_err(&request, libc::EINVAL.into()) + .await; return; } @@ -3505,7 +3463,7 @@ impl Session { Ok((poll_in, _)) => poll_in, }; - let mut resp_sender = self.response_sender.clone(); + let resp_sender = self.response_sender().clone(); let fs = fs.clone(); let notify = self.get_notify(); @@ -3535,8 +3493,7 @@ impl Session { .await { Err(err) => { - reply_error_in_place(err, request, resp_sender).await; - + resp_sender.send_err(&request, err).await; return; } @@ -3551,12 +3508,7 @@ impl Session { unique: request.unique, }; - let mut data = Vec::with_capacity(FUSE_OUT_HEADER_SIZE + FUSE_POLL_OUT_SIZE); - - out_header.write_to_io(&mut data).unwrap(); - poll_out.write_to_io(&mut data).unwrap(); - - let _ = resp_sender.send(Either::Left(data)).await; + let _ = resp_sender.send2(&out_header, poll_out.as_bytes()).await; }); } @@ -3568,7 +3520,7 @@ impl Session { data: &[u8], fs: &Arc, ) { - let resp_sender = self.response_sender.clone(); + let resp_sender = self.response_sender().clone(); let (notify_retrieve_in, data) = match fuse_notify_retrieve_in::read_from_prefix(data) { Err(err) => { @@ -3608,7 +3560,7 @@ impl Session { ) .await { - reply_error_in_place(err, request, resp_sender).await; + resp_sender.send_err(&request, err).await; } }); } @@ -3693,7 +3645,9 @@ impl Session { err, request.unique ); - reply_error_in_place(libc::EINVAL.into(), request, &self.response_sender).await; + self.response_sender() + .send_err(&request, libc::EINVAL.into()) + .await; return; } @@ -3701,7 +3655,7 @@ impl Session { Ok((fallocate_in, _)) => fallocate_in, }; - let mut resp_sender = self.response_sender.clone(); + let resp_sender = self.response_sender().clone(); let fs = fs.clone(); spawn(debug_span!("fuse_fallocate"), async move { @@ -3732,9 +3686,7 @@ impl Session { unique: request.unique, }; - let data = out_header.as_bytes().to_vec(); - - let _ = resp_sender.send(Either::Left(data)).await; + resp_sender.send1(&out_header).await; }); } @@ -3753,7 +3705,9 @@ impl Session { err, request.unique ); - reply_error_in_place(libc::EINVAL.into(), request, &self.response_sender).await; + self.response_sender() + .send_err(&request, libc::EINVAL.into()) + .await; return; } @@ -3761,7 +3715,7 @@ impl Session { Ok((readdirplus_in, _)) => readdirplus_in, }; - let mut resp_sender = self.response_sender.clone(); + let resp_sender = self.response_sender().clone(); let fs = fs.clone(); spawn(debug_span!("fuse_readdirplus"), async move { @@ -3781,8 +3735,7 @@ impl Session { .await { Err(err) => { - reply_error_in_place(err, request, resp_sender).await; - + resp_sender.send_err(&request, err).await; return; } @@ -3799,8 +3752,7 @@ impl Session { while let Some(entry) = entries.next().await { let entry = match entry { Err(err) => { - reply_error_in_place(err, request, resp_sender).await; - + resp_sender.send_err(&request, err).await; return; } @@ -3846,21 +3798,13 @@ impl Session { entry_data.resize(entry_data.len() + padding_size, 0); } - // TODO find a way to avoid multi allocate - let out_header = fuse_out_header { len: (FUSE_OUT_HEADER_SIZE + entry_data.len()) as u32, error: 0, unique: request.unique, }; - let mut data = Vec::with_capacity(FUSE_OUT_HEADER_SIZE); - - out_header.write_to_io(&mut data).unwrap(); - - let _ = resp_sender - .send(Either::Right((data, entry_data.into()))) - .await; + resp_sender.send2(&out_header, &entry_data).await; }); } @@ -3879,7 +3823,9 @@ impl Session { err, request.unique ); - reply_error_in_place(libc::EINVAL.into(), request, &self.response_sender).await; + self.response_sender() + .send_err(&request, libc::EINVAL.into()) + .await; return; } @@ -3894,7 +3840,9 @@ impl Session { request.unique ); - reply_error_in_place(libc::EINVAL.into(), request, &self.response_sender).await; + self.response_sender() + .send_err(&request, libc::EINVAL.into()) + .await; return; } @@ -3911,7 +3859,9 @@ impl Session { request.unique ); - reply_error_in_place(libc::EINVAL.into(), request, &self.response_sender).await; + self.response_sender() + .send_err(&request, libc::EINVAL.into()) + .await; return; } @@ -3919,7 +3869,7 @@ impl Session { Some(index) => OsString::from_vec(data[..index].to_vec()), }; - let mut resp_sender = self.response_sender.clone(); + let resp_sender = self.response_sender().clone(); let fs = fs.clone(); spawn(debug_span!("fuse_rename2"), async move { @@ -3955,9 +3905,7 @@ impl Session { unique: request.unique, }; - let data = out_header.as_bytes().to_vec(); - - let _ = resp_sender.send(Either::Left(data)).await; + resp_sender.send1(&out_header).await; }); } @@ -3969,7 +3917,7 @@ impl Session { data: &[u8], fs: &Arc, ) { - let mut resp_sender = self.response_sender.clone(); + let resp_sender = self.response_sender().clone(); let lseek_in = match fuse_lseek_in::read_from_prefix(data) { Err(err) => { @@ -3977,9 +3925,7 @@ impl Session { "deserialize fuse_lseek_in failed {}, request unique {}", err, request.unique ); - - reply_error_in_place(libc::EINVAL.into(), request, &self.response_sender).await; - + resp_sender.send_err(&request, libc::EINVAL.into()).await; return; } @@ -4005,8 +3951,7 @@ impl Session { .await { Err(err) => { - reply_error_in_place(err, request, resp_sender).await; - + resp_sender.send_err(&request, err).await; return; } @@ -4020,13 +3965,7 @@ impl Session { error: 0, unique: request.unique, }; - - let mut data = Vec::with_capacity(FUSE_OUT_HEADER_SIZE + FUSE_OPEN_OUT_SIZE); - - out_header.write_to_io(&mut data).unwrap(); - lseek_out.write_to_io(&mut data).unwrap(); - - let _ = resp_sender.send(Either::Left(data)).await; + resp_sender.send2(&out_header, lseek_out.as_bytes()).await; }); } @@ -4038,7 +3977,7 @@ impl Session { data: &[u8], fs: &Arc, ) { - let mut resp_sender = self.response_sender.clone(); + let resp_sender = self.response_sender().clone(); let copy_file_range_in = match fuse_copy_file_range_in::read_from_prefix(data) { Err(err) => { @@ -4047,7 +3986,9 @@ impl Session { err, request.unique ); - reply_error_in_place(libc::EINVAL.into(), request, &self.response_sender).await; + self.response_sender() + .send_err(&request, libc::EINVAL.into()) + .await; return; } @@ -4078,8 +4019,7 @@ impl Session { .await { Err(err) => { - reply_error_in_place(err, request, resp_sender).await; - + resp_sender.send_err(&request, err).await; return; } @@ -4094,31 +4034,11 @@ impl Session { unique: request.unique, }; - let mut data = Vec::with_capacity(FUSE_OUT_HEADER_SIZE + FUSE_WRITE_OUT_SIZE); - - out_header.write_to_io(&mut data).unwrap(); - write_out.write_to_io(&mut data).unwrap(); - - let _ = resp_sender.send(Either::Left(data)).await; + resp_sender.send2(&out_header, write_out.as_bytes()).await; }); } } -async fn reply_error_in_place(err: Errno, request: Request, sender: S) -where - S: Sink, (Vec, Bytes)>>, -{ - let out_header = fuse_out_header { - len: FUSE_OUT_HEADER_SIZE as u32, - error: err.into(), - unique: request.unique, - }; - - let data = out_header.as_bytes().to_vec(); - - let _ = pin!(sender).send(Either::Left(data)).await; -} - #[inline] fn spawn(span: Span, fut: F) where From f5ea647eccaeb2e448c5788c4cc6f93e46b76cfe Mon Sep 17 00:00:00 2001 From: Sherlock Holo Date: Wed, 11 Mar 2026 21:42:11 +0800 Subject: [PATCH 04/13] ci: move to github ci (#132) * ci: move to github ci the cirrus compute credits is too few * ci: update freebsd version --- .cirrus.yml | 59 ----------------------- .github/workflows/ci.yml | 100 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+), 59 deletions(-) delete mode 100644 .cirrus.yml create mode 100644 .github/workflows/ci.yml diff --git a/.cirrus.yml b/.cirrus.yml deleted file mode 100644 index 2c3bae7..0000000 --- a/.cirrus.yml +++ /dev/null @@ -1,59 +0,0 @@ -build: &BUILD - cargo_cache: - folder: $HOME/.cargo/registry - fingerprint_script: cat Cargo.lock || echo "" - build_script: - - . $HOME/.cargo/env || true - - rustup component add clippy - - cargo check --all-targets --features=tokio-runtime,file-lock,unprivileged - - cargo check --all-targets --features=async-io-runtime,file-lock,unprivileged - # - RUSTDOCFLAGS="--cfg docsrs" cargo doc --features=file-lock,unprivileged,tokio-runtime # disable until doc_cfg and doc_auto_cfg are stable - - cargo doc --features=file-lock,unprivileged,tokio-runtime - - cargo clippy --all-targets --features=tokio-runtime,file-lock,unprivileged - - cargo clippy --all-targets --features=async-io-runtime,file-lock,unprivileged - before_cache_script: rm -rf $HOME/.cargo/registry/index - - -task: - name: FreeBSD - freebsd_instance: - image: freebsd-14-3-release-amd64-ufs - setup_script: - - fetch https://sh.rustup.rs -o rustup.sh - - sh rustup.sh -y --profile=minimal - - . $HOME/.cargo/env - << : *BUILD - -task: - name: MacOS - macos_instance: - image: ghcr.io/cirruslabs/macos-sonoma-base:latest - setup_script: - - curl https://sh.rustup.rs -o rustup.sh - - sh rustup.sh -y --profile=minimal - - . $HOME/.cargo/env - << : *BUILD - -task: - name: Linux - container: - image: rust:latest - << : *BUILD - -minver_task: - depends_on: - - FreeBSD - - Linux - - MacOS - freebsd_instance: - image: freebsd-14-3-release-amd64-ufs - setup_script: - - pkg install -y ca_root_nss - - fetch https://sh.rustup.rs -o rustup.sh - - sh rustup.sh -y --default-toolchain nightly --profile=minimal - - . $HOME/.cargo/env - test_script: - - . $HOME/.cargo/env || true - - cargo update -Zdirect-minimal-versions - - cargo check --all-targets --features=tokio-runtime,file-lock,unprivileged - - cargo check --all-targets --features=async-io-runtime,file-lock,unprivileged diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..06e6307 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,100 @@ +name: CI + +on: + push: + branches: [main, master] + pull_request: + branches: [main, master] + +env: + CARGO_TERM_COLOR: always + +jobs: + linux: + name: Linux + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Install Rust + uses: dtolnay/rust-toolchain@stable + with: + components: clippy + + - name: Cache cargo + uses: Swatinem/rust-cache@v2 + + - name: Clippy (tokio-runtime) + run: cargo clippy --all-targets --features=tokio-runtime,file-lock,unprivileged + + - name: Clippy (async-io-runtime) + run: cargo clippy --all-targets --features=async-io-runtime,file-lock,unprivileged + + - name: Doc + run: cargo doc --features=file-lock,unprivileged,tokio-runtime + + macos: + name: MacOS + runs-on: macos-latest + steps: + - uses: actions/checkout@v4 + + - name: Install Rust + uses: dtolnay/rust-toolchain@stable + with: + components: clippy + + - name: Cache cargo + uses: Swatinem/rust-cache@v2 + + - name: Clippy (tokio-runtime) + run: cargo clippy --all-targets --features=tokio-runtime,file-lock,unprivileged + + - name: Clippy (async-io-runtime) + run: cargo clippy --all-targets --features=async-io-runtime,file-lock,unprivileged + + - name: Doc + run: cargo doc --features=file-lock,unprivileged,tokio-runtime + + freebsd: + name: FreeBSD + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Build on FreeBSD + uses: vmactions/freebsd-vm@v1 + with: + release: "15.0" + usesh: true + prepare: | + pkg install -y ca_root_nss curl + fetch https://sh.rustup.rs -o rustup.sh + sh rustup.sh -y --profile=minimal + run: | + . $HOME/.cargo/env || true + rustup component add clippy + cargo clippy --all-targets --features=tokio-runtime,file-lock,unprivileged + cargo clippy --all-targets --features=async-io-runtime,file-lock,unprivileged + cargo doc --features=file-lock,unprivileged,tokio-runtime + + minver: + name: MinVer + runs-on: ubuntu-latest + needs: [linux, macos, freebsd] + steps: + - uses: actions/checkout@v4 + + - name: Install Rust (nightly) + uses: dtolnay/rust-toolchain@nightly + with: + components: clippy + + - name: Cache cargo + uses: Swatinem/rust-cache@v2 + + - name: MinVer check + run: | + cargo update -Zdirect-minimal-versions + cargo clippy --all-targets --features=tokio-runtime,file-lock,unprivileged + cargo clippy --all-targets --features=async-io-runtime,file-lock,unprivileged From 701cd3bf10bea6ac518a581cc45d7a6b221a48e8 Mon Sep 17 00:00:00 2001 From: Sherlock Holo Date: Mon, 9 Mar 2026 23:05:01 +0800 Subject: [PATCH 05/13] fix style, update dependencies and prepare release --- .gitignore | 2 +- .rustfmt.toml | 2 +- Cargo.lock | 693 +++++++++++++++++---------------- Cargo.toml | 35 +- examples/Cargo.toml | 14 +- src/lib.rs | 14 +- src/notify.rs | 64 +-- src/path/inode_path_bridge.rs | 14 +- src/path/mod.rs | 6 +- src/path/path_filesystem.rs | 2 +- src/path/session.rs | 2 +- src/raw/connection/async_io.rs | 17 +- src/raw/connection/tokio.rs | 33 +- src/raw/mod.rs | 6 +- src/raw/session.rs | 47 +-- 15 files changed, 474 insertions(+), 477 deletions(-) diff --git a/.gitignore b/.gitignore index bd787a3..185ca35 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ /target -.idea \ No newline at end of file +.idea diff --git a/.rustfmt.toml b/.rustfmt.toml index dd3bd0d..f8449af 100644 --- a/.rustfmt.toml +++ b/.rustfmt.toml @@ -1,2 +1,2 @@ -edition = "2021" +edition = "2024" group_imports = "StdExternalCrate" diff --git a/Cargo.lock b/Cargo.lock index c613aac..fbb8158 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,21 +1,12 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] -name = "addr2line" -version = "0.25.1" +name = "anyhow" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" [[package]] name = "async-channel" @@ -24,7 +15,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2" dependencies = [ "concurrent-queue", - "event-listener-strategy 0.5.4", + "event-listener-strategy", "futures-core", "pin-project-lite", ] @@ -45,9 +36,9 @@ dependencies = [ [[package]] name = "async-fs" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc19683171f287921f2405677dd2ed2549c3b3bda697a563ebc3a121ace2aba1" +checksum = "8034a681df4aed8b8edbd7fbe472401ecf009251c8b40556b304567052e294c5" dependencies = [ "async-lock", "blocking", @@ -56,9 +47,9 @@ dependencies = [ [[package]] name = "async-global-executor" -version = "2.4.1" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" +checksum = "13f937e26114b93193065fd44f507aa2e9169ad0cdabbb996920b1fe1ddea7ba" dependencies = [ "async-channel", "async-executor", @@ -66,36 +57,34 @@ dependencies = [ "async-lock", "blocking", "futures-lite", - "once_cell", ] [[package]] name = "async-io" -version = "2.3.1" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f97ab0c5b00a7cdbe5a371b9a782ee7be1316095885c8a4ea1daf490eb0ef65" +checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc" dependencies = [ - "async-lock", + "autocfg", "cfg-if", "concurrent-queue", "futures-io", "futures-lite", "parking", "polling", - "rustix 0.38.44", + "rustix", "slab", - "tracing", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] name = "async-lock" -version = "3.3.0" +version = "3.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d034b430882f8381900d3fe6f0aaa3ad94f2cb4ac519b429692a1bc2dda4ae7b" +checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" dependencies = [ - "event-listener 4.0.3", - "event-listener-strategy 0.4.0", + "event-listener 5.4.1", + "event-listener-strategy", "pin-project-lite", ] @@ -112,20 +101,20 @@ dependencies = [ [[package]] name = "async-process" -version = "2.1.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "451e3cf68011bd56771c79db04a9e333095ab6349f7e47592b788e9b98720cc8" +checksum = "fc50921ec0055cdd8a16de48773bfeec5c972598674347252c0399676be7da75" dependencies = [ "async-channel", "async-io", "async-lock", "async-signal", + "async-task", "blocking", "cfg-if", "event-listener 5.4.1", "futures-lite", - "rustix 0.38.44", - "windows-sys 0.52.0", + "rustix", ] [[package]] @@ -140,7 +129,7 @@ dependencies = [ "cfg-if", "futures-core", "futures-io", - "rustix 1.0.8", + "rustix", "signal-hook-registry", "slab", "windows-sys 0.61.2", @@ -164,26 +153,11 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" -[[package]] -name = "backtrace" -version = "0.3.76" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-link", -] - [[package]] name = "bitflags" -version = "2.10.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" [[package]] name = "blocking" @@ -200,9 +174,9 @@ dependencies = [ [[package]] name = "bytes" -version = "1.5.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] name = "cfg-if" @@ -232,10 +206,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] -name = "either" -version = "1.15.0" +name = "equivalent" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" @@ -269,16 +243,6 @@ dependencies = [ "pin-project-lite", ] -[[package]] -name = "event-listener-strategy" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3" -dependencies = [ - "event-listener 4.0.3", - "pin-project-lite", -] - [[package]] name = "event-listener-strategy" version = "0.5.4" @@ -310,9 +274,15 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + [[package]] name = "fuse3" -version = "0.8.1" +version = "0.9.0" dependencies = [ "async-fs", "async-global-executor", @@ -321,7 +291,6 @@ dependencies = [ "async-notify", "async-process", "bytes", - "futures-channel", "futures-util", "libc", "nix", @@ -333,27 +302,17 @@ dependencies = [ "zerocopy", ] -[[package]] -name = "futures-channel" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" -dependencies = [ - "futures-core", - "futures-sink", -] - [[package]] name = "futures-core" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" [[package]] name = "futures-io" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" [[package]] name = "futures-lite" @@ -370,9 +329,9 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" dependencies = [ "proc-macro2", "quote", @@ -381,21 +340,21 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" [[package]] name = "futures-task" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" [[package]] name = "futures-util" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" dependencies = [ "futures-core", "futures-io", @@ -404,15 +363,42 @@ dependencies = [ "futures-task", "memchr", "pin-project-lite", - "pin-utils", "slab", ] [[package]] -name = "gimli" -version = "0.32.3" +name = "getrandom" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", + "wasip3", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" @@ -421,14 +407,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" [[package]] -name = "home" -version = "0.5.12" +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + +[[package]] +name = "indexmap" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" dependencies = [ - "windows-sys 0.61.2", + "equivalent", + "hashbrown 0.16.1", + "serde", + "serde_core", ] +[[package]] +name = "itoa" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" + [[package]] name = "lazy_static" version = "1.5.0" @@ -436,22 +437,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] -name = "libc" -version = "0.2.168" +name = "leb128fmt" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] -name = "linux-raw-sys" -version = "0.4.15" +name = "libc" +version = "0.2.183" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" +checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" [[package]] name = "linux-raw-sys" -version = "0.9.4" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" [[package]] name = "log" @@ -461,9 +462,9 @@ checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] name = "memchr" -version = "2.7.6" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "memoffset" @@ -474,15 +475,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "miniz_oxide" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" -dependencies = [ - "adler2", -] - [[package]] name = "mio" version = "0.8.11" @@ -497,9 +489,9 @@ dependencies = [ [[package]] name = "mio" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" dependencies = [ "libc", "wasi", @@ -508,9 +500,9 @@ dependencies = [ [[package]] name = "nix" -version = "0.29.0" +version = "0.31.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +checksum = "5d6d0705320c1e6ba1d912b5e37cf18071b6c2e9b7fa8215a1e8a7651966f5d3" dependencies = [ "bitflags", "cfg-if", @@ -528,15 +520,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "object" -version = "0.37.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" -dependencies = [ - "memchr", -] - [[package]] name = "once_cell" version = "1.21.3" @@ -551,21 +534,15 @@ checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "pin-project-lite" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" [[package]] name = "piper" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" +checksum = "c835479a4443ded371d6c535cbfd8d31ad92c5d23ae9770a61bc155e4992a3c1" dependencies = [ "atomic-waker", "fastrand", @@ -582,58 +559,103 @@ dependencies = [ "concurrent-queue", "hermit-abi", "pin-project-lite", - "rustix 1.0.8", + "rustix", "windows-sys 0.61.2", ] +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + [[package]] name = "proc-macro2" -version = "1.0.105" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.43" +version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" dependencies = [ "proc-macro2", ] [[package]] -name = "rustc-demangle" -version = "0.1.26" +name = "r-efi" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" [[package]] name = "rustix" -version = "0.38.44" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ "bitflags", "errno", "libc", - "linux-raw-sys 0.4.15", - "windows-sys 0.59.0", + "linux-raw-sys", + "windows-sys 0.61.2", ] [[package]] -name = "rustix" -version = "1.0.8" +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + +[[package]] +name = "serde" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ - "bitflags", - "errno", - "libc", - "linux-raw-sys 0.9.4", - "windows-sys 0.60.2", + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", ] [[package]] @@ -657,12 +679,9 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.9" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "smallvec" @@ -672,19 +691,19 @@ checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "socket2" -version = "0.5.8" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" +checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] name = "syn" -version = "2.0.114" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", @@ -693,14 +712,15 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.10.0" +version = "3.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a365e8cd18e44762ef95d87f284f4b5cd04107fec2ff3052bd6a3e6069669e67" +checksum = "82a72c767771b47409d2345987fda8628641887d5466101319899796367354a0" dependencies = [ - "cfg-if", "fastrand", - "rustix 0.38.44", - "windows-sys 0.52.0", + "getrandom", + "once_cell", + "rustix", + "windows-sys 0.61.2", ] [[package]] @@ -714,26 +734,25 @@ dependencies = [ [[package]] name = "tokio" -version = "1.45.0" +version = "1.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2513ca694ef9ede0fb23fe71a4ee4107cb102b9dc1930f6d0fd77aae068ae165" +checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d" dependencies = [ - "backtrace", "bytes", "libc", - "mio 1.1.0", + "mio 1.1.1", "pin-project-lite", "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] name = "tokio-macros" -version = "2.5.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +checksum = "5c55a2eff8b69ce66c84f85e1da1c233edc36ceb85a2058d11b0d6a3c7e7569c" dependencies = [ "proc-macro2", "quote", @@ -742,9 +761,9 @@ dependencies = [ [[package]] name = "tracing" -version = "0.1.40" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ "pin-project-lite", "tracing-attributes", @@ -785,9 +804,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.20" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5" +checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" dependencies = [ "nu-ansi-term", "sharded-slab", @@ -810,9 +829,15 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.22" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-xid" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "valuable" @@ -827,115 +852,103 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] -name = "which" -version = "6.0.0" +name = "wasip2" +version = "1.0.2+wasi-0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fa5e0c10bf77f44aac573e498d1a82d5fbd5e91f6fc0a99e7be4b38e85e101c" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" dependencies = [ - "either", - "home", - "once_cell", - "rustix 0.38.44", - "windows-sys 0.52.0", + "wit-bindgen", ] [[package]] -name = "windows-link" -version = "0.2.1" +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen", +] [[package]] -name = "windows-sys" -version = "0.48.0" +name = "wasm-encoder" +version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" dependencies = [ - "windows-targets 0.48.5", + "leb128fmt", + "wasmparser", ] [[package]] -name = "windows-sys" -version = "0.52.0" +name = "wasm-metadata" +version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" dependencies = [ - "windows-targets 0.52.6", + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", ] [[package]] -name = "windows-sys" -version = "0.59.0" +name = "wasmparser" +version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" dependencies = [ - "windows-targets 0.52.6", + "bitflags", + "hashbrown 0.15.5", + "indexmap", + "semver", ] [[package]] -name = "windows-sys" -version = "0.60.2" +name = "which" +version = "8.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +checksum = "81995fafaaaf6ae47a7d0cc83c67caf92aeb7e5331650ae6ff856f7c0c60c459" dependencies = [ - "windows-targets 0.53.5", + "libc", ] [[package]] -name = "windows-sys" -version = "0.61.2" +name = "windows-link" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" -dependencies = [ - "windows-link", -] +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] -name = "windows-targets" -version = "0.48.5" +name = "windows-sys" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", + "windows-targets", ] [[package]] -name = "windows-targets" -version = "0.52.6" +name = "windows-sys" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", + "windows-link", ] [[package]] name = "windows-targets" -version = "0.53.5" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows-link", - "windows_aarch64_gnullvm 0.53.1", - "windows_aarch64_msvc 0.53.1", - "windows_i686_gnu 0.53.1", - "windows_i686_gnullvm 0.53.1", - "windows_i686_msvc 0.53.1", - "windows_x86_64_gnu 0.53.1", - "windows_x86_64_gnullvm 0.53.1", - "windows_x86_64_msvc 0.53.1", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] [[package]] @@ -944,84 +957,24 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" - [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" - [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnu" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" - [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_i686_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" - [[package]] name = "windows_x86_64_gnu" version = "0.48.5" @@ -1029,69 +982,127 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" +name = "windows_x86_64_gnullvm" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] -name = "windows_x86_64_gnu" -version = "0.53.1" +name = "windows_x86_64_msvc" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" +name = "wit-bindgen" +version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] [[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" +name = "wit-bindgen-core" +version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] [[package]] -name = "windows_x86_64_gnullvm" -version = "0.53.1" +name = "wit-bindgen-rust" +version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "prettyplease", + "syn", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] [[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" +name = "wit-bindgen-rust-macro" +version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn", + "wit-bindgen-core", + "wit-bindgen-rust", +] [[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" +name = "wit-component" +version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] [[package]] -name = "windows_x86_64_msvc" -version = "0.53.1" +name = "wit-parser" +version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] [[package]] name = "zerocopy" -version = "0.8.40" +version = "0.8.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a789c6e490b576db9f7e6b6d661bcc9799f7c0ac8352f56ea20193b2681532e5" +checksum = "f2578b716f8a7a858b7f02d5bd870c14bf4ddbbcf3a4c05414ba6503640505e3" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.40" +version = "0.8.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f65c489a7071a749c849713807783f70672b28094011623e200cb86dcb835953" +checksum = "7e6cc098ea4d3bd6246687de65af3f920c430e236bee1e3bf2e441463f08a02f" dependencies = [ "proc-macro2", "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/Cargo.toml b/Cargo.toml index 59a6af0..e15cae8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,15 +1,15 @@ [package] name = "fuse3" -version = "0.8.1" +version = "0.9.0" authors = ["Sherlock Holo "] -edition = "2021" +edition = "2024" readme = "README.md" keywords = ["fuse", "filesystem", "system", "bindings"] categories = ["api-bindings", "filesystem"] license = "MIT" repository = "https://github.com/Sherlock-Holo/fuse3" description = "FUSE user-space library async version implementation." -rust-version = "1.77" +rust-version = "1.91" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -23,25 +23,24 @@ file-lock = [] unprivileged = ["nix/socket", "dep:which"] [dependencies] -async-fs = { version = "2.1.1", optional = true } -async-global-executor = { version = "2.4.1", optional = true } -async-lock = { version = "3.3.0", optional = true } +async-fs = { version = "2.2.0", optional = true } +async-global-executor = { version = "3.1.0", optional = true } +async-lock = { version = "3.4.2", optional = true } async-notify = "0.3" -async-io = { version = "2.3.1", optional = true } -async-process = { version = "2.1.0", optional = true } -bytes = "1.5" -futures-channel = { version = "0.3.30", features = ["sink"] } -futures-util = { version = "0.3.30", features = ["sink"] } -libc = "0.2.168" -nix = { version = "0.29.0", default-features = false, features = ["fs", "mount", "user"] } -slab = "0.4.9" -tracing = "0.1.40" +async-io = { version = "2.6.0", optional = true } +async-process = { version = "2.5.0", optional = true } +bytes = "1.11.1" +futures-util = { version = "0.3.32", features = ["sink"] } +libc = "0.2.183" +nix = { version = "0.31.2", default-features = false, features = ["fs", "mount", "user"] } +slab = "0.4.12" +tracing = "0.1.44" trait-make = "0.1" -which = { version = "6", optional = true } -zerocopy = {version = "0.8.10", features = ["derive", "std"]} +which = { version = "8.0.2", optional = true } +zerocopy = { version = "0.8.42", features = ["derive", "std"] } [dependencies.tokio] -version = "1.45" +version = "1.50" features = ["fs", "rt", "sync", "net", "macros", "process", "time"] optional = true diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 00e56f0..9045e1d 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -25,11 +25,11 @@ path = "src/path_memfs/main.rs" [dependencies] fuse3 = { path = "../", features = ["tokio-runtime", "unprivileged"] } -libc = "0.2.168" -tokio = { version = "1.45", features = ["macros", "rt", "time", "signal"] } -futures-util = "0.3.31" +libc = "0.2.183" +tokio = { version = "1.50", features = ["macros", "rt", "time", "signal"] } +futures-util = "0.3.32" mio = { version = "0.8.11", features = ["os-poll"] } -tempfile = "3.10" -bytes = "1.5" -tracing = "0.1.40" -tracing-subscriber = "0.3.20" +tempfile = "3.26" +bytes = "1.11" +tracing = "0.1.44" +tracing-subscriber = "0.3.22" diff --git a/src/lib.rs b/src/lib.rs index c92df96..4fe8fec 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,7 +24,7 @@ all(target_os = "linux", feature = "unprivileged"), target_os = "macos" ))] -use std::io::{self, ErrorKind}; +use std::io::{self}; #[cfg(target_os = "macos")] use std::path::Path; #[cfg(any( @@ -39,8 +39,8 @@ pub use helper::{mode_from_kind_and_perm, perm_from_mode_and_kind}; pub use mount_options::MountOptions; use nix::sys::stat::mode_t; use raw::abi::{ - fuse_setattr_in, FATTR_ATIME, FATTR_ATIME_NOW, FATTR_CTIME, FATTR_GID, FATTR_LOCKOWNER, - FATTR_MODE, FATTR_MTIME, FATTR_MTIME_NOW, FATTR_SIZE, FATTR_UID, + FATTR_ATIME, FATTR_ATIME_NOW, FATTR_CTIME, FATTR_GID, FATTR_LOCKOWNER, FATTR_MODE, FATTR_MTIME, + FATTR_MTIME_NOW, FATTR_SIZE, FATTR_UID, fuse_setattr_in, }; #[cfg(target_os = "macos")] use raw::abi::{FATTR_BKUPTIME, FATTR_CHGTIME, FATTR_CRTIME, FATTR_FLAGS}; @@ -237,12 +237,8 @@ impl From for Timestamp { #[cfg(all(target_os = "linux", feature = "unprivileged"))] fn find_fusermount3() -> io::Result { - which::which("fusermount3").map_err(|err| { - io::Error::new( - ErrorKind::Other, - format!("find fusermount3 binary failed {err:?}"), - ) - }) + which::which("fusermount3") + .map_err(|err| io::Error::other(format!("find fusermount3 binary failed {err:?}"))) } #[cfg(target_os = "macos")] diff --git a/src/notify.rs b/src/notify.rs index cd945e6..c451a01 100644 --- a/src/notify.rs +++ b/src/notify.rs @@ -7,12 +7,12 @@ use bytes::{Buf, Bytes}; use zerocopy::IntoBytes; use crate::raw::abi::{ + FUSE_NOTIFY_DELETE_OUT_SIZE, FUSE_NOTIFY_INVAL_ENTRY_OUT_SIZE, + FUSE_NOTIFY_INVAL_INODE_OUT_SIZE, FUSE_NOTIFY_POLL_WAKEUP_OUT_SIZE, + FUSE_NOTIFY_RETRIEVE_OUT_SIZE, FUSE_NOTIFY_STORE_OUT_SIZE, FUSE_OUT_HEADER_SIZE, fuse_notify_code, fuse_notify_delete_out, fuse_notify_inval_entry_out, fuse_notify_inval_inode_out, fuse_notify_poll_wakeup_out, fuse_notify_retrieve_out, - fuse_notify_store_out, fuse_out_header, FUSE_NOTIFY_DELETE_OUT_SIZE, - FUSE_NOTIFY_INVAL_ENTRY_OUT_SIZE, FUSE_NOTIFY_INVAL_INODE_OUT_SIZE, - FUSE_NOTIFY_POLL_WAKEUP_OUT_SIZE, FUSE_NOTIFY_RETRIEVE_OUT_SIZE, FUSE_NOTIFY_STORE_OUT_SIZE, - FUSE_OUT_HEADER_SIZE, + fuse_notify_store_out, fuse_out_header, }; use crate::raw::session::ResponseSender; @@ -56,7 +56,9 @@ impl Notify { len: *len, }; - self.sender.send2(&out_header, invalid_inode_out.as_bytes()).await; + self.sender + .send2(&out_header, invalid_inode_out.as_bytes()) + .await; } NotifyKind::InvalidEntry { parent, name } => { @@ -73,7 +75,9 @@ impl Notify { }; // TODO should I add null at the end? - self.sender.send2(&out_header, invalid_entry_out.as_bytes()).await; + self.sender + .send2(&out_header, invalid_entry_out.as_bytes()) + .await; } NotifyKind::Delete { @@ -139,7 +143,9 @@ impl Notify { _padding: 0, }; - self.sender.send2(&out_header, retrieve_out.as_bytes()).await; + self.sender + .send2(&out_header, retrieve_out.as_bytes()) + .await; } }; } @@ -151,8 +157,7 @@ impl Notify { /// try to notify the cache invalidation about an inode. pub async fn invalid_inode(mut self, inode: u64, offset: i64, len: i64) { - self - .notify(NotifyKind::InvalidInode { inode, offset, len }) + self.notify(NotifyKind::InvalidInode { inode, offset, len }) .await; } @@ -163,36 +168,33 @@ impl Notify { /// try to notify a directory entry has been deleted. pub async fn delete(mut self, parent: u64, child: u64, name: OsString) { - self - .notify(NotifyKind::Delete { - parent, - child, - name, - }) - .await; + self.notify(NotifyKind::Delete { + parent, + child, + name, + }) + .await; } /// try to push the data in an inode for updating the kernel cache. pub async fn store(mut self, inode: u64, offset: u64, mut data: impl Buf) { - self - .notify(NotifyKind::Store { - inode, - offset, - data: data.copy_to_bytes(data.remaining()), - }) - .await; + self.notify(NotifyKind::Store { + inode, + offset, + data: data.copy_to_bytes(data.remaining()), + }) + .await; } /// try to retrieve data in an inode from the kernel cache. pub async fn retrieve(mut self, notify_unique: u64, inode: u64, offset: u64, size: u32) { - self - .notify(NotifyKind::Retrieve { - notify_unique, - inode, - offset, - size, - }) - .await; + self.notify(NotifyKind::Retrieve { + notify_unique, + inode, + offset, + size, + }) + .await; } } diff --git a/src/path/inode_path_bridge.rs b/src/path/inode_path_bridge.rs index b157467..8d6b1fc 100644 --- a/src/path/inode_path_bridge.rs +++ b/src/path/inode_path_bridge.rs @@ -57,14 +57,14 @@ impl InodeNameManager { } fn remove_name(&mut self, name: &Name) { - if let Some(inode) = self.name_to_inode.remove(name) { - if let Some(names) = self.inode_to_names.get_mut(&inode) { - names.remove(name); + if let Some(inode) = self.name_to_inode.remove(name) + && let Some(names) = self.inode_to_names.get_mut(&inode) + { + names.remove(name); - if names.is_empty() { - self.inode_to_names.remove(&inode); - self.inode_generator.release_inode(inode); - } + if names.is_empty() { + self.inode_to_names.remove(&inode); + self.inode_generator.release_inode(inode); } } } diff --git a/src/path/mod.rs b/src/path/mod.rs index 5b66257..bca6b28 100644 --- a/src/path/mod.rs +++ b/src/path/mod.rs @@ -16,12 +16,12 @@ pub mod reply; mod session; pub mod prelude { - pub use super::reply::FileAttr; - pub use super::reply::*; pub use super::PathFilesystem; pub use super::Request; pub use super::Session; - pub use crate::notify::Notify; + pub use super::reply::FileAttr; + pub use super::reply::*; pub use crate::FileType; pub use crate::SetAttr; + pub use crate::notify::Notify; } diff --git a/src/path/path_filesystem.rs b/src/path/path_filesystem.rs index dea3623..e8e22fd 100644 --- a/src/path/path_filesystem.rs +++ b/src/path/path_filesystem.rs @@ -3,8 +3,8 @@ use std::ffi::OsStr; use bytes::Bytes; use futures_util::stream::{Empty, Stream}; -use super::reply::*; use super::Request; +use super::reply::*; use crate::notify::Notify; use crate::{Result, SetAttr}; diff --git a/src/path/session.rs b/src/path/session.rs index 8b57801..8ec5678 100644 --- a/src/path/session.rs +++ b/src/path/session.rs @@ -1,10 +1,10 @@ use std::io; use std::path::Path; +use crate::MountOptions; use crate::path::inode_path_bridge::InodePathBridge; use crate::path::path_filesystem::PathFilesystem; use crate::raw; -use crate::MountOptions; #[cfg(any(feature = "async-io-runtime", feature = "tokio-runtime"))] #[derive(Debug)] diff --git a/src/raw/connection/async_io.rs b/src/raw/connection/async_io.rs index 96735af..ca2f154 100644 --- a/src/raw/connection/async_io.rs +++ b/src/raw/connection/async_io.rs @@ -43,9 +43,9 @@ use async_notify::Notify; target_os = "macos" ))] use async_process::Command; +use futures_util::{FutureExt, select}; #[cfg(target_os = "macos")] use futures_util::{join, try_join}; -use futures_util::{select, FutureExt}; #[cfg(any( all(target_os = "linux", feature = "unprivileged"), target_os = "macos" @@ -63,14 +63,14 @@ use nix::sys::uio; ))] use tracing::debug; -#[cfg(all(target_os = "linux", feature = "unprivileged"))] -use crate::find_fusermount3; -use crate::raw::connection::CompleteIoResult; #[cfg(any( all(target_os = "linux", feature = "unprivileged"), target_os = "macos" ))] use crate::MountOptions; +#[cfg(all(target_os = "linux", feature = "unprivileged"))] +use crate::find_fusermount3; +use crate::raw::connection::CompleteIoResult; #[derive(Debug)] pub struct FuseConnection { unmount_notify: Arc, @@ -449,10 +449,7 @@ impl NonBlockFuseConnection { .spawn()?; if !child.status().await?.success() { - return Err(io::Error::new( - io::ErrorKind::Other, - "fusermount run failed", - )); + return Err(io::Error::other("fusermount run failed")); } let fd1 = sock1.as_raw_fd(); @@ -477,12 +474,12 @@ impl NonBlockFuseConnection { let fd = if let Some(ControlMessageOwned::ScmRights(fds)) = msg.cmsgs()?.next() { if fds.is_empty() { - return Err(io::Error::new(io::ErrorKind::Other, "no fuse fd")); + return Err(io::Error::other("no fuse fd")); } fds[0] } else { - return Err(io::Error::new(io::ErrorKind::Other, "get fuse fd failed")); + return Err(io::Error::other("get fuse fd failed")); }; Ok(fd) diff --git a/src/raw/connection/tokio.rs b/src/raw/connection/tokio.rs index 493c01b..5caf5d7 100644 --- a/src/raw/connection/tokio.rs +++ b/src/raw/connection/tokio.rs @@ -4,12 +4,6 @@ use std::env; use std::fs::File; use std::fs::OpenOptions; use std::io; -#[cfg(any( - all(target_os = "linux", feature = "unprivileged"), - target_os = "freebsd", - target_os = "macos", -))] -use std::io::ErrorKind; #[cfg(any(target_os = "linux", target_os = "macos"))] use std::io::Write; use std::io::{IoSlice, IoSliceMut}; @@ -40,7 +34,7 @@ use std::{ffi::OsString, path::Path}; use async_notify::Notify; use futures_util::lock::Mutex; -use futures_util::{select, FutureExt}; +use futures_util::{FutureExt, select}; #[cfg(any( all(target_os = "linux", feature = "unprivileged"), target_os = "freebsd", @@ -58,14 +52,14 @@ use nix::{ #[cfg(any( all(target_os = "linux", feature = "unprivileged"), target_os = "freebsd", - target_os = "macos", ))] -use tokio::io::unix::AsyncFd; +use tokio::io::Interest; #[cfg(any( all(target_os = "linux", feature = "unprivileged"), target_os = "freebsd", + target_os = "macos", ))] -use tokio::io::Interest; +use tokio::io::unix::AsyncFd; #[cfg(any( all(target_os = "linux", feature = "unprivileged"), target_os = "macos" @@ -82,13 +76,13 @@ use tracing::debug; use tracing::warn; use super::CompleteIoResult; -#[cfg(all(target_os = "linux", feature = "unprivileged"))] -use crate::find_fusermount3; #[cfg(any( all(target_os = "linux", feature = "unprivileged"), target_os = "macos" ))] use crate::MountOptions; +#[cfg(all(target_os = "linux", feature = "unprivileged"))] +use crate::find_fusermount3; #[derive(Debug)] pub struct FuseConnection { @@ -485,10 +479,7 @@ impl NonBlockFuseConnection { .spawn()?; if !child.wait().await?.success() { - return Err(io::Error::new( - io::ErrorKind::Other, - "fusermount run failed", - )); + return Err(io::Error::other("fusermount run failed")); } let fd1 = sock1.as_raw_fd(); @@ -513,12 +504,12 @@ impl NonBlockFuseConnection { let fd = if let Some(ControlMessageOwned::ScmRights(fds)) = msg.cmsgs()?.next() { if fds.is_empty() { - return Err(io::Error::new(ErrorKind::Other, "no fuse fd")); + return Err(io::Error::other("no fuse fd")); } fds[0] } else { - return Err(io::Error::new(ErrorKind::Other, "get fuse fd failed")); + return Err(io::Error::other("get fuse fd failed")); }; Ok(fd) @@ -526,11 +517,11 @@ impl NonBlockFuseConnection { .await .unwrap()?; - Self::set_fd_non_blocking(fd)?; - // Safety: fd is valid let fd = unsafe { OwnedFd::from_raw_fd(fd) }; + Self::set_fd_non_blocking(fd.as_fd())?; + Ok(Self { fd: AsyncFd::new(fd)?, read: Mutex::new(()), @@ -542,7 +533,7 @@ impl NonBlockFuseConnection { all(target_os = "linux", feature = "unprivileged"), target_os = "macos" ))] - fn set_fd_non_blocking(fd: RawFd) -> io::Result<()> { + fn set_fd_non_blocking(fd: BorrowedFd) -> io::Result<()> { let flags = nix::fcntl::fcntl(fd, FcntlArg::F_GETFL).map_err(io::Error::from)?; debug!( "set fd {:?} to non-blocking", diff --git a/src/raw/mod.rs b/src/raw/mod.rs index a174801..e9aff35 100644 --- a/src/raw/mod.rs +++ b/src/raw/mod.rs @@ -20,12 +20,12 @@ mod request; pub(crate) mod session; pub mod prelude { - pub use super::reply::FileAttr; - pub use super::reply::*; pub use super::Filesystem; pub use super::Request; pub use super::Session; - pub use crate::notify::Notify; + pub use super::reply::FileAttr; + pub use super::reply::*; pub use crate::FileType; pub use crate::SetAttr; + pub use crate::notify::Notify; } diff --git a/src/raw/session.rs b/src/raw/session.rs index 59e73a4..a381931 100644 --- a/src/raw/session.rs +++ b/src/raw/session.rs @@ -12,7 +12,7 @@ use std::os::unix::ffi::OsStrExt; use std::os::unix::ffi::OsStringExt; use std::os::unix::io::AsRawFd; use std::path::{Path, PathBuf}; -use std::pin::{pin, Pin}; +use std::pin::{Pin, pin}; use std::sync::Arc; use std::task::Context; use std::task::Poll; @@ -45,9 +45,10 @@ use tokio::process::Command; use tokio::task::JoinHandle; #[cfg(all(not(feature = "async-io-runtime"), feature = "tokio-runtime"))] use tokio::{fs::read_dir, task}; -use tracing::{debug, debug_span, error, instrument, warn, Instrument, Span}; +use tracing::{Instrument, Span, debug, debug_span, error, instrument, warn}; use zerocopy::{FromBytes, IntoBytes}; +use crate::MountOptions; #[cfg(all(target_os = "linux", feature = "unprivileged"))] use crate::find_fusermount3; use crate::helper::*; @@ -58,7 +59,6 @@ use crate::raw::connection::FuseConnection; use crate::raw::filesystem::Filesystem; use crate::raw::reply::ReplyXAttr; use crate::raw::request::Request; -use crate::MountOptions; use crate::{Errno, SetAttr}; /// A Future which returns when a file system is unmounted @@ -102,7 +102,7 @@ impl Drop for MountHandle { /// A sender for sending response to kernel, it will send response immediately when call send method, and notify session when send failed. #[derive(Debug)] -pub (crate) struct ResponseSender { +pub(crate) struct ResponseSender { /// notify session when send failed, session will stop and unmount when receive this notify send_failed: Arc, /// connection to write response @@ -111,7 +111,7 @@ pub (crate) struct ResponseSender { impl ResponseSender { /// send response with only header, no data - pub (crate) async fn send1(&self, header: &fuse_out_header) { + pub(crate) async fn send1(&self, header: &fuse_out_header) { if let Err(err) = self .connection .write_vectored::<_, &[u8]>(header.as_bytes(), None) @@ -131,7 +131,7 @@ impl ResponseSender { } /// send response with header and data - pub (crate) async fn send2(&self, header: &fuse_out_header, data: &[u8]) { + pub(crate) async fn send2(&self, header: &fuse_out_header, data: &[u8]) { if let Err(err) = self .connection .write_vectored::<_, &[u8]>(header.as_bytes(), Some(data)) @@ -151,7 +151,7 @@ impl ResponseSender { } /// send response with header and two parts of data. - pub (crate) async fn send3(&self, header: &fuse_out_header, d1: &[u8], d2: &[u8]) { + pub(crate) async fn send3(&self, header: &fuse_out_header, d1: &[u8], d2: &[u8]) { // TODO: Implement a write_vectored in FuseConnection to avoid this copy let mut data = Vec::with_capacity(d1.len() + d2.len()); data.extend_from_slice(d1); @@ -233,10 +233,7 @@ impl MountHandleInner { .args([OsStr::new("-u"), self.mount_path.as_os_str()]) .spawn()?; if !child.status().await?.success() { - return Err(IoError::new( - ErrorKind::Other, - "call fusermount3 -u to unmount failed", - )); + return Err(IoError::other("call fusermount3 -u to unmount failed")); } return Ok(()); @@ -278,10 +275,7 @@ impl MountHandleInner { .args([OsStr::new("-u"), self.mount_path.as_os_str()]) .spawn()?; if !child.wait().await?.success() { - return Err(IoError::new( - ErrorKind::Other, - "call fusermount3 -u to unmount failed", - )); + return Err(IoError::other("call fusermount3 -u to unmount failed")); } return Ok(()); @@ -594,7 +588,7 @@ impl Session { select! { _ = send_failed => { - return Err(std::io::Error::new(ErrorKind::Other, "send response failed")) + return Err(std::io::Error::other("send response failed")) } dispatch_result = dispatch_task => { @@ -688,12 +682,12 @@ impl Session { }; let n = match res { Err(err) => { - if let Some(errno) = err.raw_os_error() { - if errno == libc::ENODEV { - debug!("read from /dev/fuse failed with ENODEV"); + if let Some(errno) = err.raw_os_error() + && errno == libc::ENODEV + { + debug!("read from /dev/fuse failed with ENODEV"); - return ReadResult::Destroy; - } + return ReadResult::Destroy; } error!("read from /dev/fuse failed {}", err); @@ -2476,7 +2470,11 @@ impl Session { // setxattr "size" field specifies size of only "Value" part of data if setxattr_in.size as usize != data.len() { error!( - "fuse_setxattr_in value field data length is not right, request unique {} setxattr_in.size={} data.len={}", request.unique, setxattr_in.size, data.len()); + "fuse_setxattr_in value field data length is not right, request unique {} setxattr_in.size={} data.len={}", + request.unique, + setxattr_in.size, + data.len() + ); self.response_sender() .send_err(&request, libc::EINVAL.into()) @@ -3593,7 +3591,10 @@ impl Session { while data.len() >= FUSE_FORGET_ONE_SIZE { match fuse_forget_one::read_from_prefix(data) { Err(err) => { - error!("deserialize fuse_batch_forget_in body fuse_forget_one failed {}, request unique {}", err, request.unique); + error!( + "deserialize fuse_batch_forget_in body fuse_forget_one failed {}, request unique {}", + err, request.unique + ); // no need to reply return; From bafc048b240aad415ccd58aabc57262d44004111 Mon Sep 17 00:00:00 2001 From: Sherlock Holo Date: Wed, 11 Mar 2026 21:46:53 +0800 Subject: [PATCH 06/13] refactor: fix ci problems --- Cargo.lock | 31 +++++++-------------- examples/Cargo.toml | 4 +-- src/lib.rs | 2 ++ src/mount_options.rs | 4 +-- src/raw/connection/async_io.rs | 9 +++---- src/raw/connection/tokio.rs | 49 ++++++++++++++-------------------- src/raw/session.rs | 4 ++- 7 files changed, 42 insertions(+), 61 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fbb8158..d57a93d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -22,9 +22,9 @@ dependencies = [ [[package]] name = "async-executor" -version = "1.13.3" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497c00e0fd83a72a79a39fcbd8e3e2f055d6f6c7e025f3b3d91f4f8e76527fb8" +checksum = "c96bf972d85afc50bf5ab8fe2d54d1586b4e0b46c97c50a0c9e71e2f7bcd812a" dependencies = [ "async-task", "concurrent-queue", @@ -83,18 +83,18 @@ version = "3.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" dependencies = [ - "event-listener 5.4.1", + "event-listener", "event-listener-strategy", "pin-project-lite", ] [[package]] name = "async-notify" -version = "0.3.0" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db96c36382f56ea91e5d012c4c7170046c7731449daa46655cbcabc594c8bee6" +checksum = "b31189a260b12d7159e91b74d0b94bb0be3705237082709611b53342b2fb65d7" dependencies = [ - "event-listener 4.0.3", + "event-listener", "futures-core", "pin-project-lite", ] @@ -112,7 +112,7 @@ dependencies = [ "async-task", "blocking", "cfg-if", - "event-listener 5.4.1", + "event-listener", "futures-lite", "rustix", ] @@ -221,17 +221,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "event-listener" -version = "4.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b215c49b2b248c855fb73579eb1f4f26c38ffdc12973e20e07b91d78d5646e" -dependencies = [ - "concurrent-queue", - "parking", - "pin-project-lite", -] - [[package]] name = "event-listener" version = "5.4.1" @@ -249,7 +238,7 @@ version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" dependencies = [ - "event-listener 5.4.1", + "event-listener", "pin-project-lite", ] @@ -712,9 +701,9 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.26.0" +version = "3.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82a72c767771b47409d2345987fda8628641887d5466101319899796367354a0" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" dependencies = [ "fastrand", "getrandom", diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 9045e1d..0542ee9 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -29,7 +29,7 @@ libc = "0.2.183" tokio = { version = "1.50", features = ["macros", "rt", "time", "signal"] } futures-util = "0.3.32" mio = { version = "0.8.11", features = ["os-poll"] } -tempfile = "3.26" -bytes = "1.11" +tempfile = "3.27" +bytes = "1.11.1" tracing = "0.1.44" tracing-subscriber = "0.3.22" diff --git a/src/lib.rs b/src/lib.rs index 4fe8fec..4a5cdbc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,6 +20,8 @@ #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] +#[cfg(target_os = "macos")] +use std::io::ErrorKind; #[cfg(any( all(target_os = "linux", feature = "unprivileged"), target_os = "macos" diff --git a/src/mount_options.rs b/src/mount_options.rs index c18ac1b..8fcc0df 100644 --- a/src/mount_options.rs +++ b/src/mount_options.rs @@ -1,10 +1,10 @@ use std::ffi::OsString; -#[cfg(any(target_os = "linux", target_os = "macos"))] +#[cfg(target_os = "linux")] use std::os::unix::io::RawFd; #[cfg(target_os = "freebsd")] use nix::mount::Nmount; -#[cfg(any(target_os = "macos", target_os = "linux"))] +#[cfg(target_os = "linux")] use nix::unistd; /// mount options. diff --git a/src/raw/connection/async_io.rs b/src/raw/connection/async_io.rs index ca2f154..b9dc901 100644 --- a/src/raw/connection/async_io.rs +++ b/src/raw/connection/async_io.rs @@ -266,10 +266,7 @@ impl BlockFuseConnection { .args(vec![options, mount_path]) .spawn()?; if !child.status().await?.success() { - return Err(io::Error::new( - io::ErrorKind::Other, - "fusermount run failed", - )); + return Err(io::Error::other("fusermount run failed")); } Ok(()) }); @@ -306,12 +303,12 @@ impl BlockFuseConnection { let fd = if let Some(ControlMessageOwned::ScmRights(fds)) = cmsgs.next() { if fds.is_empty() { - return Err(io::Error::new(io::ErrorKind::Other, "no fuse fd")); + return Err(io::Error::other("no fuse fd")); } fds[0] } else { - return Err(io::Error::new(io::ErrorKind::Other, "get fuse fd failed")); + return Err(io::Error::other("get fuse fd failed")); }; Ok(fd) diff --git a/src/raw/connection/tokio.rs b/src/raw/connection/tokio.rs index 5caf5d7..dbfb394 100644 --- a/src/raw/connection/tokio.rs +++ b/src/raw/connection/tokio.rs @@ -1,7 +1,10 @@ #[cfg(target_os = "macos")] use std::env; +#[cfg(all(target_os = "linux", feature = "unprivileged"))] +use std::ffi::OsString; #[cfg(any(target_os = "linux", target_os = "macos"))] use std::fs::File; +#[cfg(any(target_os = "linux", target_os = "freebsd"))] use std::fs::OpenOptions; use std::io; #[cfg(any(target_os = "linux", target_os = "macos"))] @@ -11,11 +14,10 @@ use std::ops::{Deref, DerefMut}; #[cfg(any( all(target_os = "linux", feature = "unprivileged"), target_os = "freebsd", - target_os = "macos", ))] use std::os::fd::OwnedFd; use std::os::fd::{AsFd, BorrowedFd}; -#[cfg(any(target_os = "freebsd", target_os = "macos"))] +#[cfg(target_os = "freebsd")] use std::os::unix::fs::OpenOptionsExt; #[cfg(any( all(target_os = "linux", feature = "unprivileged"), @@ -24,31 +26,29 @@ use std::os::unix::fs::OpenOptionsExt; use std::os::unix::io::RawFd; #[cfg(target_os = "macos")] use std::os::unix::io::{AsRawFd, FromRawFd}; -use std::pin::pin; -use std::sync::Arc; #[cfg(any( all(target_os = "linux", feature = "unprivileged"), - target_os = "macos" + target_os = "macos", ))] -use std::{ffi::OsString, path::Path}; +use std::path::Path; +use std::pin::pin; +use std::sync::Arc; use async_notify::Notify; use futures_util::lock::Mutex; use futures_util::{FutureExt, select}; +#[cfg(all(target_os = "linux", feature = "unprivileged"))] +use nix::fcntl::{FcntlArg, OFlag}; #[cfg(any( all(target_os = "linux", feature = "unprivileged"), - target_os = "freebsd", target_os = "macos", ))] -use nix::sys::uio; +use nix::sys::socket::{self, AddressFamily, ControlMessageOwned, MsgFlags, SockFlag, SockType}; #[cfg(any( all(target_os = "linux", feature = "unprivileged"), - target_os = "macos" + target_os = "freebsd", ))] -use nix::{ - fcntl::{FcntlArg, OFlag}, - sys::socket::{self, AddressFamily, ControlMessageOwned, MsgFlags, SockFlag, SockType}, -}; +use nix::sys::uio; #[cfg(any( all(target_os = "linux", feature = "unprivileged"), target_os = "freebsd", @@ -57,7 +57,6 @@ use tokio::io::Interest; #[cfg(any( all(target_os = "linux", feature = "unprivileged"), target_os = "freebsd", - target_os = "macos", ))] use tokio::io::unix::AsyncFd; #[cfg(any( @@ -72,7 +71,7 @@ use tokio::task; target_os = "macos" ))] use tracing::debug; -#[cfg(any(target_os = "freebsd", target_os = "macos"))] +#[cfg(target_os = "freebsd")] use tracing::warn; use super::CompleteIoResult; @@ -240,8 +239,6 @@ impl BlockFuseConnection { ) -> io::Result { use std::{thread, time::Duration}; - use tokio::time::sleep; - use crate::find_macfuse_mount; let (sock0, sock1) = match socket::socketpair( @@ -285,10 +282,7 @@ impl BlockFuseConnection { if status.success() { Ok(()) } else { - Err(io::Error::new( - io::ErrorKind::Other, - "fusermount run failed", - )) + Err(io::Error::other("fusermount run failed")) } }); @@ -324,12 +318,12 @@ impl BlockFuseConnection { }; let fd = if let Some(ControlMessageOwned::ScmRights(fds)) = cmsgs.next() { if fds.is_empty() { - return Err(io::Error::new(ErrorKind::Other, "no fuse fd")); + return Err(io::Error::other("no fuse fd")); } fds[0] } else { - return Err(io::Error::new(ErrorKind::Other, "get fuse fd failed")); + return Err(io::Error::other("get fuse fd failed")); }; Ok(fd) @@ -418,7 +412,7 @@ struct NonBlockFuseConnection { target_os = "freebsd", ))] impl NonBlockFuseConnection { - #[cfg(any(target_os = "freebsd", target_os = "macos"))] + #[cfg(target_os = "freebsd")] fn new() -> io::Result { #[cfg(target_os = "freebsd")] const DEV_FUSE: &str = "/dev/fuse"; @@ -430,7 +424,7 @@ impl NonBlockFuseConnection { .open(DEV_FUSE) { Err(e) => { - if e.kind() == ErrorKind::NotFound { + if e.kind() == io::ErrorKind::NotFound { warn!("Cannot open {}. Is the module loaded?", DEV_FUSE); } warn!("Cannot open {}. err: {:?}", DEV_FUSE, e); @@ -529,10 +523,7 @@ impl NonBlockFuseConnection { }) } - #[cfg(any( - all(target_os = "linux", feature = "unprivileged"), - target_os = "macos" - ))] + #[cfg(all(target_os = "linux", feature = "unprivileged"))] fn set_fd_non_blocking(fd: BorrowedFd) -> io::Result<()> { let flags = nix::fcntl::fcntl(fd, FcntlArg::F_GETFL).map_err(io::Error::from)?; debug!( diff --git a/src/raw/session.rs b/src/raw/session.rs index a381931..8b55c6b 100644 --- a/src/raw/session.rs +++ b/src/raw/session.rs @@ -7,9 +7,11 @@ use std::io::Error as IoError; use std::io::ErrorKind; use std::io::Result as IoResult; use std::num::NonZeroU32; +#[cfg(any(target_os = "linux", target_os = "freebsd"))] use std::os::fd::AsFd; use std::os::unix::ffi::OsStrExt; use std::os::unix::ffi::OsStringExt; +#[cfg(any(target_os = "linux", target_os = "freebsd"))] use std::os::unix::io::AsRawFd; use std::path::{Path, PathBuf}; use std::pin::{Pin, pin}; @@ -560,7 +562,7 @@ impl Session { } #[cfg(target_os = "macos")] - pub async fn mount>(mut self, fs: FS, mount_path: P) -> IoResult { + pub async fn mount>(self, fs: FS, mount_path: P) -> IoResult { self.mount_with_unprivileged(fs, mount_path).await } From 07111e0493136f2b5d144d0abe0e235f371bba12 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Fri, 13 Mar 2026 17:09:44 -0600 Subject: [PATCH 07/13] Fix the docs build with Rust nightly 1.92.0 and later --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 4a5cdbc..81ce7e8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,7 +18,7 @@ //! //! You must enable `async-io-runtime` or `tokio-runtime` feature. -#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] +#![cfg_attr(docsrs, feature(doc_cfg))] #[cfg(target_os = "macos")] use std::io::ErrorKind; From 209a00e5e7c97183676f5137c1a0eaa803923d1b Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Fri, 27 Mar 2026 19:57:04 +0000 Subject: [PATCH 08/13] ci: remove ca_root_nss workaround for FreeBSD --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 06e6307..fdae6ed 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -68,7 +68,7 @@ jobs: release: "15.0" usesh: true prepare: | - pkg install -y ca_root_nss curl + pkg install -y curl fetch https://sh.rustup.rs -o rustup.sh sh rustup.sh -y --profile=minimal run: | From 5b5103cfbd518fee60cd5a59e3908120406a9bce Mon Sep 17 00:00:00 2001 From: Nathaniel McCallum Date: Wed, 11 Mar 2026 00:18:59 -0400 Subject: [PATCH 09/13] fix: use error=0 for getxattr Size reply instead of ERANGE handle_getxattr was sending `error: libc::ERANGE` (positive 34) in the fuse_out_header when returning ReplyXAttr::Size. The FUSE protocol requires negative errno values for errors and 0 for success. The Linux kernel rejects positive error codes: if (oh->error <= -512 || oh->error > 0) { req->out.h.error = -EIO; This caused all getxattr size queries (size=0) to fail. The fix matches handle_listxattr, which already correctly uses error: 0 for the same Size reply path, and matches libfuse's fuse_reply_xattr which uses send_reply_ok (error=0). Fixes #130 --- src/raw/session.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/raw/session.rs b/src/raw/session.rs index 8b55c6b..091b920 100644 --- a/src/raw/session.rs +++ b/src/raw/session.rs @@ -2589,7 +2589,7 @@ impl Session { let out_header = fuse_out_header { len: (FUSE_OUT_HEADER_SIZE + FUSE_GETXATTR_OUT_SIZE) as u32, - error: libc::ERANGE, + error: 0, unique: request.unique, }; From b43347c129fad4bbbd43b2653dd3dce02569da1c Mon Sep 17 00:00:00 2001 From: Sam de Freyssinet Date: Sun, 8 Mar 2026 23:12:45 -0700 Subject: [PATCH 10/13] feat(init): add configurable max_background and congestion_threshold to ReplyInit Allow filesystems to override the kernel's default FUSE background request limits during init. The kernel defaults (max_background=12, congestion_threshold=9) are too low for high-concurrency workloads where many parallel reads are expected. Adds two optional fields to both `raw::ReplyInit` and `path::ReplyInit`: - `max_background: Option` - max pending background requests - `congestion_threshold: Option` - throttling threshold When `None`, the kernel defaults are preserved (backward compatible). Both `ReplyInit` structs are marked `#[non_exhaustive]` with a `new()` constructor so future fields can be added without breaking downstream code. --- examples/src/helloworld/main.rs | 4 +--- examples/src/memfs/main.rs | 4 +--- examples/src/path_memfs/main.rs | 4 +--- examples/src/poll/main.rs | 4 +--- src/path/inode_path_bridge.rs | 4 +++- src/path/reply.rs | 27 +++++++++++++++++++++++++++ src/raw/reply.rs | 27 +++++++++++++++++++++++++++ src/raw/session.rs | 4 ++-- 8 files changed, 63 insertions(+), 15 deletions(-) diff --git a/examples/src/helloworld/main.rs b/examples/src/helloworld/main.rs index 09a2de8..d9e1fab 100644 --- a/examples/src/helloworld/main.rs +++ b/examples/src/helloworld/main.rs @@ -33,9 +33,7 @@ struct HelloWorld; impl Filesystem for HelloWorld { async fn init(&self, _req: Request) -> Result { - Ok(ReplyInit { - max_write: NonZeroU32::new(16 * 1024).unwrap(), - }) + Ok(ReplyInit::new(NonZeroU32::new(16 * 1024).unwrap())) } async fn destroy(&self, _req: Request) {} diff --git a/examples/src/memfs/main.rs b/examples/src/memfs/main.rs index 2d69d54..6577b5b 100644 --- a/examples/src/memfs/main.rs +++ b/examples/src/memfs/main.rs @@ -198,9 +198,7 @@ impl Default for Fs { impl Filesystem for Fs { async fn init(&self, _req: Request) -> Result { - Ok(ReplyInit { - max_write: NonZeroU32::new(16 * 1024).unwrap(), - }) + Ok(ReplyInit::new(NonZeroU32::new(16 * 1024).unwrap())) } async fn destroy(&self, _req: Request) { diff --git a/examples/src/path_memfs/main.rs b/examples/src/path_memfs/main.rs index 2ab34d1..e4f0c36 100644 --- a/examples/src/path_memfs/main.rs +++ b/examples/src/path_memfs/main.rs @@ -147,9 +147,7 @@ impl Default for Fs { impl PathFilesystem for Fs { async fn init(&self, _req: Request) -> Result { - Ok(ReplyInit { - max_write: NonZeroU32::new(16 * 1024).unwrap(), - }) + Ok(ReplyInit::new(NonZeroU32::new(16 * 1024).unwrap())) } async fn destroy(&self, _req: Request) {} diff --git a/examples/src/poll/main.rs b/examples/src/poll/main.rs index f1089e2..e060dbf 100644 --- a/examples/src/poll/main.rs +++ b/examples/src/poll/main.rs @@ -32,9 +32,7 @@ struct Poll { impl Filesystem for Poll { async fn init(&self, _req: Request) -> Result { - Ok(ReplyInit { - max_write: NonZeroU32::new(16 * 1024).unwrap(), - }) + Ok(ReplyInit::new(NonZeroU32::new(16 * 1024).unwrap())) } async fn destroy(&self, _req: Request) {} diff --git a/src/path/inode_path_bridge.rs b/src/path/inode_path_bridge.rs index 8d6b1fc..3731b24 100644 --- a/src/path/inode_path_bridge.rs +++ b/src/path/inode_path_bridge.rs @@ -149,7 +149,9 @@ where let reply_init = self.path_filesystem.init(req).await?; Ok(ReplyInit { - max_write: reply_init.max_write, + max_background: reply_init.max_background, + congestion_threshold: reply_init.congestion_threshold, + ..ReplyInit::new(reply_init.max_write) }) } diff --git a/src/path/reply.rs b/src/path/reply.rs index 724447a..6db7d0c 100644 --- a/src/path/reply.rs +++ b/src/path/reply.rs @@ -72,10 +72,37 @@ impl From<(Inode, FileAttr)> for crate::raw::reply::FileAttr { } #[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] +#[non_exhaustive] /// init reply pub struct ReplyInit { /// the max write size pub max_write: NonZeroU32, + + /// Optional maximum number of pending background FUSE requests. + /// + /// The kernel queues background requests (readahead, async reads) up to this + /// limit. If `None`, defaults to `DEFAULT_MAX_BACKGROUND` (12). + pub max_background: Option, + + /// Optional congestion threshold for background FUSE requests. + /// + /// When the number of pending background requests exceeds this threshold, + /// the kernel starts throttling. If `None`, defaults to + /// `DEFAULT_CONGESTION_THRESHOLD` (75% of `max_background`). + pub congestion_threshold: Option, +} + +impl ReplyInit { + /// Create a new `ReplyInit` with the given max write size. + /// + /// All optional fields default to `None`, which uses kernel defaults. + pub fn new(max_write: NonZeroU32) -> Self { + Self { + max_write, + max_background: None, + congestion_threshold: None, + } + } } #[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] diff --git a/src/raw/reply.rs b/src/raw/reply.rs index 77f435c..79e2546 100644 --- a/src/raw/reply.rs +++ b/src/raw/reply.rs @@ -84,10 +84,37 @@ impl From for fuse_attr { } #[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] +#[non_exhaustive] /// init reply pub struct ReplyInit { /// the max write size pub max_write: NonZeroU32, + + /// Optional maximum number of pending background FUSE requests. + /// + /// The kernel queues background requests (readahead, async reads) up to this + /// limit. If `None`, defaults to `DEFAULT_MAX_BACKGROUND` (12). + pub max_background: Option, + + /// Optional congestion threshold for background FUSE requests. + /// + /// When the number of pending background requests exceeds this threshold, + /// the kernel starts throttling. If `None`, defaults to + /// `DEFAULT_CONGESTION_THRESHOLD` (75% of `max_background`). + pub congestion_threshold: Option, +} + +impl ReplyInit { + /// Create a new `ReplyInit` with the given max write size. + /// + /// All optional fields default to `None`, which uses kernel defaults. + pub fn new(max_write: NonZeroU32) -> Self { + Self { + max_write, + max_background: None, + congestion_threshold: None, + } + } } #[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] diff --git a/src/raw/session.rs b/src/raw/session.rs index 091b920..4e13f11 100644 --- a/src/raw/session.rs +++ b/src/raw/session.rs @@ -1289,8 +1289,8 @@ impl Session { minor: FUSE_KERNEL_MINOR_VERSION, max_readahead: init_in.max_readahead, flags: reply_flags, - max_background: DEFAULT_MAX_BACKGROUND, - congestion_threshold: DEFAULT_CONGESTION_THRESHOLD, + max_background: reply.max_background.unwrap_or(DEFAULT_MAX_BACKGROUND), + congestion_threshold: reply.congestion_threshold.unwrap_or(DEFAULT_CONGESTION_THRESHOLD), max_write: reply.max_write.get(), time_gran: DEFAULT_TIME_GRAN, max_pages: DEFAULT_MAX_PAGES, From 849e84c509348ef9691b2f416abbc616fe8c16bb Mon Sep 17 00:00:00 2001 From: dlicudi Date: Mon, 1 Jun 2026 01:17:21 +0200 Subject: [PATCH 11/13] fix(macos): don't kill the session on a transient reply error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit macFUSE can transiently reject a reply write to /dev/macfuse with EINVAL (or EAGAIN/EINTR) under heavy concurrent load — e.g. while Spotlight crawls the mount. The session loop treated ANY non-NotFound reply-send failure as fatal (send_failed.notify -> session returns Err), so a single transient failure tore down the whole mount and left it wedged (every later op ENXIO). Route send1/send2/send3's error handling through a shared handle_send_error that treats transient, per-request errors (ENOENT, EINVAL, EAGAIN, EINTR) as recoverable — drop that one reply and keep serving — while connection-gone errors (ENODEV/EBADF on unmount) stay fatal so a clean unmount still stops the session. Policy extracted to a pure is_recoverable_reply_error fn with unit tests. --- src/raw/session.rs | 105 +++++++++++++++++++++++++++++++++------------ 1 file changed, 77 insertions(+), 28 deletions(-) diff --git a/src/raw/session.rs b/src/raw/session.rs index 4e13f11..7e02696 100644 --- a/src/raw/session.rs +++ b/src/raw/session.rs @@ -112,6 +112,43 @@ pub(crate) struct ResponseSender { } impl ResponseSender { + /// Handle a failure while writing a reply to the kernel. + /// + /// A failed reply to a *single* request must not tear down the whole + /// session — only a genuinely dead connection should. We therefore treat + /// transient, per-request errors as recoverable (drop this one reply and + /// keep serving): + /// - `NotFound` (ENOENT): the request was interrupted. + /// - `InvalidInput` (EINVAL), `WouldBlock` (EAGAIN), `Interrupted` (EINTR): + /// macFUSE can transiently reject a device write under heavy concurrent + /// load (e.g. while Spotlight crawls the mount). Killing the mount over + /// one such error left the volume wedged (every later op `ENXIO`). + /// + /// Connection-gone errors (e.g. ENODEV/EBADF on unmount) map to other + /// kinds and still notify `send_failed`, so a clean unmount stops the + /// session as before. + fn handle_send_error(&self, err: IoError) { + if Self::is_recoverable_reply_error(err.kind()) { + warn!("dropping a failed fuse reply, session continues: {}", err); + } else { + error!("reply fuse failed {}", err); + self.send_failed.notify(); + } + } + + /// Whether a failed reply write is a transient, per-request error (session + /// keeps running) rather than a dead connection (fatal). Pure function so + /// the policy is unit-testable. + fn is_recoverable_reply_error(kind: ErrorKind) -> bool { + matches!( + kind, + ErrorKind::NotFound + | ErrorKind::InvalidInput + | ErrorKind::WouldBlock + | ErrorKind::Interrupted + ) + } + /// send response with only header, no data pub(crate) async fn send1(&self, header: &fuse_out_header) { if let Err(err) = self @@ -120,15 +157,7 @@ impl ResponseSender { .await .1 { - if err.kind() == ErrorKind::NotFound { - warn!( - "may reply interrupted fuse request, ignore this error {}", - err - ); - } else { - error!("reply fuse failed {}", err); - self.send_failed.notify(); - } + self.handle_send_error(err); } } @@ -140,15 +169,7 @@ impl ResponseSender { .await .1 { - if err.kind() == ErrorKind::NotFound { - warn!( - "may reply interrupted fuse request, ignore this error {}", - err - ); - } else { - error!("reply fuse failed {}", err); - self.send_failed.notify(); - } + self.handle_send_error(err); } } @@ -164,15 +185,7 @@ impl ResponseSender { .await .1 { - if err.kind() == ErrorKind::NotFound { - warn!( - "may reply interrupted fuse request, ignore this error {}", - err - ); - } else { - error!("reply fuse failed {}", err); - self.send_failed.notify(); - } + self.handle_send_error(err); } } @@ -1290,7 +1303,9 @@ impl Session { max_readahead: init_in.max_readahead, flags: reply_flags, max_background: reply.max_background.unwrap_or(DEFAULT_MAX_BACKGROUND), - congestion_threshold: reply.congestion_threshold.unwrap_or(DEFAULT_CONGESTION_THRESHOLD), + congestion_threshold: reply + .congestion_threshold + .unwrap_or(DEFAULT_CONGESTION_THRESHOLD), max_write: reply.max_write.get(), time_gran: DEFAULT_TIME_GRAN, max_pages: DEFAULT_MAX_PAGES, @@ -4054,3 +4069,37 @@ where #[cfg(all(not(feature = "tokio-runtime"), feature = "async-io-runtime"))] task::spawn(fut.instrument(span)).detach() } + +#[cfg(test)] +mod reply_error_policy_tests { + use std::io::Error as IoError; + + use super::ResponseSender; + + /// A failed reply to a single request caused by a transient/per-request + /// condition must NOT tear down the session. These are the errors macFUSE + /// can hand back under heavy concurrent load. + #[test] + fn transient_reply_errors_are_recoverable() { + for code in [libc::ENOENT, libc::EINVAL, libc::EAGAIN, libc::EINTR] { + let kind = IoError::from_raw_os_error(code).kind(); + assert!( + ResponseSender::is_recoverable_reply_error(kind), + "errno {code} ({kind:?}) should be recoverable" + ); + } + } + + /// A dead connection must stay fatal so a clean unmount still stops the + /// session (otherwise it would spin forever). + #[test] + fn connection_gone_errors_are_fatal() { + for code in [libc::ENODEV, libc::EBADF, libc::EPIPE, libc::ECONNRESET] { + let kind = IoError::from_raw_os_error(code).kind(); + assert!( + !ResponseSender::is_recoverable_reply_error(kind), + "errno {code} ({kind:?}) should be fatal" + ); + } + } +} From 43b2ee07f43bc8193d789116f87205d0de43b31a Mon Sep 17 00:00:00 2001 From: Duane Licudi Date: Mon, 22 Jun 2026 00:05:33 +0200 Subject: [PATCH 12/13] fix(macos): comma-join mount options so all -o flags apply macOS build() emitted repeated space-separated -o flags as a single mount- helper argument, so every option after the first (allow_root, allow_other, or caller custom_options like nobrowse) was silently dropped. Join with commas under one -o, matching the Linux builder. --- src/mount_options.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/mount_options.rs b/src/mount_options.rs index 8fcc0df..88e3c5c 100644 --- a/src/mount_options.rs +++ b/src/mount_options.rs @@ -245,20 +245,25 @@ impl MountOptions { #[cfg(target_os = "macos")] pub(crate) fn build(&self) -> OsString { - let mut opts = vec![String::from("-o fsname=ofs")]; + // macFUSE expects a single `-o` followed by a comma-separated option + // list (like the Linux builder), NOT repeated space-separated `-o` + // flags. The old form (`-o fsname=ofs -o allow_root`) was passed to the + // mount helper as one argument, so every option after the first was + // silently dropped — e.g. a caller-supplied `nobrowse` never took effect. + let mut opts = vec![String::from("fsname=ofs")]; if self.allow_root { - opts.push("-o allow_root".to_string()); + opts.push("allow_root".to_string()); } if self.allow_other { - opts.push("-o allow_other".to_string()); + opts.push("allow_other".to_string()); } - let mut options = OsString::from(opts.join(" ")); + let mut options = OsString::from(format!("-o {}", opts.join(","))); if let Some(custom_options) = &self.custom_options { - options.push(" "); + options.push(","); options.push(custom_options); } From 74abf558382cd20021ca10c5307c4e1b515152fa Mon Sep 17 00:00:00 2001 From: Duane Licudi Date: Mon, 22 Jun 2026 00:50:34 +0200 Subject: [PATCH 13/13] fix(macos): log recoverable reply drops at debug, not warn MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A recoverable reply-send failure (interrupted/cancelled request) is the expected, harmless case the resilience patch exists to absorb. macOS file browsers crawl the mount and routinely interrupt their own requests, so these occur tens of times per second under normal use — logging each at WARN floods the log. Demote to debug; the session-continues handling is unchanged. --- src/raw/session.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/raw/session.rs b/src/raw/session.rs index 7e02696..d1bd714 100644 --- a/src/raw/session.rs +++ b/src/raw/session.rs @@ -129,7 +129,13 @@ impl ResponseSender { /// session as before. fn handle_send_error(&self, err: IoError) { if Self::is_recoverable_reply_error(err.kind()) { - warn!("dropping a failed fuse reply, session continues: {}", err); + // Expected and harmless under normal load: macOS file browsers + // (Finder, Spotlight, open/save panels) constantly crawl the mount + // and routinely interrupt their own requests, so a steady stream of + // recoverable drops is the norm. Logging each at WARN floods the log + // (tens per second). Keep it at debug for diagnostics only — the + // drop itself is already handled by continuing the session. + debug!("dropping a failed fuse reply, session continues: {}", err); } else { error!("reply fuse failed {}", err); self.send_failed.notify();