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}