Skip to main content

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}