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;
21mod directory_cache;
22mod fuserng;
23mod inode_table;
24mod types;
25
26pub use crate::fuserng::*;
27pub use crate::types::*;
28pub use fuser::FileType;
29pub use fuser::KernelConfig;
30pub use fuser::MountOption;
31// Forward to similarly-named fuser functions to work around deprecation for now.
32// When these are removed, we'll have to either reimplement or break reverse compat.
33// Keep the doc comments in sync with those in fuser.
34
35use std::io;
36use std::path::Path;
37
38/// Number of fuser event-loop threads used to serve a mount.
39/// This configures fuser session threading, not an internal worker pool.
40#[derive(Debug, Default)]
41pub enum ThreadCount {
42    /// Use the current machine parallelism as reported by the standard library.
43    #[default]
44    Default,
45    /// Use an explicit number of fuser event-loop threads.
46    NumThreads(usize),
47}
48
49impl ThreadCount {
50    fn value(&self) -> usize {
51        match self {
52            Self::Default => std::thread::available_parallelism().unwrap().into(),
53            Self::NumThreads(num_threads) => *num_threads,
54        }
55    }
56}
57
58impl From<usize> for ThreadCount {
59    fn from(value: usize) -> Self {
60        ThreadCount::NumThreads(value)
61    }
62}
63/// Mount the given filesystem to the given mountpoint. This function will not return until the
64/// filesystem is unmounted.
65#[inline(always)]
66pub fn mount<FS: fuser::Filesystem, P: AsRef<Path>>(
67    fs: FS,
68    mountpoint: P,
69    options: &[MountOption],
70    num_threads: ThreadCount,
71) -> io::Result<()> {
72    let mut config = fuser::Config::default();
73    config.mount_options = options.to_vec();
74    let num_threads = num_threads.value();
75    if num_threads > 0 {
76        config.n_threads = Some(num_threads);
77    }
78    fuser::mount2(fs, mountpoint, &config)
79}
80
81/// Mount the given filesystem to the given mountpoint. This function spawns a background thread to
82/// handle filesystem operations while being mounted and therefore returns immediately. The
83/// returned handle should be stored to reference the mounted filesystem. If it's dropped, the
84/// filesystem will be unmounted.
85#[inline(always)]
86pub fn spawn_mount<FS: fuser::Filesystem + Send + 'static, P: AsRef<Path>>(
87    fs: FS,
88    mountpoint: P,
89    options: &[MountOption],
90    num_threads: ThreadCount,
91) -> io::Result<fuser::BackgroundSession> {
92    let mut config = fuser::Config::default();
93    config.mount_options = options.to_vec();
94    let num_threads = num_threads.value();
95    if num_threads > 0 {
96        config.n_threads = Some(num_threads);
97    }
98    fuser::spawn_mount2(fs, mountpoint, &config)
99}