Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
66493c4
breaking-feat: passthrough API
khanhtranngoccva Jan 16, 2026
c1589d0
fix: remove extra incompatible backing ID import
khanhtranngoccva Jan 16, 2026
258611f
fix: repair gated features
khanhtranngoccva Jan 16, 2026
dcc4823
fix: minor dead code suppressions
khanhtranngoccva Jan 16, 2026
3ae9a8e
breaking-feat: passthrough API
khanhtranngoccva Jan 16, 2026
f52ee37
fix: remove extra incompatible backing ID import
khanhtranngoccva Jan 16, 2026
e64706c
feat: enable passthrough for file creates
khanhtranngoccva Jan 20, 2026
2702e87
feat: add stub weak pointer for parity with weak api
khanhtranngoccva Jan 20, 2026
980ab40
fix: add API parity
khanhtranngoccva Jan 21, 2026
3d619e2
fix: open_backing should not require object ownership
khanhtranngoccva Jan 26, 2026
4b02585
fix: minor doc and ide flag fixes
khanhtranngoccva Jan 26, 2026
230f792
doc: add kernel caveat to passthrough ID
khanhtranngoccva Jan 26, 2026
91708e0
fix: change PoC fuser impl to bleeding-edge branch
khanhtranngoccva Jan 28, 2026
a2fa39c
misc: use bleeding edge fuser library
khanhtranngoccva Jan 28, 2026
2b3665b
fix: should use fuser::OpenFlags
khanhtranngoccva Jan 28, 2026
2671ea8
fix: integrate newest changes from fuser
khanhtranngoccva Feb 3, 2026
a941d82
fix: test fixes
khanhtranngoccva Feb 3, 2026
3f77b1d
fix: example fixes
khanhtranngoccva Feb 3, 2026
c03c18f
fix: adopt new code from master branch
khanhtranngoccva Feb 6, 2026
c2549a4
fix: example crate fixes
khanhtranngoccva Feb 6, 2026
77ae37f
fix: separate join with umount_and_join()
khanhtranngoccva Mar 6, 2026
5807427
fix: minor compiler errors
khanhtranngoccva Mar 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
{
"rust-analyzer.cargo.features": [
"serial",
"passthrough"
],
"files.associations": {
"*.rs.j2": "rust",
},
"rust-analyzer.cargo.features": ["serial"],
"rust-analyzer.files.exclude": [
"templates"
]
}
}
8 changes: 6 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ serial = []
parallel = ["dep:threadpool"]
async = ["dep:async-trait", "dep:tokio"]
deadlock_detection = ["parallel", "dep:parking_lot"]

passthrough = []

[dependencies]
# Core dependencies
log = "0.4"
libc = "0.2"
fuser = "0.16"
fuser = { version = "0.16" }
bitflags = "2.10"

# Parallel dependencies
Expand All @@ -43,3 +43,7 @@ askama = { version = "0.15.4", features = ["derive"] }

[package.metadata.docs.rs]
features = ["parallel"]

[patch.crates-io]
# Use the updated branch
fuser = { git = "https://github.com/khanhtranngoccva/fuser", branch = "bleeding-edge" }
11 changes: 7 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,13 @@ impl FuseHandler<PathBuf> for MyFS {

fn main() -> std::io::Result<()> {
let fs = MyFS { inner: Box::new(DefaultFuseHandler::new()) };
#[cfg(feature="serial")]
easy_fuser::mount(fs, Path::new("/mnt/myfs"), &[])?;
#[cfg(not(feature="serial"))]
easy_fuser::mount(fs, Path::new("/mnt/myfs"), &[], 4)?;
let config = MountConfig {
mount_options: vec![],
acl: SessionACL::Owner,
#[cfg(feature = "parallel")]
num_threads: 4,
};
easy_fuser::mount(fs, Path::new("/mnt/myfs"), &config)?;
Ok(())
}
```
Expand Down
4 changes: 2 additions & 2 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ fn main() -> std::io::Result<()> {
let content = FuseHandlerTemplate { mode }.render()?;
fs::write(mode_dir.join("fuse_handler.rs"), content)?;

let content = MoutingTemplate { mode }.render()?;
fs::write(mode_dir.join("mouting.rs"), content)?;
let content = MountingTemplate { mode }.render()?;
fs::write(mode_dir.join("mounting.rs"), content)?;
}

Ok(())
Expand Down
5 changes: 4 additions & 1 deletion examples/ftp_fs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,7 @@ tempfile = "3.2"
libunftp = "0.20"
unftp-sbe-fs = "0.2"
async-trait = "0.1.68"
tokio = { version = "1.42", features = ["full"] }
tokio = { version = "1.42", features = ["full"] }

[patch.crates-io]
fuser = { git = "https://github.com/khanhtranngoccva/fuser", branch = "bleeding-edge" }
4 changes: 2 additions & 2 deletions examples/ftp_fs/src/filesystem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ impl FuseHandler<PathBuf> for FtpFs {
_file_handle: BorrowedFileHandle,
offset: SeekFrom,
size: u32,
_flags: FUSEOpenFlags,
_lock_owner: Option<u64>,
_flags: OpenFlags,
_lock_owner: Option<LockOwner>,
) -> FuseResult<Vec<u8>> {
self.with_ftp(|ftp| {
let mut cursor = ftp.retr_as_buffer(file_id.to_str().unwrap())?;
Expand Down
10 changes: 8 additions & 2 deletions examples/ftp_fs/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@

use std::path::PathBuf;
use std::process::exit;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};

use clap::{Parser, ValueEnum};
use ctrlc;
Expand Down Expand Up @@ -139,7 +139,13 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("Mount point: {:?}", &mount_point);

// Mount the filesystem
easy_fuser::mount(ftp_fs, &mount_point, &[], 4)?;
let config = easy_fuser::prelude::MountConfig {
mount_options: vec![],
acl: easy_fuser::prelude::SessionACL::Owner,
num_threads: 4,
};

easy_fuser::mount(ftp_fs, &mount_point, &config)?;

// If we reach here, the filesystem has been unmounted normally
cleanup(&mount_point, &once_flag);
Expand Down
5 changes: 4 additions & 1 deletion examples/hello_fs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,7 @@ logging = ["dep:env_logger", "dep:log"]
[dependencies]
easy_fuser = { path = "../..", features = ["serial"] }
log = { version = "0.4", optional = true }
env_logger = { version = "0.11", optional = true }
env_logger = { version = "0.11", optional = true }

[patch.crates-io]
fuser = { git = "https://github.com/khanhtranngoccva/fuser", branch = "bleeding-edge" }
14 changes: 9 additions & 5 deletions examples/hello_fs/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ const HELLO_DIR_ATTR: (Inode, FileAttribute) = (
const HELLO_TXT_CONTENT: &str = "Hello World!\n";

const HELLO_TXT_ATTR: (Inode, FileAttribute) = (
Inode::from(2),
Inode::new(2),
FileAttribute {
size: 13,
blocks: 1,
Expand Down Expand Up @@ -110,8 +110,8 @@ impl FuseHandler<Inode> for HelloFS {
_file_handle: BorrowedFileHandle,
seek: SeekFrom,
size: u32,
_flags: FUSEOpenFlags,
_lock_owner: Option<u64>,
_flags: OpenFlags,
_lock_owner: Option<LockOwner>,
) -> FuseResult<Vec<u8>> {
if file_id == HELLO_TXT_ATTR.0 {
let offset = match seek {
Expand Down Expand Up @@ -166,8 +166,12 @@ fn main() {
.try_init();

let mountpoint = std::env::args().nth(1).expect("Usage: hello <MOUNTPOINT>");
let options = vec![MountOption::RO, MountOption::FSName("hello".to_string())];

let config = easy_fuser::prelude::MountConfig {
mount_options: vec![],
acl: easy_fuser::prelude::SessionACL::Owner,
};

println!("Mounting FTP filesystem...");
easy_fuser::mount(HelloFS::new(), Path::new(&mountpoint), &options).unwrap();
easy_fuser::mount(HelloFS::new(), Path::new(&mountpoint), &config).unwrap();
}
5 changes: 4 additions & 1 deletion examples/in_memory_fs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,7 @@ logging = ["dep:env_logger", "dep:log"]
[dependencies]
easy_fuser = { path = "../..", features = ["parallel"] }
log = { version = "0.4", optional = true }
env_logger = { version = "0.11", optional = true }
env_logger = { version = "0.11", optional = true }

[patch.crates-io]
fuser = { git = "https://github.com/khanhtranngoccva/fuser", branch = "bleeding-edge" }
17 changes: 10 additions & 7 deletions examples/in_memory_fs/src/filesystem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ impl InMemoryFS {
pub fn new() -> Self {
let mut fs = DataBank {
inodes: HashMap::new(),
next_inode: Inode::from(2), // Root is 1
next_inode: Inode::new(2), // Root is 1
};

// Create root directory
Expand Down Expand Up @@ -155,11 +155,13 @@ impl FuseHandler<Inode> for InMemoryFS {
mode: u32,
_umask: u32,
_flags: OpenFlags,
_helper: CreateHelper,
) -> Result<
(
OwnedFileHandle,
(Inode, FileAttribute),
FUSEOpenResponseFlags,
Option<PassthroughBackingId>,
),
PosixError,
> {
Expand Down Expand Up @@ -204,6 +206,7 @@ impl FuseHandler<Inode> for InMemoryFS {
unsafe { OwnedFileHandle::from_raw(0) },
(new_inode.clone(), attr),
FUSEOpenResponseFlags::empty(),
None,
))
} else {
Err(ErrorKind::FileNotFound.to_error(""))
Expand All @@ -215,8 +218,8 @@ impl FuseHandler<Inode> for InMemoryFS {
req: &RequestInfo,
file_id: Inode,
_file_handle: BorrowedFileHandle,
offset: i64,
length: i64,
offset: u64,
length: u64,
mode: FallocateFlags,
) -> FuseResult<()> {
self.access(req, file_id.clone(), AccessMask::CAN_WRITE)?;
Expand Down Expand Up @@ -260,7 +263,7 @@ impl FuseHandler<Inode> for InMemoryFS {
_req: &RequestInfo,
_file_id: Inode,
_file_handle: BorrowedFileHandle,
_lock_owner: u64,
_lock_owner: LockOwner,
) -> FuseResult<()> {
Ok(())
}
Expand Down Expand Up @@ -363,8 +366,8 @@ impl FuseHandler<Inode> for InMemoryFS {
_fh: BorrowedFileHandle,
offset: SeekFrom,
size: u32,
_flags: FUSEOpenFlags,
_lock_owner: Option<u64>,
_flags: OpenFlags,
_lock_owner: Option<LockOwner>,
) -> FuseResult<Vec<u8>> {
self.access(req, ino.clone(), AccessMask::CAN_READ)?;
let fs = self.fs.lock().unwrap();
Expand Down Expand Up @@ -579,7 +582,7 @@ impl FuseHandler<Inode> for InMemoryFS {
data: Vec<u8>,
_write_flags: FUSEWriteFlags,
_flags: OpenFlags,
_lock_owner: Option<u64>,
_lock_owner: Option<LockOwner>,
) -> FuseResult<u32> {
self.access(req, ino.clone(), AccessMask::CAN_WRITE)?;
let mut fs = self.fs.lock().unwrap();
Expand Down
61 changes: 22 additions & 39 deletions examples/in_memory_fs/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#![doc = include_str!("../README.md")]

use easy_fuser::prelude::*;
use std::ffi::OsStr;
use std::path::Path;
use std::fs;

const README_CONTENT: &[u8] = include_bytes!("../README.md") as &[u8];

Expand All @@ -11,38 +11,8 @@ pub use filesystem::InMemoryFS;

fn create_memory_fs() -> InMemoryFS {
let memoryfs = InMemoryFS::new();
#[cfg(feature = "readme")]
{
// An example of interacting directly with the filesystem
let request_info = RequestInfo {
id: 0,
uid: 0,
gid: 0,
pid: 0,
}; // dummy RequestInfo
let (fd, (inode, _), _) = memoryfs
.create(
&request_info,
ROOT_INODE,
OsStr::new("README.md"),
0o755,
0,
OpenFlags::empty(),
)
.unwrap();
let _ = memoryfs
.write(
&request_info,
inode,
fd.borrow(),
SeekFrom::Start(0),
README_CONTENT.to_vec(),
FUSEWriteFlags::empty(),
OpenFlags::empty(),
None,
)
.unwrap();
}
// NOTE: manual call example here is removed because the [`CreateHelper`]
// parameter is not supported
memoryfs
}

Expand All @@ -58,13 +28,26 @@ fn main() {
let mountpoint = std::env::args()
.nth(1)
.expect("Usage: in_memory_fs <MOUNTPOINT>");
let options = vec![
MountOption::RW,
MountOption::FSName("in_memory_fs".to_string()),
];

let config = MountConfig {
mount_options: vec![],
acl: SessionACL::Owner,
num_threads: 4,
};
let memoryfs = create_memory_fs();

println!("Mounting filesystem...");
easy_fuser::mount(memoryfs, Path::new(&mountpoint), &options, 1).unwrap();
let session = easy_fuser::spawn_mount(memoryfs, Path::new(&mountpoint), &config).unwrap();
println!("Filesystem mounted");
fs::write(Path::new(&mountpoint).join("README.md"), README_CONTENT)
.expect("Failed to write README.md");

std::io::stdin().read_line(&mut String::new()).unwrap();
session
.join(&[])
.map_err(|(_session, error)| {
println!("Error unmounting filesystem: {:?}", error);
error
})
.unwrap();
println!("Filesystem unmounted");
}
5 changes: 4 additions & 1 deletion examples/passthrough_fs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,7 @@ description = "A FUSE passthrough filesystem example using easy_fuser"
[dependencies]
easy_fuser = { path = "../..", features = ["parallel"] }
clap = { version = "4.5", features = ["derive"] }
ctrlc = "3.4"
ctrlc = "3.4"

[patch.crates-io]
fuser = { git = "https://github.com/khanhtranngoccva/fuser", branch = "bleeding-edge" }
13 changes: 9 additions & 4 deletions examples/passthrough_fs/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
use clap::Parser;
use ctrlc;
use easy_fuser::prelude::*;
use easy_fuser::templates::mirror_fs::*;
use easy_fuser::templates::DefaultFuseHandler;
use easy_fuser::templates::mirror_fs::*;
use std::path::PathBuf;
use std::process::exit;
use std::process::Command;
use std::process::exit;
use std::sync::Arc;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering;
use std::sync::Arc;

#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
Expand Down Expand Up @@ -75,7 +75,12 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("Source directory: {:?}", fs.source_dir());

// Mount the filesystem
mount(fs, &mntpoint, &[], 1)?;
let config = easy_fuser::prelude::MountConfig {
mount_options: vec![],
acl: easy_fuser::prelude::SessionACL::Owner,
num_threads: 1,
};
mount(fs, &mntpoint, &config)?;

// If we reach here, the filesystem has been unmounted normally
cleanup(&mntpoint, &once_flag);
Expand Down
3 changes: 3 additions & 0 deletions examples/random_fs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,6 @@ edition = "2021"
[dependencies]
easy_fuser = { path = "../..", features = ["parallel"] }
rand = "0.8.5"

[patch.crates-io]
fuser = { git = "https://github.com/khanhtranngoccva/fuser", branch = "bleeding-edge" }
Loading