use crate::bytes::{Bytes, FillBytes};
use polyfuse_kernel::*;
use std::{convert::TryInto as _, ffi::OsStr, fmt, mem, os::unix::prelude::*, time::Duration};
use zerocopy::IntoBytes as _;
#[repr(transparent)]
pub struct FileAttr {
attr: fuse_attr,
}
impl FileAttr {
#[inline]
fn from_attr_mut(attr: &mut fuse_attr) -> &mut FileAttr {
unsafe { &mut *(attr as *mut fuse_attr as *mut FileAttr) }
}
#[inline]
pub fn ino(&mut self, ino: u64) {
self.attr.ino = ino;
}
#[inline]
pub fn size(&mut self, size: u64) {
self.attr.size = size;
}
#[inline]
pub fn mode(&mut self, mode: u32) {
self.attr.mode = mode;
}
#[inline]
pub fn nlink(&mut self, nlink: u32) {
self.attr.nlink = nlink;
}
#[inline]
pub fn uid(&mut self, uid: u32) {
self.attr.uid = uid;
}
#[inline]
pub fn gid(&mut self, gid: u32) {
self.attr.gid = gid;
}
#[inline]
pub fn rdev(&mut self, rdev: u32) {
self.attr.rdev = rdev;
}
#[inline]
pub fn blksize(&mut self, blksize: u32) {
self.attr.blksize = blksize;
}
#[inline]
pub fn blocks(&mut self, blocks: u64) {
self.attr.blocks = blocks;
}
#[inline]
pub fn atime(&mut self, atime: Duration) {
self.attr.atime = atime.as_secs();
self.attr.atimensec = atime.subsec_nanos();
}
#[inline]
pub fn mtime(&mut self, mtime: Duration) {
self.attr.mtime = mtime.as_secs();
self.attr.mtimensec = mtime.subsec_nanos();
}
#[inline]
pub fn ctime(&mut self, ctime: Duration) {
self.attr.ctime = ctime.as_secs();
self.attr.ctimensec = ctime.subsec_nanos();
}
}
#[derive(Default)]
pub struct EntryOut {
out: fuse_entry_out,
}
impl fmt::Debug for EntryOut {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("EntryOut").finish()
}
}
impl Bytes for EntryOut {
#[inline]
fn size(&self) -> usize {
self.out.as_bytes().len()
}
#[inline]
fn count(&self) -> usize {
1
}
#[inline]
fn fill_bytes<'a>(&'a self, dst: &mut dyn FillBytes<'a>) {
dst.put(self.out.as_bytes());
}
}
impl EntryOut {
#[inline]
pub fn attr(&mut self) -> &mut FileAttr {
FileAttr::from_attr_mut(&mut self.out.attr)
}
#[inline]
pub fn ino(&mut self, ino: u64) {
self.out.nodeid = ino;
}
pub fn generation(&mut self, generation: u64) {
self.out.generation = generation;
}
pub fn ttl_attr(&mut self, ttl: Duration) {
self.out.attr_valid = ttl.as_secs();
self.out.attr_valid_nsec = ttl.subsec_nanos();
}
pub fn ttl_entry(&mut self, ttl: Duration) {
self.out.entry_valid = ttl.as_secs();
self.out.entry_valid_nsec = ttl.subsec_nanos();
}
}
#[derive(Default)]
pub struct AttrOut {
out: fuse_attr_out,
}
impl fmt::Debug for AttrOut {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("AttrOut").finish()
}
}
impl AttrOut {
#[inline]
pub fn attr(&mut self) -> &mut FileAttr {
FileAttr::from_attr_mut(&mut self.out.attr)
}
pub fn ttl(&mut self, ttl: Duration) {
self.out.attr_valid = ttl.as_secs();
self.out.attr_valid_nsec = ttl.subsec_nanos();
}
}
impl Bytes for AttrOut {
#[inline]
fn size(&self) -> usize {
self.out.as_bytes().len()
}
#[inline]
fn count(&self) -> usize {
1
}
#[inline]
fn fill_bytes<'a>(&'a self, dst: &mut dyn FillBytes<'a>) {
dst.put(self.out.as_bytes());
}
}
#[derive(Default)]
pub struct OpenOut {
out: fuse_open_out,
}
impl fmt::Debug for OpenOut {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("OpenOut").finish()
}
}
impl Bytes for OpenOut {
#[inline]
fn size(&self) -> usize {
self.out.as_bytes().len()
}
#[inline]
fn count(&self) -> usize {
1
}
#[inline]
fn fill_bytes<'a>(&'a self, dst: &mut dyn FillBytes<'a>) {
dst.put(self.out.as_bytes());
}
}
impl OpenOut {
pub fn fh(&mut self, fh: u64) {
self.out.fh = fh;
}
#[inline]
fn set_flag(&mut self, flag: u32, enabled: bool) {
if enabled {
self.out.open_flags |= flag;
} else {
self.out.open_flags &= !flag;
}
}
pub fn direct_io(&mut self, enabled: bool) {
self.set_flag(FOPEN_DIRECT_IO, enabled);
}
pub fn keep_cache(&mut self, enabled: bool) {
self.set_flag(FOPEN_KEEP_CACHE, enabled);
}
pub fn nonseekable(&mut self, enabled: bool) {
self.set_flag(FOPEN_NONSEEKABLE, enabled);
}
pub fn cache_dir(&mut self, enabled: bool) {
self.set_flag(FOPEN_CACHE_DIR, enabled);
}
}
#[derive(Default)]
pub struct WriteOut {
out: fuse_write_out,
}
impl fmt::Debug for WriteOut {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("WriteOut").finish()
}
}
impl Bytes for WriteOut {
#[inline]
fn size(&self) -> usize {
self.out.as_bytes().len()
}
#[inline]
fn count(&self) -> usize {
1
}
#[inline]
fn fill_bytes<'a>(&'a self, dst: &mut dyn FillBytes<'a>) {
dst.put(self.out.as_bytes());
}
}
impl WriteOut {
pub fn size(&mut self, size: u32) {
self.out.size = size;
}
}
#[derive(Default)]
pub struct StatfsOut {
out: fuse_statfs_out,
}
impl fmt::Debug for StatfsOut {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("StatfsOut").finish()
}
}
impl Bytes for StatfsOut {
#[inline]
fn size(&self) -> usize {
self.out.as_bytes().len()
}
#[inline]
fn count(&self) -> usize {
1
}
#[inline]
fn fill_bytes<'a>(&'a self, dst: &mut dyn FillBytes<'a>) {
dst.put(self.out.as_bytes());
}
}
impl StatfsOut {
pub fn statfs(&mut self) -> &mut Statfs {
Statfs::from_kstatfs_mut(&mut self.out.st)
}
}
#[derive(Default)]
pub struct Statfs {
st: fuse_kstatfs,
}
impl Statfs {
#[inline]
fn from_kstatfs_mut(st: &mut fuse_kstatfs) -> &mut Statfs {
unsafe { &mut *(st as *mut fuse_kstatfs as *mut Statfs) }
}
pub fn bsize(&mut self, bsize: u32) {
self.st.bsize = bsize;
}
pub fn frsize(&mut self, frsize: u32) {
self.st.frsize = frsize;
}
pub fn blocks(&mut self, blocks: u64) {
self.st.blocks = blocks;
}
pub fn bfree(&mut self, bfree: u64) {
self.st.bfree = bfree;
}
pub fn bavail(&mut self, bavail: u64) {
self.st.bavail = bavail;
}
pub fn files(&mut self, files: u64) {
self.st.files = files;
}
pub fn ffree(&mut self, ffree: u64) {
self.st.ffree = ffree;
}
pub fn namelen(&mut self, namelen: u32) {
self.st.namelen = namelen;
}
}
#[derive(Default)]
pub struct XattrOut {
out: fuse_getxattr_out,
}
impl fmt::Debug for XattrOut {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("XattrOut").finish()
}
}
impl Bytes for XattrOut {
#[inline]
fn size(&self) -> usize {
self.out.as_bytes().len()
}
#[inline]
fn count(&self) -> usize {
1
}
#[inline]
fn fill_bytes<'a>(&'a self, dst: &mut dyn FillBytes<'a>) {
dst.put(self.out.as_bytes());
}
}
impl XattrOut {
pub fn size(&mut self, size: u32) {
self.out.size = size;
}
}
#[derive(Default)]
pub struct LkOut {
out: fuse_lk_out,
}
impl fmt::Debug for LkOut {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("LkOut").finish()
}
}
impl Bytes for LkOut {
#[inline]
fn size(&self) -> usize {
self.out.as_bytes().len()
}
#[inline]
fn count(&self) -> usize {
1
}
#[inline]
fn fill_bytes<'a>(&'a self, dst: &mut dyn FillBytes<'a>) {
dst.put(self.out.as_bytes());
}
}
impl LkOut {
pub fn file_lock(&mut self) -> &mut FileLock {
FileLock::from_file_lock_mut(&mut self.out.lk)
}
}
#[repr(transparent)]
pub struct FileLock {
lk: fuse_file_lock,
}
impl FileLock {
#[inline]
fn from_file_lock_mut(lk: &mut fuse_file_lock) -> &mut Self {
unsafe { &mut *(lk as *mut fuse_file_lock as *mut Self) }
}
pub fn typ(&mut self, typ: u32) {
self.lk.typ = typ;
}
pub fn start(&mut self, start: u64) {
self.lk.start = start;
}
pub fn end(&mut self, end: u64) {
self.lk.end = end;
}
pub fn pid(&mut self, pid: u32) {
self.lk.pid = pid;
}
}
#[derive(Default)]
pub struct BmapOut {
out: fuse_bmap_out,
}
impl fmt::Debug for BmapOut {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("BmapOut").finish()
}
}
impl Bytes for BmapOut {
#[inline]
fn size(&self) -> usize {
self.out.as_bytes().len()
}
#[inline]
fn count(&self) -> usize {
1
}
#[inline]
fn fill_bytes<'a>(&'a self, dst: &mut dyn FillBytes<'a>) {
dst.put(self.out.as_bytes());
}
}
impl BmapOut {
pub fn block(&mut self, block: u64) {
self.out.block = block;
}
}
#[derive(Default)]
pub struct PollOut {
out: fuse_poll_out,
}
impl fmt::Debug for PollOut {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("PollOut").finish()
}
}
impl Bytes for PollOut {
#[inline]
fn size(&self) -> usize {
self.out.as_bytes().len()
}
#[inline]
fn count(&self) -> usize {
1
}
#[inline]
fn fill_bytes<'a>(&'a self, dst: &mut dyn FillBytes<'a>) {
dst.put(self.out.as_bytes());
}
}
impl PollOut {
pub fn revents(&mut self, revents: u32) {
self.out.revents = revents;
}
}
pub struct ReaddirOut {
buf: Vec<u8>,
}
impl fmt::Debug for ReaddirOut {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ReaddirOut").finish()
}
}
impl Bytes for ReaddirOut {
#[inline]
fn size(&self) -> usize {
self.buf.size()
}
#[inline]
fn count(&self) -> usize {
self.buf.count()
}
fn fill_bytes<'a>(&'a self, dst: &mut dyn FillBytes<'a>) {
self.buf.fill_bytes(dst)
}
}
impl ReaddirOut {
pub fn new(capacity: usize) -> Self {
Self {
buf: Vec::with_capacity(capacity),
}
}
pub fn entry(&mut self, name: &OsStr, ino: u64, typ: u32, off: u64) -> bool {
let name = name.as_bytes();
let remaining = self.buf.capacity() - self.buf.len();
let entry_size = mem::size_of::<fuse_dirent>() + name.len();
let aligned_entry_size = aligned(entry_size);
if remaining < aligned_entry_size {
return true;
}
let dirent = fuse_dirent {
ino,
off,
namelen: name.len().try_into().expect("name length is too long"),
typ,
name: [],
};
let lenbefore = self.buf.len();
self.buf.extend_from_slice(dirent.as_bytes());
self.buf.extend_from_slice(name);
self.buf.resize(lenbefore + aligned_entry_size, 0);
false
}
}
#[inline]
const fn aligned(len: usize) -> usize {
(len + mem::size_of::<u64>() - 1) & !(mem::size_of::<u64>() - 1)
}