From 14db0a7456cbfee18b9b3046181654df3bc32916 Mon Sep 17 00:00:00 2001 From: Valentin Lorentz Date: Sat, 16 Aug 2025 13:10:59 +0200 Subject: [PATCH 1/2] Fix typos in the documentation and add a few links --- src/errno.rs | 4 +- src/helper.rs | 8 ++-- src/lib.rs | 22 ++++++----- src/notify.rs | 4 +- src/path/mod.rs | 4 +- src/path/path_filesystem.rs | 76 ++++++++++++++++++++----------------- src/raw/filesystem.rs | 34 +++++++++-------- src/raw/mod.rs | 10 ++--- src/raw/session.rs | 4 +- 9 files changed, 90 insertions(+), 76 deletions(-) diff --git a/src/errno.rs b/src/errno.rs index b9b59e9..6db76f9 100644 --- a/src/errno.rs +++ b/src/errno.rs @@ -4,7 +4,7 @@ use std::io::Error as IoError; use std::os::raw::c_int; #[derive(Debug, Copy, Clone, Eq, PartialEq)] -/// linux errno wrap. +/// linux errno wrapper. pub struct Errno(c_int); impl From for c_int { @@ -19,7 +19,7 @@ impl From for Errno { } } -/// When raw os error is undefined, will return Errno(libc::EIO) +/// When raw os error is undefined, will return `Errno(libc::EIO)` impl From for Errno { fn from(err: IoError) -> Self { if let Some(errno) = err.raw_os_error() { diff --git a/src/helper.rs b/src/helper.rs index b87f3cc..819e6c1 100644 --- a/src/helper.rs +++ b/src/helper.rs @@ -22,8 +22,8 @@ pub fn get_first_null_position(data: impl AsRef<[u8]>) -> Option { data.as_ref().iter().position(|char| *char == 0) } -// Some platforms like Linux x86_64 have mode_t = u32, and lint warns of a trivial_numeric_casts. -// But others like macOS x86_64 have mode_t = u16, requiring a typecast. So, just silence lint. +// Some platforms like Linux x86_64 have mode_t = u32, and linters warn of a trivial_numeric_casts. +// But others like macOS x86_64 have mode_t = u16, requiring a typecast. So, just silence linters. #[cfg(target_os = "linux")] #[allow(trivial_numeric_casts)] /// returns the mode for a given file kind and permission @@ -31,8 +31,8 @@ pub const fn mode_from_kind_and_perm(kind: FileType, perm: u16) -> u32 { kind.const_into_mode_t() | perm as mode_t } -// Some platforms like Linux x86_64 have mode_t = u32, and lint warns of a trivial_numeric_casts. -// But others like macOS x86_64 have mode_t = u16, requiring a typecast. So, just silence lint. +// Some platforms like Linux x86_64 have mode_t = u32, and linters warn of a trivial_numeric_casts. +// But others like macOS x86_64 have mode_t = u16, requiring a typecast. So, just silence linters. #[cfg(all( not(target_os = "linux"), any(target_os = "freebsd", target_os = "macos") diff --git a/src/lib.rs b/src/lib.rs index c92df96..53b47d1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,20 +3,22 @@ //! This is an improved rewrite of the FUSE user-space library to fully take advantage of Rust's //! architecture. //! -//! This library doesn't depend on `libfuse`, unless enable `unprivileged` feature, this feature -//! will support mount the filesystem without root permission by using `fusermount3` binary. +//! This library doesn't depend on `libfuse`, unless the `unprivileged` feature is enabled. +//! This feature adds support for mounting the filesystem without root permission by using +//! `fusermount3` binary. //! //! # Features: //! //! - `file-lock`: enable POSIX file lock feature. -//! - `async-io-runtime`: use [async_io](https://docs.rs/async-io) and -//! [async-global-executor](https://docs.rs/async-global-executor) to drive async io and task. -//! - `tokio-runtime`: use [tokio](https://docs.rs/tokio) runtime to drive async io and task. -//! - `unprivileged`: allow mount filesystem without root permission by using `fusermount3`. +//! - `async-io-runtime`: use [async_io](https://docs.rs/async-io) or +//! [async-global-executor](https://docs.rs/async-global-executor) to drive async I/O and tasks. +//! - `tokio-runtime`: use [tokio](https://docs.rs/tokio) runtime to drive async I/O and tasks. +//! - `unprivileged`: allow mounting filesystems without root permission by using `fusermount3`. //! //! # Notes: //! -//! You must enable `async-io-runtime` or `tokio-runtime` feature. +//! You must enable either the `async-io-runtime` or `tokio-runtime` features, but not both +//! or the crate won't compile. #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] @@ -98,7 +100,7 @@ impl From for mode_t { } } -/// the setattr argument. +/// the [`setattr`](crate::path::PathFilesystem::setattr) argument #[derive(Debug, Clone, Default, Eq, PartialEq)] pub struct SetAttr { /// set file or directory mode. @@ -127,7 +129,7 @@ pub struct SetAttr { pub flags: Option, } -/// Helper for constructing Timestamps from fuse_setattr_in, which sign-casts +/// Helper for constructing [`Timestamp`s](Timestamp) from fuse_setattr_in, which sign-casts /// the seconds. macro_rules! fsai2ts { ( $secs: expr, $nsecs: expr) => { @@ -205,7 +207,7 @@ impl From<&fuse_setattr_in> for SetAttr { /// A file's timestamp, according to FUSE. /// -/// Nearly the same as a `libc::timespec`, except for the width of the nsec +/// Nearly the same as a [`libc::timespec`], except for the width of the nsec /// field. // Could implement From for Duration, and/or libc::timespec, if desired #[derive(Debug, Clone, Copy, Ord, PartialOrd, Eq, PartialEq, Hash)] diff --git a/src/notify.rs b/src/notify.rs index 5d26291..aca9c9e 100644 --- a/src/notify.rs +++ b/src/notify.rs @@ -1,4 +1,4 @@ -//! notify kernel. +//! notify kernel of changes to data it may have in its cache use std::ffi::OsString; use std::os::unix::ffi::OsStrExt; @@ -21,7 +21,7 @@ use crate::raw::abi::{ use crate::raw::FuseData; #[derive(Debug, Clone)] -/// notify kernel there are something need to handle. +/// queue of change notifications to send to the kernel pub struct Notify { sender: UnboundedSender, } diff --git a/src/path/mod.rs b/src/path/mod.rs index 5b66257..21e00d6 100644 --- a/src/path/mod.rs +++ b/src/path/mod.rs @@ -1,7 +1,7 @@ //! path based //! -//! it is recommend to use path based [`PathFilesystem`] first, [`PathFilesystem`] is more simple -//! than inode based [`Filesystem`][crate::raw::Filesystem]. However if you want to control the +//! it is recommend to use the path based [`PathFilesystem`] first, which is more simple +//! than the inode based [`Filesystem`][crate::raw::Filesystem]. However if you want to control the //! inode or do the path<->inode map on yourself, use [`Filesystem`][crate::raw::Filesystem]. pub use path_filesystem::PathFilesystem; diff --git a/src/path/path_filesystem.rs b/src/path/path_filesystem.rs index 8c8d785..f997d09 100644 --- a/src/path/path_filesystem.rs +++ b/src/path/path_filesystem.rs @@ -26,20 +26,22 @@ pub trait PathFilesystem { Err(libc::ENOSYS.into()) } - /// forget an path. The nlookup parameter indicates the number of lookups previously + /// forget a path. The nlookup parameter indicates the number of lookups previously /// performed on this path. If the filesystem implements path lifetimes, it is recommended /// that paths acquire a single reference on each lookup, and lose nlookup references on each - /// forget. The filesystem may ignore forget calls, if the paths don't need to have a limited - /// lifetime. On unmount it is not guaranteed, that all referenced paths will receive a forget - /// message. When filesystem is normal(not fuseblk) and unmounting, kernel may send forget - /// request for root and this library will stop session after call forget. There is some + /// forget. The filesystem may ignore forget calls if the paths don't need to have a limited + /// lifetime. On unmount it is not guaranteed that all referenced paths will receive a forget + /// message. When filesystem is normal(not fuseblk) and unmounting, the kernel may send a forget + /// request for the root and this library will stop session after calling forget. There is some /// discussion for this , /// /// async fn forget(&self, req: Request, parent: &OsStr, nlookup: u64) {} - /// get file attributes. If `fh` is None, means `fh` is not set. If `path` is None, means the - /// path may be deleted. + /// get file attributes. + /// + /// `fh` contains the value set by the open method, or `None` if the open method didn't set any value. + /// If `path` is None, then the file/directory at that path may have been deleted. async fn getattr( &self, req: Request, @@ -50,8 +52,9 @@ pub trait PathFilesystem { Err(libc::ENOSYS.into()) } - /// set file attributes. If `fh` is None, means `fh` is not set. If `path` is None, means the - /// path may be deleted. + /// set file attributes. + /// `fh` contains the value set by the open method, or `None` if the open method didn't set any value. + /// If `path` is None, then the file/directory at that path may have been deleted. async fn setattr( &self, req: Request, @@ -137,10 +140,11 @@ pub trait PathFilesystem { Err(libc::ENOSYS.into()) } - /// open a file. Open flags (with the exception of `O_CREAT`, `O_EXCL` and `O_NOCTTY`) are - /// available in flags. Filesystem may store an arbitrary file handle (pointer, index, etc) in - /// fh, and use this in other all other file operations (read, write, flush, release, fsync). - /// Filesystem may also implement stateless file I/O and not store anything in fh. There are + /// open a file. Open flags (with the exception of [`O_CREAT`](libc::O_CREAT), + /// [`O_EXCL`](libc::O_EXCL) and [`O_NOCTTY`](libc::O_NOCTTY)) are available as flags. + /// The PathFilesystem may store an arbitrary file handle (pointer, index, etc) in + /// `fh`, and use it in other all other file operations (read, write, flush, release, fsync). + /// The PathFilesystem may also implement stateless file I/O and not store anything in `fh`. There are /// also some flags (`direct_io`, `keep_cache`) which the filesystem may set, to change the way /// the file is opened. A file system need not implement this method if it /// sets [`MountOptions::no_open_support`][crate::MountOptions::no_open_support] and if the @@ -160,7 +164,7 @@ pub trait PathFilesystem { /// when the file has been opened in `direct_io` mode, in which case the return value of the /// read system call will reflect the return value of this operation. `fh` will contain the /// value set by the open method, or will be undefined if the open method didn't set any value. - /// when `path` is None, it means the path may be deleted. + /// If `path` is None, then the file/directory at that path may have been deleted. async fn read( &self, req: Request, @@ -176,9 +180,10 @@ pub trait PathFilesystem { /// exception to this is when the file has been opened in `direct_io` mode, in which case the /// return value of the write system call will reflect the return value of this operation. `fh` /// will contain the value set by the open method, or will be undefined if the open method - /// didn't set any value. When `path` is None, it means the path may be deleted. When - /// `write_flags` contains [`FUSE_WRITE_CACHE`](crate::raw::flags::FUSE_WRITE_CACHE), means the - /// write operation is a delay write. + /// didn't set any value. + /// If `path` is None, then the file/directory at that path may have been deleted. + /// When `write_flags` contains [`FUSE_WRITE_CACHE`](crate::raw::flags::FUSE_WRITE_CACHE), means + /// the write operation is a delay write. #[allow(clippy::too_many_arguments)] async fn write( &self, @@ -201,10 +206,11 @@ pub trait PathFilesystem { /// release an open file. Release is called when there are no more references to an open file: /// all file descriptors are closed and all memory mappings are unmapped. For every open call /// there will be exactly one release call. The filesystem may reply with an error, but error - /// values are not returned to `close()` or `munmap()` which triggered the release. `fh` will + /// values are not returned to the `close()` or `munmap()` which triggered the release. `fh` will /// contain the value set by the open method, or will be undefined if the open method didn't /// set any value. `flags` will contain the same flags as for open. `flush` means flush the - /// data or not when closing file. when `path` is None, it means the path may be deleted. + /// data or not when closing file. + /// If `path` is None, then the file/directory at that path may have been deleted. async fn release( &self, req: Request, @@ -217,8 +223,9 @@ pub trait PathFilesystem { Err(libc::ENOSYS.into()) } - /// synchronize file contents. If the `datasync` is true, then only the user data should be - /// flushed, not the metadata. when `path` is None, it means the path may be deleted. + /// synchronize file contents. If `datasync` is true, then only the user data should be + /// flushed, not the metadata. + /// If `path` is None, then the file/directory at that path may have been deleted. async fn fsync( &self, req: Request, @@ -242,8 +249,8 @@ pub trait PathFilesystem { Err(libc::ENOSYS.into()) } - /// get an extended attribute. If size is too small, use [`ReplyXAttr::Size`] to return correct - /// size. If size is enough, use [`ReplyXAttr::Data`] to send it, or return error. + /// get an extended attribute. If `size` is too small, use [`ReplyXAttr::Size`] to return + /// the correct size. If size is enough, use [`ReplyXAttr::Data`] to send it, or return an error. async fn getxattr( &self, req: Request, @@ -254,8 +261,8 @@ pub trait PathFilesystem { Err(libc::ENOSYS.into()) } - /// list extended attribute names. If size is too small, use [`ReplyXAttr::Size`] to return - /// correct size. If size is enough, use [`ReplyXAttr::Data`] to send it, or return error. + /// list extended attribute names. If `size` is too small, use [`ReplyXAttr::Size`] to return + /// the correct size. If size is enough, use [`ReplyXAttr::Data`] to send it, or return an error. async fn listxattr(&self, req: Request, path: &OsStr, size: u32) -> Result { Err(libc::ENOSYS.into()) } @@ -266,11 +273,12 @@ pub trait PathFilesystem { } /// flush method. This is called on each `close()` of the opened file. Since file descriptors - /// can be duplicated (`dup`, `dup2`, `fork`), for one open call there may be many flush calls. + /// can be duplicated (`dup`, `dup2`, `fork`), there may be many flush calls for each `open()` + /// call. /// Filesystems shouldn't assume that flush will always be called after some writes, or that if /// will be called at all. `fh` will contain the value set by the open method, or will be - /// undefined if the open method didn't set any value. when `path` is None, it means the path - /// may be deleted. + /// undefined if the open method didn't set any value. + /// If `path` is None, then the file/directory at that path may have been deleted. /// /// # Notes: /// @@ -339,7 +347,7 @@ pub trait PathFilesystem { /// /// # Notes: /// - /// this is supported on enable **`file-lock`** feature. + /// this is only supported when the **`file-lock`** feature is enabled. #[allow(clippy::too_many_arguments)] async fn getlk( &self, @@ -358,7 +366,7 @@ pub trait PathFilesystem { /// /// # Notes: /// - /// this is supported on enable **`file-lock`** feature. + /// this is only supported when the **`file-lock`** feature is enabled. #[allow(clippy::too_many_arguments)] async fn setlk( &self, @@ -407,17 +415,17 @@ pub trait PathFilesystem { Err(libc::ENOSYS.into()) } - /// handle interrupt. When a operation is interrupted, an interrupt request will send to fuse - /// server with the unique id of the operation. + /// handle interrupt. When a operation is interrupted, an interrupt request will be sent to + /// the fuse server with the unique id of the operation. async fn interrupt(&self, req: Request, unique: u64) -> Result<()> { Err(libc::ENOSYS.into()) } - /// map block index within file to block index within device. + /// map block index within a file to block index within a device. /// /// # Notes: /// - /// This may not works because currently this crate doesn't support fuseblk mode yet. + /// This may not work because currently this crate doesn't support fuseblk mode yet. async fn bmap( &self, req: Request, diff --git a/src/raw/filesystem.rs b/src/raw/filesystem.rs index c4cdc52..69acf16 100644 --- a/src/raw/filesystem.rs +++ b/src/raw/filesystem.rs @@ -29,15 +29,16 @@ pub trait Filesystem { /// forget an inode. The nlookup parameter indicates the number of lookups previously /// performed on this inode. If the filesystem implements inode lifetimes, it is recommended /// that inodes acquire a single reference on each lookup, and lose nlookup references on each - /// forget. The filesystem may ignore forget calls, if the inodes don't need to have a limited - /// lifetime. On unmount it is not guaranteed, that all referenced inodes will receive a forget - /// message. When filesystem is normal(not fuseblk) and unmounting, kernel may send forget - /// request for root and this library will stop session after call forget. There is some + /// forget. The filesystem may ignore forget calls if the inodes don't need to have a limited + /// lifetime. On unmount it is not guaranteed that all referenced inodes will receive a forget + /// message. When filesystem is normal(not fuseblk) and unmounting, the kernel may send a forget + /// request for root and this library will stop session after calling forget. There is some /// discussion for this , /// async fn forget(&self, req: Request, inode: Inode, nlookup: u64) {} - /// get file attributes. If `fh` is None, means `fh` is not set. + /// get file attributes. + /// `fh` contains the value set by the open method, or `None` if the open method didn't set any value. async fn getattr( &self, req: Request, @@ -48,7 +49,8 @@ pub trait Filesystem { Err(libc::ENOSYS.into()) } - /// set file attributes. If `fh` is None, means `fh` is not set. + /// set file attributes. + /// `fh` contains the value set by the open method, or `None` if the open method didn't set any value. async fn setattr( &self, req: Request, @@ -134,8 +136,9 @@ pub trait Filesystem { Err(libc::ENOSYS.into()) } - /// open a file. Open flags (with the exception of `O_CREAT`, `O_EXCL` and `O_NOCTTY`) are - /// available in flags. Filesystem may store an arbitrary file handle (pointer, index, etc) in + /// open a file. Open flags (with the exception of [`O_CREAT`](libc::O_CREAT), + /// [`O_EXCL`](libc::O_EXCL) and [`O_NOCTTY`](libc::O_NOCTTY)) are available as flags. + /// The Filesystem may store an arbitrary file handle (pointer, index, etc) in /// fh, and use this in other all other file operations (read, write, flush, release, fsync). /// Filesystem may also implement stateless file I/O and not store anything in fh. There are /// also some flags (`direct_io`, `keep_cache`) which the filesystem may set, to change the way @@ -197,7 +200,7 @@ pub trait Filesystem { /// release an open file. Release is called when there are no more references to an open file: /// all file descriptors are closed and all memory mappings are unmapped. For every open call /// there will be exactly one release call. The filesystem may reply with an error, but error - /// values are not returned to `close()` or `munmap()` which triggered the release. `fh` will + /// values are not returned to the `close()` or `munmap()` which triggered the release. `fh` will /// contain the value set by the open method, or will be undefined if the open method didn't /// set any value. `flags` will contain the same flags as for open. `flush` means flush the /// data or not when closing file. @@ -259,7 +262,8 @@ pub trait Filesystem { } /// flush method. This is called on each `close()` of the opened file. Since file descriptors - /// can be duplicated (`dup`, `dup2`, `fork`), for one open call there may be many flush calls. + /// can be duplicated (`dup`, `dup2`, `fork`), there may be many flush calls for each `open()` + /// call. /// Filesystems shouldn't assume that flush will always be called after some writes, or that if /// will be called at all. `fh` will contain the value set by the open method, or will be /// undefined if the open method didn't set any value. @@ -324,7 +328,7 @@ pub trait Filesystem { /// /// # Notes: /// - /// this is supported on enable **`file-lock`** feature. + /// this is only supported when the **`file-lock`** feature is enabled. #[allow(clippy::too_many_arguments)] async fn getlk( &self, @@ -343,7 +347,7 @@ pub trait Filesystem { /// /// # Notes: /// - /// this is supported on enable **`file-lock`** feature. + /// this is only supported when the **`file-lock`** feature is enabled. #[allow(clippy::too_many_arguments)] async fn setlk( &self, @@ -392,8 +396,8 @@ pub trait Filesystem { Err(libc::ENOSYS.into()) } - /// handle interrupt. When a operation is interrupted, an interrupt request will send to fuse - /// server with the unique id of the operation. + /// handle interrupt. When a operation is interrupted, an interrupt request will be sent + /// to the fuse server with the unique id of the operation. async fn interrupt(&self, req: Request, unique: u64) -> Result<()> { Err(libc::ENOSYS.into()) } @@ -402,7 +406,7 @@ pub trait Filesystem { /// /// # Notes: /// - /// This may not works because currently this crate doesn't support fuseblk mode yet. + /// This may not work because currently this crate doesn't support fuseblk mode yet. async fn bmap( &self, req: Request, diff --git a/src/raw/mod.rs b/src/raw/mod.rs index 064878b..650e4cb 100644 --- a/src/raw/mod.rs +++ b/src/raw/mod.rs @@ -1,10 +1,10 @@ //! inode based //! -//! it is not recommend to use this inode based [`Filesystem`] first, you need to handle inode -//! allocate, recycle and sometimes map to the path, [`PathFilesystem`][crate::path::PathFilesystem] -//! helps you do those jobs so you can pay more attention to your filesystem design. However if you -//! want to control the inode or do the path<->inode map on yourself, [`Filesystem`] is the only one -//! choose. +//! it is not recommend to use this inode-based [`Filesystem`] as you need to handle inode +//! allocate, recycle and sometimes map to the path. [`PathFilesystem`][crate::path::PathFilesystem] +//! helps you do those jobs so you can pay more attention to your filesystem design. However, if you +//! want to control the inode or do the path<->inode map on yourself, then [`Filesystem`] is +//! the one to choose. use bytes::Bytes; pub use filesystem::Filesystem; diff --git a/src/raw/session.rs b/src/raw/session.rs index 128d817..f8d267f 100644 --- a/src/raw/session.rs +++ b/src/raw/session.rs @@ -67,8 +67,8 @@ use crate::{Errno, SetAttr}; /// A Future which returns when a file system is unmounted /// -/// when drop the [`MountHandle`], it will unmount Filesystem in background task, if user want to -/// wait unmount completely, use [`MountHandle::unmount`] +/// When dropped, the [`MountHandle`] will unmount the Filesystem in a background task. +/// If you want to wait for the unmount to complete, use [`MountHandle::unmount`]. #[derive(Debug)] pub struct MountHandle { inner: Option, From 51b780c5651962fd3e99ff3c919ec1141a959732 Mon Sep 17 00:00:00 2001 From: Valentin Lorentz Date: Sat, 16 Aug 2025 13:13:57 +0200 Subject: [PATCH 2/2] Add warning about feature unification --- src/lib.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 53b47d1..dc44f88 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,6 +19,12 @@ //! //! You must enable either the `async-io-runtime` or `tokio-runtime` features, but not both //! or the crate won't compile. +//! +//! If you are writing a library and not an executable, beware of [feature +//! unification](https://doc.rust-lang.org/cargo/reference/features.html#feature-unification) +//! which may prevents user from depending on `fuse3` via an other crate +//! if it requires a different async runtime or it requests `file-lock` and +//! your crate doesn't (or vice versa). #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]