Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# FUSE for Rust - Changelog

## 0.17 - Unreleased

* Use new type `OpenFlags` in `Filesystem::open`

## 0.16.0 - 2025-09-12
* Add support for passthrough file descriptors
* Change `KernelConfig` capabilities flags parameters to `u64`
Expand Down
8 changes: 4 additions & 4 deletions examples/notify_inval_inode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ use libc::{EACCES, EINVAL, EISDIR, ENOBUFS, ENOENT, ENOTDIR};
use clap::Parser;

use fuser::{
FUSE_ROOT_ID, FileAttr, FileType, Filesystem, MountOption, ReplyAttr, ReplyData,
ReplyDirectory, ReplyEntry, ReplyOpen, Request, consts,
FUSE_ROOT_ID, FileAttr, FileType, Filesystem, MountOption, OpenAccMode, OpenFlags, ReplyAttr,
ReplyData, ReplyDirectory, ReplyEntry, ReplyOpen, Request, consts,
};

struct ClockFS<'a> {
Expand Down Expand Up @@ -120,10 +120,10 @@ impl Filesystem for ClockFS<'_> {
}
}

fn open(&mut self, _req: &Request, ino: u64, flags: i32, reply: ReplyOpen) {
fn open(&mut self, _req: &Request, ino: u64, flags: OpenFlags, reply: ReplyOpen) {
if ino == FUSE_ROOT_ID {
reply.error(EISDIR);
} else if flags & libc::O_ACCMODE != libc::O_RDONLY {
} else if flags.acc_mode() != OpenAccMode::O_RDONLY {
reply.error(EACCES);
} else if ino != Self::FILE_INO {
eprintln!("Got open for nonexistent inode {ino}");
Expand Down
4 changes: 2 additions & 2 deletions examples/passthrough.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

use clap::{Arg, ArgAction, Command, crate_version};
use fuser::{
BackingId, FileAttr, FileType, Filesystem, KernelConfig, MountOption, ReplyAttr,
BackingId, FileAttr, FileType, Filesystem, KernelConfig, MountOption, OpenFlags, ReplyAttr,
ReplyDirectory, ReplyEmpty, ReplyEntry, ReplyOpen, Request, consts,
};
use libc::ENOENT;
Expand Down Expand Up @@ -163,7 +163,7 @@ impl Filesystem for PassthroughFs {
}
}

fn open(&mut self, _req: &Request, ino: u64, _flags: i32, reply: ReplyOpen) {
fn open(&mut self, _req: &Request, ino: u64, _flags: OpenFlags, reply: ReplyOpen) {
if ino != 2 {
reply.error(ENOENT);
return;
Expand Down
6 changes: 3 additions & 3 deletions examples/poll.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use std::{
use libc::{EACCES, EBADF, EBUSY, EINVAL, ENOENT, ENOTDIR};

use fuser::{
FUSE_ROOT_ID, FileAttr, FileType, MountOption, PollHandle, Request,
FUSE_ROOT_ID, FileAttr, FileType, MountOption, OpenAccMode, OpenFlags, PollHandle, Request,
consts::{FOPEN_DIRECT_IO, FOPEN_NONSEEKABLE, FUSE_POLL_SCHEDULE_NOTIFY},
};

Expand Down Expand Up @@ -169,14 +169,14 @@ impl fuser::Filesystem for FSelFS {
reply.ok();
}

fn open(&mut self, _req: &Request, ino: u64, flags: i32, reply: fuser::ReplyOpen) {
fn open(&mut self, _req: &Request, ino: u64, flags: OpenFlags, reply: fuser::ReplyOpen) {
let idx = FSelData::ino_to_idx(ino);
if idx >= NUMFILES {
reply.error(ENOENT);
return;
}

if (flags & libc::O_ACCMODE) != libc::O_RDONLY {
if flags.acc_mode() != OpenAccMode::O_RDONLY {
reply.error(EACCES);
return;
}
Expand Down
25 changes: 10 additions & 15 deletions examples/simple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ use fuser::consts::FUSE_HANDLE_KILLPRIV;
// use fuser::consts::FUSE_WRITE_KILL_PRIV;
use fuser::TimeOrNow::Now;
use fuser::{
FUSE_ROOT_ID, Filesystem, KernelConfig, MountOption, ReplyAttr, ReplyCreate, ReplyData,
ReplyDirectory, ReplyEmpty, ReplyEntry, ReplyOpen, ReplyStatfs, ReplyWrite, ReplyXattr,
Request, TimeOrNow,
FUSE_ROOT_ID, Filesystem, KernelConfig, MountOption, OpenAccMode, OpenFlags, ReplyAttr,
ReplyCreate, ReplyData, ReplyDirectory, ReplyEmpty, ReplyEntry, ReplyOpen, ReplyStatfs,
ReplyWrite, ReplyXattr, Request, TimeOrNow,
};
#[cfg(feature = "abi-7-26")]
use log::info;
Expand Down Expand Up @@ -1347,29 +1347,24 @@ impl Filesystem for SimpleFS {
}
}

fn open(&mut self, req: &Request, inode: u64, flags: i32, reply: ReplyOpen) {
fn open(&mut self, req: &Request, inode: u64, flags: OpenFlags, reply: ReplyOpen) {
debug!("open() called for {inode:?}");
let (access_mask, read, write) = match flags & libc::O_ACCMODE {
libc::O_RDONLY => {
let (access_mask, read, write) = match flags.acc_mode() {
OpenAccMode::O_RDONLY => {
// Behavior is undefined, but most filesystems return EACCES
if flags & libc::O_TRUNC != 0 {
if flags.0 & libc::O_TRUNC != 0 {
reply.error(libc::EACCES);
return;
}
if flags & FMODE_EXEC != 0 {
if flags.0 & FMODE_EXEC != 0 {
// Open is from internal exec syscall
(libc::X_OK, true, false)
} else {
(libc::R_OK, true, false)
}
}
libc::O_WRONLY => (libc::W_OK, false, true),
libc::O_RDWR => (libc::R_OK | libc::W_OK, true, true),
// Exactly one access mode flag must be specified
_ => {
reply.error(libc::EINVAL);
return;
}
OpenAccMode::O_WRONLY => (libc::W_OK, false, true),
OpenAccMode::O_RDWR => (libc::R_OK | libc::W_OK, true, true),
};

match self.get_inode(inode) {
Expand Down
5 changes: 4 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ use crate::ll::fuse_abi::InitFlags;
use crate::ll::fuse_abi::consts::*;
pub use crate::ll::{TimeOrNow, fuse_abi::consts};
use crate::mnt::mount_options::check_option_conflicts;
pub use crate::open_flags::OpenAccMode;
pub use crate::open_flags::OpenFlags;
use crate::session::MAX_WRITE_SIZE;
pub use ll::fuse_abi::fuse_forget_one;
pub use mnt::mount_options::MountOption;
Expand Down Expand Up @@ -58,6 +60,7 @@ pub mod experimental;
mod ll;
mod mnt;
mod notify;
mod open_flags;
#[cfg(feature = "abi-7-40")]
mod passthrough;
mod reply;
Expand Down Expand Up @@ -515,7 +518,7 @@ pub trait Filesystem {
/// 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. See `fuse_file_info`
/// structure in <`fuse_common.h`> for more details.
fn open(&mut self, _req: &Request<'_>, _ino: u64, _flags: i32, reply: ReplyOpen) {
fn open(&mut self, _req: &Request<'_>, _ino: u64, _flags: OpenFlags, reply: ReplyOpen) {
reply.opened(0, 0);
}

Expand Down
5 changes: 3 additions & 2 deletions src/ll/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,7 @@ mod op {
use super::{
FileHandle, INodeNo, Lock, LockOwner, Operation, RequestId, abi::consts::*, abi::*,
};
use crate::OpenFlags;
use std::{
convert::TryInto,
ffi::OsStr,
Expand Down Expand Up @@ -642,8 +643,8 @@ mod op {
}
impl_request!(Open<'_>);
impl Open<'_> {
pub(crate) fn flags(&self) -> i32 {
self.arg.flags
pub(crate) fn flags(&self) -> OpenFlags {
OpenFlags(self.arg.flags)
}
}

Expand Down
47 changes: 47 additions & 0 deletions src/open_flags.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
use std::fmt;
use std::fmt::{Formatter, LowerHex, UpperHex};

/// How the file should be opened: read-only, write-only, or read-write.
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
#[repr(i32)]
#[allow(non_camel_case_types)]
pub enum OpenAccMode {
/// Open file for reading only.
O_RDONLY = libc::O_RDONLY,
/// Open file for writing only.
O_WRONLY = libc::O_WRONLY,
/// Open file for reading and writing.
O_RDWR = libc::O_RDWR,
}

/// Open flags as passed to open operation.
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub struct OpenFlags(pub i32);

impl LowerHex for OpenFlags {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
LowerHex::fmt(&self.0, f)
}
}

impl UpperHex for OpenFlags {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
UpperHex::fmt(&self.0, f)
}
}

impl OpenFlags {
/// File access mode.
pub fn acc_mode(self) -> OpenAccMode {
match self.0 & libc::O_ACCMODE {
libc::O_RDONLY => OpenAccMode::O_RDONLY,
libc::O_WRONLY => OpenAccMode::O_WRONLY,
libc::O_RDWR => OpenAccMode::O_RDWR,
_ => {
// Impossible combination of flags.
// Do not panic because the field is public.
OpenAccMode::O_RDONLY
}
}
}
}