fuser_ng/lib.rs
1#![doc = include_str!("../DOC.md")]
2
3// FuserNG -- A higher-level FUSE (Filesystem in Userspace) interface and wrapper around the
4// low-level `fuser`` library that makes implementing a filesystem a bit easier.
5//
6// FuserNG translates inodes to paths and simplifies some details of filesystem implementation,
7// for example: splitting the `setattr` call
8// into multiple separate operations, and simplifying the `readdir` call so that filesystems don't
9// need to deal with pagination.
10//
11// To implement a filesystem, implement the `Filesystem` trait. Not all functions in it need to
12// be implemented -- the default behavior is to return `ENOSYS` ("Function not implemented"). For
13// example, a read-only filesystem can skip implementing the `write` call and many others.
14
15//
16// Copyright (c) 2016-2022 by William R. Fraser, 2026 by François NT
17//
18
19#[macro_use]
20extern crate log;
21#[cfg(feature = "async")]
22mod r#async;
23mod directory_cache;
24mod fuserng;
25mod inode_table;
26mod types;
27#[cfg(feature = "async")]
28pub use r#async::{AsyncFilesystem, AsyncFuserNG};
29#[cfg(feature = "async")]
30pub mod asynchronous {
31 pub use crate::AsyncFilesystem as Filesystem;
32 pub use crate::AsyncFuserNG as FuserNG;
33}
34pub use crate::fuserng::*;
35pub use crate::types::*;
36pub use fuser::FileType;
37pub use fuser::KernelConfig;
38pub use fuser::MountOption;
39// Forward to similarly-named fuser functions to work around deprecation for now.
40// When these are removed, we'll have to either reimplement or break reverse compat.
41// Keep the doc comments in sync with those in fuser.
42
43use std::io;
44use std::path::Path;
45
46/// Number of fuser event-loop threads used to serve a mount.
47/// This configures fuser session threading, not an internal worker pool.
48#[derive(Debug, Default)]
49pub enum ThreadCount {
50 /// Use the current machine parallelism as reported by the standard library.
51 #[default]
52 Default,
53 /// Use an explicit number of fuser event-loop threads.
54 NumThreads(usize),
55}
56
57impl ThreadCount {
58 fn value(&self) -> usize {
59 match self {
60 Self::Default => std::thread::available_parallelism().unwrap().into(),
61 Self::NumThreads(num_threads) => *num_threads,
62 }
63 }
64}
65
66impl From<usize> for ThreadCount {
67 fn from(value: usize) -> Self {
68 ThreadCount::NumThreads(value)
69 }
70}
71/// Mount the given filesystem to the given mountpoint. This function will not return until the
72/// filesystem is unmounted.
73#[inline(always)]
74pub fn mount<FS: fuser::Filesystem, P: AsRef<Path>>(
75 fs: FS,
76 mountpoint: P,
77 options: &[MountOption],
78 num_threads: ThreadCount,
79) -> io::Result<()> {
80 let mut config = fuser::Config::default();
81 config.mount_options = options.to_vec();
82 let num_threads = num_threads.value();
83 if num_threads > 0 {
84 config.n_threads = Some(num_threads);
85 }
86 fuser::mount2(fs, mountpoint, &config)
87}
88
89/// Mount the given filesystem to the given mountpoint. This function spawns a background thread to
90/// handle filesystem operations while being mounted and therefore returns immediately. The
91/// returned handle should be stored to reference the mounted filesystem. If it's dropped, the
92/// filesystem will be unmounted.
93#[inline(always)]
94pub fn spawn_mount<FS: fuser::Filesystem + Send + 'static, P: AsRef<Path>>(
95 fs: FS,
96 mountpoint: P,
97 options: &[MountOption],
98 num_threads: ThreadCount,
99) -> io::Result<fuser::BackgroundSession> {
100 let mut config = fuser::Config::default();
101 config.mount_options = options.to_vec();
102 let num_threads = num_threads.value();
103 if num_threads > 0 {
104 config.n_threads = Some(num_threads);
105 }
106 fuser::spawn_mount2(fs, mountpoint, &config)
107}