use crate::decoder::Decoder;
use polyfuse_kernel::*;
use std::{convert::TryFrom, ffi::OsStr, fmt, time::Duration, u32, u64};
#[derive(Debug)]
pub struct DecodeError {
inner: crate::decoder::DecodeError,
}
impl DecodeError {
#[inline]
const fn new(inner: crate::decoder::DecodeError) -> Self {
Self { inner }
}
}
impl fmt::Display for DecodeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "failed to decode request message")
}
}
impl std::error::Error for DecodeError {}
#[non_exhaustive]
pub enum Operation<'op, T> {
Lookup(Lookup<'op>),
Getattr(Getattr<'op>),
Setattr(Setattr<'op>),
Readlink(Readlink<'op>),
Symlink(Symlink<'op>),
Mknod(Mknod<'op>),
Mkdir(Mkdir<'op>),
Unlink(Unlink<'op>),
Rmdir(Rmdir<'op>),
Rename(Rename<'op>),
Link(Link<'op>),
Open(Open<'op>),
Read(Read<'op>),
Write(Write<'op>, T),
Release(Release<'op>),
Statfs(Statfs<'op>),
Fsync(Fsync<'op>),
Setxattr(Setxattr<'op>),
Getxattr(Getxattr<'op>),
Listxattr(Listxattr<'op>),
Removexattr(Removexattr<'op>),
Flush(Flush<'op>),
Opendir(Opendir<'op>),
Readdir(Readdir<'op>),
Releasedir(Releasedir<'op>),
Fsyncdir(Fsyncdir<'op>),
Getlk(Getlk<'op>),
Setlk(Setlk<'op>),
Flock(Flock<'op>),
Access(Access<'op>),
Create(Create<'op>),
Bmap(Bmap<'op>),
Fallocate(Fallocate<'op>),
CopyFileRange(CopyFileRange<'op>),
Poll(Poll<'op>),
Forget(Forgets<'op>),
Interrupt(Interrupt<'op>),
NotifyReply(NotifyReply<'op>, T),
#[doc(hidden)]
Unknown,
}
impl<T> fmt::Debug for Operation<'_, T>
where
T: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Operation::Lookup(op) => op.fmt(f),
Operation::Getattr(op) => op.fmt(f),
Operation::Setattr(op) => op.fmt(f),
Operation::Readlink(op) => op.fmt(f),
Operation::Symlink(op) => op.fmt(f),
Operation::Mknod(op) => op.fmt(f),
Operation::Mkdir(op) => op.fmt(f),
Operation::Unlink(op) => op.fmt(f),
Operation::Rmdir(op) => op.fmt(f),
Operation::Rename(op) => op.fmt(f),
Operation::Link(op) => op.fmt(f),
Operation::Open(op) => op.fmt(f),
Operation::Read(op) => op.fmt(f),
Operation::Release(op) => op.fmt(f),
Operation::Statfs(op) => op.fmt(f),
Operation::Fsync(op) => op.fmt(f),
Operation::Setxattr(op) => op.fmt(f),
Operation::Getxattr(op) => op.fmt(f),
Operation::Listxattr(op) => op.fmt(f),
Operation::Removexattr(op) => op.fmt(f),
Operation::Flush(op) => op.fmt(f),
Operation::Opendir(op) => op.fmt(f),
Operation::Readdir(op) => op.fmt(f),
Operation::Releasedir(op) => op.fmt(f),
Operation::Fsyncdir(op) => op.fmt(f),
Operation::Getlk(op) => op.fmt(f),
Operation::Setlk(op) => op.fmt(f),
Operation::Flock(op) => op.fmt(f),
Operation::Access(op) => op.fmt(f),
Operation::Create(op) => op.fmt(f),
Operation::Bmap(op) => op.fmt(f),
Operation::Fallocate(op) => op.fmt(f),
Operation::CopyFileRange(op) => op.fmt(f),
Operation::Poll(op) => op.fmt(f),
Operation::Forget(op) => op.fmt(f),
Operation::Interrupt(op) => op.fmt(f),
Operation::Write(op, data) => f
.debug_struct("Write")
.field("op", op)
.field("data", data)
.finish(),
Operation::NotifyReply(op, data) => f
.debug_struct("NotifyReply")
.field("op", op)
.field("data", data)
.finish(),
_ => f.debug_struct("Unknown").finish(),
}
}
}
impl<'op, T> Operation<'op, T> {
#[inline]
pub(crate) fn unknown() -> Self {
Self::Unknown
}
pub(crate) fn decode(
header: &'op fuse_in_header,
arg: &'op [u8],
data: T,
) -> Result<Self, DecodeError> {
let mut decoder = Decoder::new(arg);
match fuse_opcode::try_from(header.opcode).ok() {
Some(fuse_opcode::FUSE_FORGET) => {
let arg: &fuse_forget_in = decoder.fetch().map_err(DecodeError::new)?;
let forget = fuse_forget_one {
nodeid: header.nodeid,
nlookup: arg.nlookup,
};
Ok(Operation::Forget(Forgets {
inner: ForgetsInner::Single(forget),
}))
}
Some(fuse_opcode::FUSE_BATCH_FORGET) => {
let arg: &fuse_batch_forget_in = decoder.fetch().map_err(DecodeError::new)?;
let forgets = decoder
.fetch_array::<fuse_forget_one>(arg.count as usize)
.map_err(DecodeError::new)?;
Ok(Operation::Forget(Forgets {
inner: ForgetsInner::Batch(forgets),
}))
}
Some(fuse_opcode::FUSE_INTERRUPT) => {
let arg = decoder.fetch().map_err(DecodeError::new)?;
Ok(Operation::Interrupt(Interrupt { header, arg }))
}
Some(fuse_opcode::FUSE_NOTIFY_REPLY) => {
let arg = decoder.fetch().map_err(DecodeError::new)?;
Ok(Operation::NotifyReply(NotifyReply { header, arg }, data))
}
Some(fuse_opcode::FUSE_LOOKUP) => {
let name = decoder.fetch_str().map_err(DecodeError::new)?;
Ok(Operation::Lookup(Lookup { header, name }))
}
Some(fuse_opcode::FUSE_GETATTR) => {
let arg = decoder.fetch().map_err(DecodeError::new)?;
Ok(Operation::Getattr(Getattr { header, arg }))
}
Some(fuse_opcode::FUSE_SETATTR) => {
let arg = decoder.fetch().map_err(DecodeError::new)?;
Ok(Operation::Setattr(Setattr { header, arg }))
}
Some(fuse_opcode::FUSE_READLINK) => Ok(Operation::Readlink(Readlink { header })),
Some(fuse_opcode::FUSE_SYMLINK) => {
let name = decoder.fetch_str().map_err(DecodeError::new)?;
let link = decoder.fetch_str().map_err(DecodeError::new)?;
Ok(Operation::Symlink(Symlink { header, name, link }))
}
Some(fuse_opcode::FUSE_MKNOD) => {
let arg = decoder.fetch().map_err(DecodeError::new)?;
let name = decoder.fetch_str().map_err(DecodeError::new)?;
Ok(Operation::Mknod(Mknod { header, arg, name }))
}
Some(fuse_opcode::FUSE_MKDIR) => {
let arg = decoder.fetch().map_err(DecodeError::new)?;
let name = decoder.fetch_str().map_err(DecodeError::new)?;
Ok(Operation::Mkdir(Mkdir { header, arg, name }))
}
Some(fuse_opcode::FUSE_UNLINK) => {
let name = decoder.fetch_str().map_err(DecodeError::new)?;
Ok(Operation::Unlink(Unlink { header, name }))
}
Some(fuse_opcode::FUSE_RMDIR) => {
let name = decoder.fetch_str().map_err(DecodeError::new)?;
Ok(Operation::Rmdir(Rmdir { header, name }))
}
Some(fuse_opcode::FUSE_RENAME) => {
let arg = decoder.fetch().map_err(DecodeError::new)?;
let name = decoder.fetch_str().map_err(DecodeError::new)?;
let newname = decoder.fetch_str().map_err(DecodeError::new)?;
Ok(Operation::Rename(Rename {
header,
arg: RenameArg::V1(arg),
name,
newname,
}))
}
Some(fuse_opcode::FUSE_RENAME2) => {
let arg = decoder.fetch().map_err(DecodeError::new)?;
let name = decoder.fetch_str().map_err(DecodeError::new)?;
let newname = decoder.fetch_str().map_err(DecodeError::new)?;
Ok(Operation::Rename(Rename {
header,
arg: RenameArg::V2(arg),
name,
newname,
}))
}
Some(fuse_opcode::FUSE_LINK) => {
let arg = decoder.fetch().map_err(DecodeError::new)?;
let newname = decoder.fetch_str().map_err(DecodeError::new)?;
Ok(Operation::Link(Link {
header,
arg,
newname,
}))
}
Some(fuse_opcode::FUSE_OPEN) => {
let arg = decoder.fetch().map_err(DecodeError::new)?;
Ok(Operation::Open(Open { header, arg }))
}
Some(fuse_opcode::FUSE_READ) => {
let arg = decoder.fetch().map_err(DecodeError::new)?;
Ok(Operation::Read(Read { header, arg }))
}
Some(fuse_opcode::FUSE_WRITE) => {
let arg: &fuse_write_in = decoder.fetch().map_err(DecodeError::new)?;
Ok(Operation::Write(Write { header, arg }, data))
}
Some(fuse_opcode::FUSE_RELEASE) => {
let arg = decoder.fetch().map_err(DecodeError::new)?;
Ok(Operation::Release(Release { header, arg }))
}
Some(fuse_opcode::FUSE_STATFS) => Ok(Operation::Statfs(Statfs { header })),
Some(fuse_opcode::FUSE_FSYNC) => {
let arg = decoder.fetch().map_err(DecodeError::new)?;
Ok(Operation::Fsync(Fsync { header, arg }))
}
Some(fuse_opcode::FUSE_SETXATTR) => {
let arg = decoder
.fetch::<fuse_setxattr_in>()
.map_err(DecodeError::new)?;
let name = decoder.fetch_str().map_err(DecodeError::new)?;
let value = decoder
.fetch_bytes(arg.size as usize)
.map_err(DecodeError::new)?;
Ok(Operation::Setxattr(Setxattr {
header,
arg,
name,
value,
}))
}
Some(fuse_opcode::FUSE_GETXATTR) => {
let arg: &fuse_getxattr_in = decoder.fetch().map_err(DecodeError::new)?;
let name = decoder.fetch_str().map_err(DecodeError::new)?;
Ok(Operation::Getxattr(Getxattr { header, arg, name }))
}
Some(fuse_opcode::FUSE_LISTXATTR) => {
let arg: &fuse_getxattr_in = decoder.fetch().map_err(DecodeError::new)?;
Ok(Operation::Listxattr(Listxattr { header, arg }))
}
Some(fuse_opcode::FUSE_REMOVEXATTR) => {
let name = decoder.fetch_str().map_err(DecodeError::new)?;
Ok(Operation::Removexattr(Removexattr { header, name }))
}
Some(fuse_opcode::FUSE_FLUSH) => {
let arg = decoder.fetch().map_err(DecodeError::new)?;
Ok(Operation::Flush(Flush { header, arg }))
}
Some(fuse_opcode::FUSE_OPENDIR) => {
let arg = decoder.fetch().map_err(DecodeError::new)?;
Ok(Operation::Opendir(Opendir { header, arg }))
}
Some(fuse_opcode::FUSE_READDIR) => {
let arg = decoder.fetch().map_err(DecodeError::new)?;
Ok(Operation::Readdir(Readdir {
header,
arg,
mode: ReaddirMode::Normal,
}))
}
Some(fuse_opcode::FUSE_READDIRPLUS) => {
let arg = decoder.fetch().map_err(DecodeError::new)?;
Ok(Operation::Readdir(Readdir {
header,
arg,
mode: ReaddirMode::Plus,
}))
}
Some(fuse_opcode::FUSE_RELEASEDIR) => {
let arg = decoder.fetch().map_err(DecodeError::new)?;
Ok(Operation::Releasedir(Releasedir { header, arg }))
}
Some(fuse_opcode::FUSE_FSYNCDIR) => {
let arg = decoder.fetch().map_err(DecodeError::new)?;
Ok(Operation::Fsyncdir(Fsyncdir { header, arg }))
}
Some(fuse_opcode::FUSE_GETLK) => {
let arg = decoder.fetch().map_err(DecodeError::new)?;
Ok(Operation::Getlk(Getlk { header, arg }))
}
Some(opcode @ fuse_opcode::FUSE_SETLK) | Some(opcode @ fuse_opcode::FUSE_SETLKW) => {
let arg: &fuse_lk_in = decoder.fetch().map_err(DecodeError::new)?;
let sleep = match opcode {
fuse_opcode::FUSE_SETLK => false,
fuse_opcode::FUSE_SETLKW => true,
_ => unreachable!(),
};
if arg.lk_flags & FUSE_LK_FLOCK == 0 {
Ok(Operation::Setlk(Setlk { header, arg, sleep }))
} else {
let op = convert_to_flock_op(arg.lk.typ, sleep).unwrap_or(0);
Ok(Operation::Flock(Flock { header, arg, op }))
}
}
Some(fuse_opcode::FUSE_ACCESS) => {
let arg = decoder.fetch().map_err(DecodeError::new)?;
Ok(Operation::Access(Access { header, arg }))
}
Some(fuse_opcode::FUSE_CREATE) => {
let arg = decoder.fetch().map_err(DecodeError::new)?;
let name = decoder.fetch_str().map_err(DecodeError::new)?;
Ok(Operation::Create(Create { header, arg, name }))
}
Some(fuse_opcode::FUSE_BMAP) => {
let arg = decoder.fetch().map_err(DecodeError::new)?;
Ok(Operation::Bmap(Bmap { header, arg }))
}
Some(fuse_opcode::FUSE_FALLOCATE) => {
let arg = decoder.fetch().map_err(DecodeError::new)?;
Ok(Operation::Fallocate(Fallocate { header, arg }))
}
Some(fuse_opcode::FUSE_COPY_FILE_RANGE) => {
let arg = decoder.fetch().map_err(DecodeError::new)?;
Ok(Operation::CopyFileRange(CopyFileRange { header, arg }))
}
Some(fuse_opcode::FUSE_POLL) => {
let arg = decoder.fetch().map_err(DecodeError::new)?;
Ok(Operation::Poll(Poll { header, arg }))
}
_ => {
tracing::warn!("unsupported opcode: {}", header.opcode);
Ok(Operation::Unknown)
}
}
}
}
#[inline]
fn convert_to_flock_op(lk_type: u32, sleep: bool) -> Option<u32> {
const F_RDLCK: u32 = libc::F_RDLCK as u32;
const F_WRLCK: u32 = libc::F_WRLCK as u32;
const F_UNLCK: u32 = libc::F_UNLCK as u32;
let mut op = match lk_type {
F_RDLCK => libc::LOCK_SH as u32,
F_WRLCK => libc::LOCK_EX as u32,
F_UNLCK => libc::LOCK_UN as u32,
_ => return None,
};
if !sleep {
op |= libc::LOCK_NB as u32;
}
Some(op)
}
#[repr(transparent)]
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct LockOwner(u64);
impl fmt::Debug for LockOwner {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "LockOwner {{ .. }}")
}
}
impl LockOwner {
#[inline]
pub const fn from_raw(id: u64) -> Self {
Self(id)
}
#[inline]
pub const fn into_raw(self) -> u64 {
self.0
}
}
pub struct Forgets<'op> {
inner: ForgetsInner<'op>,
}
impl fmt::Debug for Forgets<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_set().entries(self.as_ref()).finish()
}
}
enum ForgetsInner<'op> {
Single(fuse_forget_one),
Batch(&'op [fuse_forget_one]),
}
impl<'op> std::ops::Deref for Forgets<'op> {
type Target = [Forget];
#[inline]
fn deref(&self) -> &Self::Target {
let (ptr, len) = match &self.inner {
ForgetsInner::Single(forget) => (forget as *const fuse_forget_one, 1),
ForgetsInner::Batch(forgets) => (forgets.as_ptr(), forgets.len()),
};
unsafe {
std::slice::from_raw_parts(ptr as *const Forget, len)
}
}
}
#[repr(transparent)]
pub struct Forget {
forget: fuse_forget_one,
}
impl fmt::Debug for Forget {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Forget").finish()
}
}
impl Forget {
#[inline]
pub fn ino(&self) -> u64 {
self.forget.nodeid
}
#[inline]
pub fn nlookup(&self) -> u64 {
self.forget.nlookup
}
}
pub struct NotifyReply<'op> {
header: &'op fuse_in_header,
arg: &'op fuse_notify_retrieve_in,
}
impl fmt::Debug for NotifyReply<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("NotifyReply").finish()
}
}
impl<'op> NotifyReply<'op> {
#[inline]
pub fn unique(&self) -> u64 {
self.header.unique
}
#[inline]
pub fn ino(&self) -> u64 {
self.header.nodeid
}
#[inline]
pub fn offset(&self) -> u64 {
self.arg.offset
}
#[inline]
pub fn size(&self) -> u32 {
self.arg.size
}
}
pub struct Interrupt<'op> {
#[allow(dead_code)]
header: &'op fuse_in_header,
arg: &'op fuse_interrupt_in,
}
impl fmt::Debug for Interrupt<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Interrupt").finish()
}
}
impl<'op> Interrupt<'op> {
#[inline]
pub fn unique(&self) -> u64 {
self.arg.unique
}
}
pub struct Lookup<'op> {
header: &'op fuse_in_header,
name: &'op OsStr,
}
impl fmt::Debug for Lookup<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Lookup").finish()
}
}
impl<'op> Lookup<'op> {
pub fn parent(&self) -> u64 {
self.header.nodeid
}
pub fn name(&self) -> &OsStr {
self.name
}
}
pub struct Getattr<'op> {
header: &'op fuse_in_header,
arg: &'op fuse_getattr_in,
}
impl fmt::Debug for Getattr<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Getattr").finish()
}
}
impl<'op> Getattr<'op> {
pub fn ino(&self) -> u64 {
self.header.nodeid
}
pub fn fh(&self) -> Option<u64> {
if self.arg.getattr_flags & FUSE_GETATTR_FH != 0 {
Some(self.arg.fh)
} else {
None
}
}
}
pub struct Setattr<'op> {
header: &'op fuse_in_header,
arg: &'op fuse_setattr_in,
}
impl fmt::Debug for Setattr<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Setattr").finish()
}
}
impl<'op> Setattr<'op> {
#[inline(always)]
fn get<R>(&self, flag: u32, f: impl FnOnce(&fuse_setattr_in) -> R) -> Option<R> {
if self.arg.valid & flag != 0 {
Some(f(&self.arg))
} else {
None
}
}
pub fn ino(&self) -> u64 {
self.header.nodeid
}
#[inline]
pub fn fh(&self) -> Option<u64> {
self.get(FATTR_FH, |arg| arg.fh)
}
#[inline]
pub fn mode(&self) -> Option<u32> {
self.get(FATTR_MODE, |arg| arg.mode)
}
#[inline]
pub fn uid(&self) -> Option<u32> {
self.get(FATTR_UID, |arg| arg.uid)
}
#[inline]
pub fn gid(&self) -> Option<u32> {
self.get(FATTR_GID, |arg| arg.gid)
}
#[inline]
pub fn size(&self) -> Option<u64> {
self.get(FATTR_SIZE, |arg| arg.size)
}
#[inline]
pub fn atime(&self) -> Option<SetAttrTime> {
self.get(FATTR_ATIME, |arg| {
if arg.valid & FATTR_ATIME_NOW != 0 {
SetAttrTime::Now
} else {
SetAttrTime::Timespec(Duration::new(arg.atime, arg.atimensec))
}
})
}
#[inline]
pub fn mtime(&self) -> Option<SetAttrTime> {
self.get(FATTR_MTIME, |arg| {
if arg.valid & FATTR_MTIME_NOW != 0 {
SetAttrTime::Now
} else {
SetAttrTime::Timespec(Duration::new(arg.mtime, arg.mtimensec))
}
})
}
#[inline]
pub fn ctime(&self) -> Option<Duration> {
self.get(FATTR_CTIME, |arg| Duration::new(arg.ctime, arg.ctimensec))
}
#[inline]
pub fn lock_owner(&self) -> Option<LockOwner> {
self.get(FATTR_LOCKOWNER, |arg| LockOwner::from_raw(arg.lock_owner))
}
}
#[derive(Copy, Clone, Debug)]
#[non_exhaustive]
pub enum SetAttrTime {
Timespec(Duration),
Now,
}
pub struct Readlink<'op> {
header: &'op fuse_in_header,
}
impl fmt::Debug for Readlink<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Readlink").finish()
}
}
impl<'op> Readlink<'op> {
#[inline]
pub fn ino(&self) -> u64 {
self.header.nodeid
}
}
pub struct Symlink<'op> {
header: &'op fuse_in_header,
name: &'op OsStr,
link: &'op OsStr,
}
impl fmt::Debug for Symlink<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Symlink").finish()
}
}
impl<'op> Symlink<'op> {
#[inline]
pub fn parent(&self) -> u64 {
self.header.nodeid
}
#[inline]
pub fn name(&self) -> &OsStr {
self.name
}
#[inline]
pub fn link(&self) -> &OsStr {
self.link
}
}
pub struct Mknod<'op> {
header: &'op fuse_in_header,
arg: &'op fuse_mknod_in,
name: &'op OsStr,
}
impl fmt::Debug for Mknod<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Mknod").finish()
}
}
impl<'op> Mknod<'op> {
#[inline]
pub fn parent(&self) -> u64 {
self.header.nodeid
}
#[inline]
pub fn name(&self) -> &OsStr {
self.name
}
#[inline]
pub fn mode(&self) -> u32 {
self.arg.mode
}
#[inline]
pub fn rdev(&self) -> u32 {
self.arg.rdev
}
#[doc(hidden)]
pub fn umask(&self) -> u32 {
self.arg.umask
}
}
pub struct Mkdir<'op> {
header: &'op fuse_in_header,
arg: &'op fuse_mkdir_in,
name: &'op OsStr,
}
impl fmt::Debug for Mkdir<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Mkdir").finish()
}
}
impl<'op> Mkdir<'op> {
#[inline]
pub fn parent(&self) -> u64 {
self.header.nodeid
}
#[inline]
pub fn name(&self) -> &OsStr {
self.name
}
#[inline]
pub fn mode(&self) -> u32 {
self.arg.mode
}
#[doc(hidden)]
pub fn umask(&self) -> u32 {
self.arg.umask
}
}
pub struct Unlink<'op> {
header: &'op fuse_in_header,
name: &'op OsStr,
}
impl fmt::Debug for Unlink<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Unlink").finish()
}
}
impl<'op> Unlink<'op> {
#[inline]
pub fn parent(&self) -> u64 {
self.header.nodeid
}
#[inline]
pub fn name(&self) -> &OsStr {
self.name
}
}
pub struct Rmdir<'op> {
header: &'op fuse_in_header,
name: &'op OsStr,
}
impl fmt::Debug for Rmdir<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Rmdir").finish()
}
}
impl<'op> Rmdir<'op> {
#[inline]
pub fn parent(&self) -> u64 {
self.header.nodeid
}
#[inline]
pub fn name(&self) -> &OsStr {
self.name
}
}
pub struct Rename<'op> {
header: &'op fuse_in_header,
arg: RenameArg<'op>,
name: &'op OsStr,
newname: &'op OsStr,
}
enum RenameArg<'op> {
V1(&'op fuse_rename_in),
V2(&'op fuse_rename2_in),
}
impl fmt::Debug for Rename<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Rename").finish()
}
}
impl<'op> Rename<'op> {
#[inline]
pub fn parent(&self) -> u64 {
self.header.nodeid
}
#[inline]
pub fn name(&self) -> &OsStr {
self.name
}
#[inline]
pub fn newparent(&self) -> u64 {
match self.arg {
RenameArg::V1(arg) => arg.newdir,
RenameArg::V2(arg) => arg.newdir,
}
}
#[inline]
pub fn newname(&self) -> &OsStr {
self.newname
}
#[inline]
pub fn flags(&self) -> u32 {
match self.arg {
RenameArg::V1(..) => 0,
RenameArg::V2(arg) => arg.flags,
}
}
}
pub struct Link<'op> {
header: &'op fuse_in_header,
arg: &'op fuse_link_in,
newname: &'op OsStr,
}
impl fmt::Debug for Link<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Link").finish()
}
}
impl<'op> Link<'op> {
#[inline]
pub fn ino(&self) -> u64 {
self.arg.oldnodeid
}
#[inline]
pub fn newparent(&self) -> u64 {
self.header.nodeid
}
#[inline]
pub fn newname(&self) -> &OsStr {
self.newname
}
}
pub struct Open<'op> {
header: &'op fuse_in_header,
arg: &'op fuse_open_in,
}
impl fmt::Debug for Open<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Open").finish()
}
}
impl<'op> Open<'op> {
#[inline]
pub fn ino(&self) -> u64 {
self.header.nodeid
}
#[inline]
pub fn flags(&self) -> u32 {
self.arg.flags
}
}
pub struct Read<'op> {
header: &'op fuse_in_header,
arg: &'op fuse_read_in,
}
impl fmt::Debug for Read<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Read").finish()
}
}
impl<'op> Read<'op> {
#[inline]
pub fn ino(&self) -> u64 {
self.header.nodeid
}
#[inline]
pub fn fh(&self) -> u64 {
self.arg.fh
}
#[inline]
pub fn offset(&self) -> u64 {
self.arg.offset
}
#[inline]
pub fn size(&self) -> u32 {
self.arg.size
}
#[inline]
pub fn flags(&self) -> u32 {
self.arg.flags
}
#[inline]
pub fn lock_owner(&self) -> Option<LockOwner> {
if self.arg.read_flags & FUSE_READ_LOCKOWNER != 0 {
Some(LockOwner::from_raw(self.arg.lock_owner))
} else {
None
}
}
}
pub struct Write<'op> {
header: &'op fuse_in_header,
arg: &'op fuse_write_in,
}
impl fmt::Debug for Write<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Write").finish()
}
}
impl<'op> Write<'op> {
#[inline]
pub fn ino(&self) -> u64 {
self.header.nodeid
}
#[inline]
pub fn fh(&self) -> u64 {
self.arg.fh
}
#[inline]
pub fn offset(&self) -> u64 {
self.arg.offset
}
#[inline]
pub fn size(&self) -> u32 {
self.arg.size
}
#[inline]
pub fn flags(&self) -> u32 {
self.arg.flags
}
#[inline]
pub fn lock_owner(&self) -> Option<LockOwner> {
if self.arg.write_flags & FUSE_WRITE_LOCKOWNER != 0 {
Some(LockOwner::from_raw(self.arg.lock_owner))
} else {
None
}
}
}
pub struct Release<'op> {
header: &'op fuse_in_header,
arg: &'op fuse_release_in,
}
impl fmt::Debug for Release<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Release").finish()
}
}
impl<'op> Release<'op> {
#[inline]
pub fn ino(&self) -> u64 {
self.header.nodeid
}
#[inline]
pub fn fh(&self) -> u64 {
self.arg.fh
}
#[inline]
pub fn flags(&self) -> u32 {
self.arg.flags
}
#[inline]
pub fn lock_owner(&self) -> LockOwner {
LockOwner::from_raw(self.arg.lock_owner)
}
#[inline]
pub fn flush(&self) -> bool {
self.arg.release_flags & FUSE_RELEASE_FLUSH != 0
}
#[inline]
pub fn flock_release(&self) -> bool {
self.arg.release_flags & FUSE_RELEASE_FLOCK_UNLOCK != 0
}
}
pub struct Statfs<'op> {
header: &'op fuse_in_header,
}
impl fmt::Debug for Statfs<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Statfs").finish()
}
}
impl<'op> Statfs<'op> {
#[inline]
pub fn ino(&self) -> u64 {
self.header.nodeid
}
}
pub struct Fsync<'op> {
header: &'op fuse_in_header,
arg: &'op fuse_fsync_in,
}
impl fmt::Debug for Fsync<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Fsync").finish()
}
}
impl<'op> Fsync<'op> {
#[inline]
pub fn ino(&self) -> u64 {
self.header.nodeid
}
#[inline]
pub fn fh(&self) -> u64 {
self.arg.fh
}
#[inline]
pub fn datasync(&self) -> bool {
self.arg.fsync_flags & FUSE_FSYNC_FDATASYNC != 0
}
}
pub struct Setxattr<'op> {
header: &'op fuse_in_header,
arg: &'op fuse_setxattr_in,
name: &'op OsStr,
value: &'op [u8],
}
impl fmt::Debug for Setxattr<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Setxattr").finish()
}
}
impl<'op> Setxattr<'op> {
#[inline]
pub fn ino(&self) -> u64 {
self.header.nodeid
}
#[inline]
pub fn name(&self) -> &OsStr {
self.name
}
#[inline]
pub fn value(&self) -> &[u8] {
self.value
}
#[inline]
pub fn flags(&self) -> u32 {
self.arg.flags
}
}
pub struct Getxattr<'op> {
header: &'op fuse_in_header,
arg: &'op fuse_getxattr_in,
name: &'op OsStr,
}
impl fmt::Debug for Getxattr<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Getxattr").finish()
}
}
impl<'op> Getxattr<'op> {
#[inline]
pub fn ino(&self) -> u64 {
self.header.nodeid
}
#[inline]
pub fn name(&self) -> &OsStr {
self.name
}
#[inline]
pub fn size(&self) -> u32 {
self.arg.size
}
}
pub struct Listxattr<'op> {
header: &'op fuse_in_header,
arg: &'op fuse_getxattr_in,
}
impl fmt::Debug for Listxattr<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Listxattr").finish()
}
}
impl<'op> Listxattr<'op> {
#[inline]
pub fn ino(&self) -> u64 {
self.header.nodeid
}
#[inline]
pub fn size(&self) -> u32 {
self.arg.size
}
}
pub struct Removexattr<'op> {
header: &'op fuse_in_header,
name: &'op OsStr,
}
impl fmt::Debug for Removexattr<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Removexattr").finish()
}
}
impl<'op> Removexattr<'op> {
#[inline]
pub fn ino(&self) -> u64 {
self.header.nodeid
}
#[inline]
pub fn name(&self) -> &OsStr {
self.name
}
}
pub struct Flush<'op> {
header: &'op fuse_in_header,
arg: &'op fuse_flush_in,
}
impl fmt::Debug for Flush<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Flush").finish()
}
}
impl<'op> Flush<'op> {
#[inline]
pub fn ino(&self) -> u64 {
self.header.nodeid
}
#[inline]
pub fn fh(&self) -> u64 {
self.arg.fh
}
#[inline]
pub fn lock_owner(&self) -> LockOwner {
LockOwner::from_raw(self.arg.lock_owner)
}
}
pub struct Opendir<'op> {
header: &'op fuse_in_header,
arg: &'op fuse_open_in,
}
impl fmt::Debug for Opendir<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Opendir").finish()
}
}
impl<'op> Opendir<'op> {
#[inline]
pub fn ino(&self) -> u64 {
self.header.nodeid
}
#[inline]
pub fn flags(&self) -> u32 {
self.arg.flags
}
}
pub struct Readdir<'op> {
header: &'op fuse_in_header,
arg: &'op fuse_read_in,
mode: ReaddirMode,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum ReaddirMode {
Normal,
Plus,
}
impl fmt::Debug for Readdir<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Readdir").finish()
}
}
impl<'op> Readdir<'op> {
#[inline]
pub fn ino(&self) -> u64 {
self.header.nodeid
}
#[inline]
pub fn fh(&self) -> u64 {
self.arg.fh
}
#[inline]
pub fn offset(&self) -> u64 {
self.arg.offset
}
#[inline]
pub fn size(&self) -> u32 {
self.arg.size
}
pub fn mode(&self) -> ReaddirMode {
self.mode
}
}
pub struct Releasedir<'op> {
header: &'op fuse_in_header,
arg: &'op fuse_release_in,
}
impl fmt::Debug for Releasedir<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Releasedir").finish()
}
}
impl<'op> Releasedir<'op> {
#[inline]
pub fn ino(&self) -> u64 {
self.header.nodeid
}
#[inline]
pub fn fh(&self) -> u64 {
self.arg.fh
}
#[inline]
pub fn flags(&self) -> u32 {
self.arg.flags
}
}
pub struct Fsyncdir<'op> {
header: &'op fuse_in_header,
arg: &'op fuse_fsync_in,
}
impl fmt::Debug for Fsyncdir<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Fsyncdir").finish()
}
}
impl<'op> Fsyncdir<'op> {
#[inline]
pub fn ino(&self) -> u64 {
self.header.nodeid
}
#[inline]
pub fn fh(&self) -> u64 {
self.arg.fh
}
#[inline]
pub fn datasync(&self) -> bool {
self.arg.fsync_flags & FUSE_FSYNC_FDATASYNC != 0
}
}
pub struct Getlk<'op> {
header: &'op fuse_in_header,
arg: &'op fuse_lk_in,
}
impl fmt::Debug for Getlk<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Getlk").finish()
}
}
impl<'op> Getlk<'op> {
#[inline]
pub fn ino(&self) -> u64 {
self.header.nodeid
}
#[inline]
pub fn fh(&self) -> u64 {
self.arg.fh
}
#[inline]
pub fn owner(&self) -> LockOwner {
LockOwner::from_raw(self.arg.owner)
}
#[inline]
pub fn typ(&self) -> u32 {
self.arg.lk.typ
}
#[inline]
pub fn start(&self) -> u64 {
self.arg.lk.start
}
#[inline]
pub fn end(&self) -> u64 {
self.arg.lk.end
}
#[inline]
pub fn pid(&self) -> u32 {
self.arg.lk.pid
}
}
pub struct Setlk<'op> {
header: &'op fuse_in_header,
arg: &'op fuse_lk_in,
sleep: bool,
}
impl fmt::Debug for Setlk<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Setlk").finish()
}
}
impl<'op> Setlk<'op> {
#[inline]
pub fn ino(&self) -> u64 {
self.header.nodeid
}
#[inline]
pub fn fh(&self) -> u64 {
self.arg.fh
}
#[inline]
pub fn owner(&self) -> LockOwner {
LockOwner::from_raw(self.arg.owner)
}
#[inline]
pub fn typ(&self) -> u32 {
self.arg.lk.typ
}
#[inline]
pub fn start(&self) -> u64 {
self.arg.lk.start
}
#[inline]
pub fn end(&self) -> u64 {
self.arg.lk.end
}
#[inline]
pub fn pid(&self) -> u32 {
self.arg.lk.pid
}
#[inline]
pub fn sleep(&self) -> bool {
self.sleep
}
}
pub struct Flock<'op> {
header: &'op fuse_in_header,
arg: &'op fuse_lk_in,
op: u32,
}
impl fmt::Debug for Flock<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Flock").finish()
}
}
impl<'op> Flock<'op> {
#[inline]
pub fn ino(&self) -> u64 {
self.header.nodeid
}
#[inline]
pub fn fh(&self) -> u64 {
self.arg.fh
}
#[inline]
pub fn owner(&self) -> LockOwner {
LockOwner::from_raw(self.arg.owner)
}
#[inline]
pub fn op(&self) -> Option<u32> {
Some(self.op)
}
}
pub struct Access<'op> {
header: &'op fuse_in_header,
arg: &'op fuse_access_in,
}
impl fmt::Debug for Access<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Access").finish()
}
}
impl<'op> Access<'op> {
#[inline]
pub fn ino(&self) -> u64 {
self.header.nodeid
}
#[inline]
pub fn mask(&self) -> u32 {
self.arg.mask
}
}
pub struct Create<'op> {
header: &'op fuse_in_header,
arg: &'op fuse_create_in,
name: &'op OsStr,
}
impl fmt::Debug for Create<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Create").finish()
}
}
impl<'op> Create<'op> {
#[inline]
pub fn parent(&self) -> u64 {
self.header.nodeid
}
#[inline]
pub fn name(&self) -> &OsStr {
self.name
}
#[inline]
pub fn mode(&self) -> u32 {
self.arg.mode
}
#[inline]
pub fn open_flags(&self) -> u32 {
self.arg.flags
}
#[doc(hidden)]
#[inline]
pub fn umask(&self) -> u32 {
self.arg.umask
}
}
pub struct Bmap<'op> {
header: &'op fuse_in_header,
arg: &'op fuse_bmap_in,
}
impl fmt::Debug for Bmap<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Bmap").finish()
}
}
impl<'op> Bmap<'op> {
#[inline]
pub fn ino(&self) -> u64 {
self.header.nodeid
}
#[inline]
pub fn block(&self) -> u64 {
self.arg.block
}
#[inline]
pub fn blocksize(&self) -> u32 {
self.arg.blocksize
}
}
pub struct Fallocate<'op> {
header: &'op fuse_in_header,
arg: &'op fuse_fallocate_in,
}
impl fmt::Debug for Fallocate<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Fallocate").finish()
}
}
impl<'op> Fallocate<'op> {
#[inline]
pub fn ino(&self) -> u64 {
self.header.nodeid
}
#[inline]
pub fn fh(&self) -> u64 {
self.arg.fh
}
#[inline]
pub fn offset(&self) -> u64 {
self.arg.offset
}
#[inline]
pub fn length(&self) -> u64 {
self.arg.length
}
#[inline]
pub fn mode(&self) -> u32 {
self.arg.mode
}
}
pub struct CopyFileRange<'op> {
header: &'op fuse_in_header,
arg: &'op fuse_copy_file_range_in,
}
impl fmt::Debug for CopyFileRange<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("CopyFileRange").finish()
}
}
impl<'op> CopyFileRange<'op> {
#[inline]
pub fn ino_in(&self) -> u64 {
self.header.nodeid
}
#[inline]
pub fn fh_in(&self) -> u64 {
self.arg.fh_in
}
#[inline]
pub fn offset_in(&self) -> u64 {
self.arg.off_in
}
#[inline]
pub fn ino_out(&self) -> u64 {
self.arg.nodeid_out
}
#[inline]
pub fn fh_out(&self) -> u64 {
self.arg.fh_out
}
#[inline]
pub fn offset_out(&self) -> u64 {
self.arg.off_out
}
#[inline]
pub fn length(&self) -> u64 {
self.arg.len
}
#[inline]
pub fn flags(&self) -> u64 {
self.arg.flags
}
}
pub struct Poll<'op> {
header: &'op fuse_in_header,
arg: &'op fuse_poll_in,
}
impl fmt::Debug for Poll<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Poll")
.field("ino", &self.ino())
.field("fh", &self.fh())
.field("events", &self.events())
.field("kh", &self.kh())
.finish()
}
}
impl<'op> Poll<'op> {
#[inline]
pub fn ino(&self) -> u64 {
self.header.nodeid
}
#[inline]
pub fn fh(&self) -> u64 {
self.arg.fh
}
#[inline]
pub fn events(&self) -> u32 {
self.arg.events
}
#[inline]
pub fn kh(&self) -> Option<u64> {
if self.arg.flags & FUSE_POLL_SCHEDULE_NOTIFY != 0 {
Some(self.arg.kh)
} else {
None
}
}
}