#![allow(clippy::needless_update)]
use crate::{
common::{FileAttr, FileLock, StatFs},
kernel::{
fuse_attr_out,
fuse_bmap_out,
fuse_entry_out,
fuse_getxattr_out,
fuse_lk_out,
fuse_open_out,
fuse_poll_out,
fuse_statfs_out,
fuse_write_out,
FOPEN_CACHE_DIR,
FOPEN_DIRECT_IO,
FOPEN_KEEP_CACHE,
FOPEN_NONSEEKABLE,
},
};
use std::{
ffi::{OsStr, OsString},
fmt,
os::unix::ffi::OsStrExt,
path::{Path, PathBuf},
time::Duration,
};
pub trait Reply {
fn collect_bytes<'a, T: ?Sized>(&'a self, collector: &mut T)
where
T: Collector<'a>;
}
macro_rules! impl_reply_body_for_pointers {
() => {
#[inline]
fn collect_bytes<'a, T: ?Sized>(&'a self, collector: &mut T)
where
T: Collector<'a>,
{
(**self).collect_bytes(collector)
}
}
}
impl<R: ?Sized> Reply for &R
where
R: Reply,
{
impl_reply_body_for_pointers!();
}
impl<R: ?Sized> Reply for &mut R
where
R: Reply,
{
impl_reply_body_for_pointers!();
}
impl<R: ?Sized> Reply for Box<R>
where
R: Reply,
{
impl_reply_body_for_pointers!();
}
impl<R: ?Sized> Reply for std::rc::Rc<R>
where
R: Reply,
{
impl_reply_body_for_pointers!();
}
impl<R: ?Sized> Reply for std::sync::Arc<R>
where
R: Reply,
{
impl_reply_body_for_pointers!();
}
impl Reply for () {
#[inline]
fn collect_bytes<'a, T: ?Sized>(&'a self, _: &mut T)
where
T: Collector<'a>,
{
}
}
impl Reply for [u8; 0] {
#[inline]
fn collect_bytes<'a, T: ?Sized>(&'a self, _: &mut T)
where
T: Collector<'a>,
{
}
}
macro_rules! impl_reply_for_tuple {
($($T:ident),+ $(,)?) => {
impl<$($T),+> Reply for ($($T,)+)
where
$( $T: Reply, )+
{
#[allow(nonstandard_style)]
#[inline]
fn collect_bytes<'a, T: ?Sized>(&'a self, collector: &mut T)
where
T: Collector<'a>,
{
let ($($T,)+) = self;
$(
$T.collect_bytes(collector);
)+
}
}
}
}
impl_reply_for_tuple!(T1);
impl_reply_for_tuple!(T1, T2);
impl_reply_for_tuple!(T1, T2, T3);
impl_reply_for_tuple!(T1, T2, T3, T4);
impl_reply_for_tuple!(T1, T2, T3, T4, T5);
impl<R> Reply for [R]
where
R: Reply,
{
#[inline]
fn collect_bytes<'a, T: ?Sized>(&'a self, collector: &mut T)
where
T: Collector<'a>,
{
for t in self {
t.collect_bytes(collector);
}
}
}
impl<R> Reply for Vec<R>
where
R: Reply,
{
#[inline]
fn collect_bytes<'a, T: ?Sized>(&'a self, collector: &mut T)
where
T: Collector<'a>,
{
for t in self {
t.collect_bytes(collector);
}
}
}
impl<T> Reply for Option<T>
where
T: Reply,
{
#[inline]
fn collect_bytes<'a, C: ?Sized>(&'a self, collector: &mut C)
where
C: Collector<'a>,
{
if let Some(ref reply) = self {
reply.collect_bytes(collector);
}
}
}
mod impl_scattered_bytes_for_cont {
use super::*;
#[inline(always)]
fn as_bytes(t: &(impl AsRef<[u8]> + ?Sized)) -> &[u8] {
t.as_ref()
}
macro_rules! impl_reply {
($($t:ty),*$(,)?) => {$(
impl Reply for $t {
#[inline]
fn collect_bytes<'a, T: ?Sized>(&'a self, collector: &mut T)
where
T: Collector<'a>,
{
let this = as_bytes(self);
if !this.is_empty() {
collector.append(this);
}
}
}
)*};
}
impl_reply! {
[u8],
str,
String,
Vec<u8>,
std::borrow::Cow<'_, [u8]>,
}
}
impl Reply for OsStr {
#[inline]
fn collect_bytes<'a, T: ?Sized>(&'a self, collector: &mut T)
where
T: Collector<'a>,
{
self.as_bytes().collect_bytes(collector)
}
}
impl Reply for OsString {
#[inline]
fn collect_bytes<'a, T: ?Sized>(&'a self, collector: &mut T)
where
T: Collector<'a>,
{
(**self).collect_bytes(collector)
}
}
impl Reply for Path {
#[inline]
fn collect_bytes<'a, T: ?Sized>(&'a self, collector: &mut T)
where
T: Collector<'a>,
{
self.as_os_str().collect_bytes(collector)
}
}
impl Reply for PathBuf {
#[inline]
fn collect_bytes<'a, T: ?Sized>(&'a self, collector: &mut T)
where
T: Collector<'a>,
{
(**self).collect_bytes(collector)
}
}
pub trait Collector<'a> {
fn append(&mut self, buf: &'a [u8]);
}
macro_rules! impl_reply {
($t:ty) => {
impl Reply for $t {
#[inline]
fn collect_bytes<'a, T: ?Sized>(&'a self, collector: &mut T)
where
T: Collector<'a>,
{
collector.append(unsafe { crate::util::as_bytes(self) })
}
}
};
}
#[must_use]
pub struct ReplyAttr(fuse_attr_out);
impl_reply!(ReplyAttr);
impl AsRef<Self> for ReplyAttr {
#[inline]
fn as_ref(&self) -> &Self {
self
}
}
impl fmt::Debug for ReplyAttr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ReplyAttr")
.field("attr", unsafe {
&*(&self.0.attr as *const _ as *const FileAttr)
})
.field(
"ttl",
&Duration::new(self.0.attr_valid, self.0.attr_valid_nsec),
)
.finish()
}
}
impl ReplyAttr {
pub fn new(attr: FileAttr) -> Self {
Self(fuse_attr_out {
attr: attr.into_inner(),
..Default::default()
})
}
pub fn attr(&mut self, attr: FileAttr) -> &mut Self {
self.0.attr = attr.into_inner();
self
}
pub fn ttl_attr(&mut self, duration: Duration) -> &mut Self {
self.0.attr_valid = duration.as_secs();
self.0.attr_valid_nsec = duration.subsec_nanos();
self
}
}
#[must_use]
pub struct ReplyEntry(fuse_entry_out);
impl_reply!(ReplyEntry);
impl AsRef<Self> for ReplyEntry {
#[inline]
fn as_ref(&self) -> &Self {
self
}
}
impl Default for ReplyEntry {
fn default() -> Self {
Self(fuse_entry_out::default())
}
}
impl fmt::Debug for ReplyEntry {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ReplyEntry")
.field("nodeid", &self.0.nodeid)
.field("generation", &self.0.generation)
.field("attr", unsafe {
&*(&self.0.attr as *const _ as *const FileAttr)
})
.field(
"ttl_attr",
&Duration::new(self.0.attr_valid, self.0.attr_valid_nsec),
)
.field(
"ttl_entry",
&Duration::new(self.0.entry_valid, self.0.entry_valid_nsec),
)
.finish()
}
}
impl ReplyEntry {
#[doc(hidden)]
#[deprecated(
since = "0.3.1",
note = "The assumption used here is incorrect. \
See also https://github.com/ubnt-intrepid/polyfuse/issues/65."
)]
pub fn new(attr: FileAttr) -> Self {
let attr = attr.into_inner();
let nodeid = attr.ino;
Self(fuse_entry_out {
nodeid,
attr,
..Default::default()
})
}
#[inline]
pub fn ino(&mut self, ino: u64) -> &mut Self {
self.0.nodeid = ino;
self
}
pub fn attr(&mut self, attr: FileAttr) -> &mut Self {
self.0.attr = attr.into_inner();
self
}
pub fn ttl_attr(&mut self, duration: Duration) -> &mut Self {
self.0.attr_valid = duration.as_secs();
self.0.attr_valid_nsec = duration.subsec_nanos();
self
}
pub fn ttl_entry(&mut self, duration: Duration) -> &mut Self {
self.0.entry_valid = duration.as_secs();
self.0.entry_valid_nsec = duration.subsec_nanos();
self
}
pub fn generation(&mut self, generation: u64) -> &mut Self {
self.0.generation = generation;
self
}
}
#[must_use]
pub struct ReplyOpen(fuse_open_out);
impl_reply!(ReplyOpen);
impl AsRef<Self> for ReplyOpen {
#[inline]
fn as_ref(&self) -> &Self {
self
}
}
impl fmt::Debug for ReplyOpen {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ReplyOpen")
.field("fh", &self.0.fh)
.field("direct_io", &self.get_flag(FOPEN_DIRECT_IO))
.field("keep_cache", &self.get_flag(FOPEN_KEEP_CACHE))
.field("nonseekable", &self.get_flag(FOPEN_NONSEEKABLE))
.field("cache_dir", &self.get_flag(FOPEN_CACHE_DIR))
.finish()
}
}
impl ReplyOpen {
pub fn new(fh: u64) -> Self {
Self(fuse_open_out {
fh,
..Default::default()
})
}
fn get_flag(&self, flag: u32) -> bool {
self.0.open_flags & flag != 0
}
fn set_flag(&mut self, flag: u32, enabled: bool) {
if enabled {
self.0.open_flags |= flag;
} else {
self.0.open_flags &= !flag;
}
}
pub fn fh(&mut self, fh: u64) -> &mut Self {
self.0.fh = fh;
self
}
pub fn direct_io(&mut self, enabled: bool) -> &mut Self {
self.set_flag(FOPEN_DIRECT_IO, enabled);
self
}
pub fn keep_cache(&mut self, enabled: bool) -> &mut Self {
self.set_flag(FOPEN_KEEP_CACHE, enabled);
self
}
pub fn nonseekable(&mut self, enabled: bool) -> &mut Self {
self.set_flag(FOPEN_NONSEEKABLE, enabled);
self
}
pub fn cache_dir(&mut self, enabled: bool) -> &mut Self {
self.set_flag(FOPEN_CACHE_DIR, enabled);
self
}
}
#[must_use]
pub struct ReplyWrite(fuse_write_out);
impl_reply!(ReplyWrite);
impl AsRef<Self> for ReplyWrite {
#[inline]
fn as_ref(&self) -> &Self {
self
}
}
impl fmt::Debug for ReplyWrite {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ReplyWrite")
.field("size", &self.0.size)
.finish()
}
}
impl ReplyWrite {
pub fn new(size: u32) -> Self {
Self(fuse_write_out {
size,
..Default::default()
})
}
pub fn size(&mut self, size: u32) -> &mut Self {
self.0.size = size;
self
}
}
#[must_use]
pub struct ReplyXattr(fuse_getxattr_out);
impl_reply!(ReplyXattr);
impl AsRef<Self> for ReplyXattr {
#[inline]
fn as_ref(&self) -> &Self {
self
}
}
impl fmt::Debug for ReplyXattr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ReplyXattr")
.field("size", &self.0.size)
.finish()
}
}
impl ReplyXattr {
pub fn new(size: u32) -> Self {
Self(fuse_getxattr_out {
size,
..Default::default()
})
}
pub fn size(&mut self, size: u32) -> &mut Self {
self.0.size = size;
self
}
}
#[must_use]
pub struct ReplyStatfs(fuse_statfs_out);
impl_reply!(ReplyStatfs);
impl AsRef<Self> for ReplyStatfs {
#[inline]
fn as_ref(&self) -> &Self {
self
}
}
impl fmt::Debug for ReplyStatfs {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ReplyStatfs")
.field("st", &self.get_stat())
.finish()
}
}
impl ReplyStatfs {
pub fn new(st: StatFs) -> Self {
Self(fuse_statfs_out {
st: st.into_inner(),
..Default::default()
})
}
pub fn stat(&mut self, st: StatFs) -> &mut Self {
self.0.st = st.into_inner();
self
}
fn get_stat(&self) -> &StatFs {
unsafe { &*(&self.0.st as *const _ as *const StatFs) }
}
}
#[must_use]
pub struct ReplyLk(fuse_lk_out);
impl_reply!(ReplyLk);
impl AsRef<Self> for ReplyLk {
#[inline]
fn as_ref(&self) -> &Self {
self
}
}
impl fmt::Debug for ReplyLk {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ReplyLk")
.field("lk", &self.get_lock())
.finish()
}
}
impl ReplyLk {
pub fn new(lk: FileLock) -> Self {
Self(fuse_lk_out {
lk: lk.into_inner(),
..Default::default()
})
}
pub fn lock(&mut self, lk: FileLock) -> &mut Self {
self.0.lk = lk.into_inner();
self
}
fn get_lock(&self) -> &FileLock {
unsafe { &*(&self.0.lk as *const _ as *const FileLock) }
}
}
#[must_use]
pub struct ReplyBmap(fuse_bmap_out);
impl_reply!(ReplyBmap);
impl AsRef<Self> for ReplyBmap {
#[inline]
fn as_ref(&self) -> &Self {
self
}
}
impl fmt::Debug for ReplyBmap {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ReplyBmap")
.field("block", &self.0.block)
.finish()
}
}
impl ReplyBmap {
pub fn new(block: u64) -> Self {
Self(fuse_bmap_out {
block,
..Default::default()
})
}
pub fn block(&mut self, block: u64) -> &mut Self {
self.0.block = block;
self
}
}
#[must_use]
pub struct ReplyPoll(fuse_poll_out);
impl_reply!(ReplyPoll);
impl AsRef<Self> for ReplyPoll {
#[inline]
fn as_ref(&self) -> &Self {
self
}
}
impl fmt::Debug for ReplyPoll {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ReplyPoll")
.field("revents", &self.0.revents)
.finish()
}
}
impl ReplyPoll {
pub fn new(revents: u32) -> Self {
Self(fuse_poll_out {
revents,
..Default::default()
})
}
pub fn revents(&mut self, revents: u32) -> &mut Self {
self.0.revents = revents;
self
}
}