diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/fuse/ops.rs | 19 | ||||
| -rw-r--r-- | src/fuse/session.rs | 10 | ||||
| -rw-r--r-- | src/proto.rs | 71 |
3 files changed, 85 insertions, 15 deletions
diff --git a/src/fuse/ops.rs b/src/fuse/ops.rs index 60e5815..4727d10 100644 --- a/src/fuse/ops.rs +++ b/src/fuse/ops.rs @@ -85,6 +85,25 @@ op! { } op! { + Forget { + type RequestBody = proto::OpcodeSelect< + (&'o proto::BatchForgetIn, &'o [proto::ForgetOne]), + &'o proto::ForgetOne, + { proto::Opcode::BatchForget as u32 }, + >; + + type ReplyTail = (); + } + + impl Reply { + pub fn ok(self) -> Done<'o> { + // No reply for forget requests + Done::done() + } + } +} + +op! { Getattr { type RequestBody = &'o proto::GetattrIn; type ReplyTail = (); diff --git a/src/fuse/session.rs b/src/fuse/session.rs index 6d43123..82db758 100644 --- a/src/fuse/session.rs +++ b/src/fuse/session.rs @@ -51,6 +51,7 @@ pub struct Endpoint<'a> { pub enum Dispatch<'o> { Lookup(Incoming<'o, ops::Lookup>), + Forget(Incoming<'o, ops::Forget>), Getattr(Incoming<'o, ops::Getattr>), Readlink(Incoming<'o, ops::Readlink>), Read(Incoming<'o, ops::Read>), @@ -112,7 +113,9 @@ impl Session { let (header, opcode) = InHeader::from_bytes(&buffer.0[..bytes])?; let body = match opcode { - proto::Opcode::Init => <&proto::InitIn>::toplevel_from(&buffer.0[HEADER_END..bytes])?, + proto::Opcode::Init => { + <&proto::InitIn>::toplevel_from(&buffer.0[HEADER_END..bytes], &header)? + } _ => { log::error!("First message from kernel is not Init, but {:?}", opcode); @@ -211,6 +214,7 @@ impl<'o> Dispatch<'o> { let common = match self { Lookup(incoming) => incoming.common, + Forget(incoming) => incoming.common, Getattr(incoming) => incoming.common, Readlink(incoming) => incoming.common, Read(incoming) => incoming.common, @@ -276,6 +280,7 @@ impl Endpoint<'_> { Destroy => return Ok(ControlFlow::Break(())), Lookup => dispatch!(Lookup), + Forget => dispatch!(Forget), Getattr => dispatch!(Getattr), Readlink => dispatch!(Readlink), Read => dispatch!(Read), @@ -283,6 +288,7 @@ impl Endpoint<'_> { Statfs => dispatch!(Statfs), Readdir => dispatch!(Readdir), Access => dispatch!(Access), + BatchForget => dispatch!(Forget), _ => { log::warn!("Not implemented: {}", common.header); @@ -456,7 +462,7 @@ fn try_op<'o, O: Operation<'o>>( where O::ReplyTail: Default, { - let body = match Structured::toplevel_from(&bytes[HEADER_END..header.len as usize]) { + let body = match Structured::toplevel_from(&bytes[HEADER_END..header.len as usize], &header) { Ok(body) => body, Err(error) => { log::error!("Parsing request {}: {}", header, error); diff --git a/src/proto.rs b/src/proto.rs index f15aaff..7ef3415 100644 --- a/src/proto.rs +++ b/src/proto.rs @@ -1,7 +1,7 @@ // Based on libfuse/include/fuse_kernel.h use bitflags::bitflags; -use bytemuck::{self, Pod}; +use bytemuck::{self, try_cast_slice, try_from_bytes, Pod}; use bytemuck_derive::{Pod, Zeroable}; use num_enum::TryFromPrimitive; use std::{convert::TryFrom, ffi::CStr, fmt}; @@ -15,16 +15,21 @@ pub const TARGET_MINOR_VERSION: u32 = 32; pub const REQUIRED_MINOR_VERSION: u32 = 31; pub trait Structured<'o>: Sized { - fn split_from(bytes: &'o [u8], last: bool) -> FuseResult<(Self, &'o [u8])>; + fn split_from(bytes: &'o [u8], header: &InHeader, last: bool) -> FuseResult<(Self, &'o [u8])>; - fn toplevel_from(bytes: &'o [u8]) -> FuseResult<Self> { - match Self::split_from(bytes, true)? { + fn toplevel_from(bytes: &'o [u8], header: &InHeader) -> FuseResult<Self> { + match Self::split_from(bytes, header, true)? { (ok, end) if end.is_empty() => Ok(ok), _ => Err(FuseError::BadLength), } } } +pub enum OpcodeSelect<L, R, const OP: u32> { + Match(L), + Alt(R), +} + #[derive(Pod, Zeroable, Copy, Clone)] #[repr(C)] pub struct InHeader { @@ -565,13 +570,48 @@ pub struct CopyFileRangeIn { } impl<'o> Structured<'o> for () { - fn split_from(bytes: &'o [u8], _last: bool) -> FuseResult<(Self, &'o [u8])> { + fn split_from(bytes: &'o [u8], _: &InHeader, _last: bool) -> FuseResult<(Self, &'o [u8])> { Ok(((), bytes)) } } +impl<'o, T, U> Structured<'o> for (T, U) +where + T: Structured<'o>, + U: Structured<'o>, +{ + fn split_from(bytes: &'o [u8], header: &InHeader, last: bool) -> FuseResult<(Self, &'o [u8])> { + let (first, bytes) = T::split_from(bytes, header, false)?; + let (second, end) = U::split_from(bytes, header, last)?; + Ok(((first, second), end)) + } +} + +impl<'o, T: Pod> Structured<'o> for &'o T { + fn split_from(bytes: &'o [u8], _: &InHeader, _last: bool) -> FuseResult<(Self, &'o [u8])> { + let (bytes, next_bytes) = bytes.split_at(bytes.len().min(std::mem::size_of::<T>())); + match try_from_bytes(bytes) { + Ok(t) => Ok((t, next_bytes)), + Err(_) => Err(FuseError::Truncated), + } + } +} + +impl<'o, T: Pod> Structured<'o> for &'o [T] { + fn split_from(bytes: &'o [u8], _header: &InHeader, last: bool) -> FuseResult<(Self, &'o [u8])> { + if !last { + unimplemented!(); + } + + match try_cast_slice(bytes) { + Ok(slice) => Ok((slice, &[])), + Err(_) => Err(FuseError::Truncated), + } + } +} + impl<'o> Structured<'o> for &'o CStr { - fn split_from(bytes: &'o [u8], last: bool) -> FuseResult<(Self, &'o [u8])> { + fn split_from(bytes: &'o [u8], _header: &InHeader, last: bool) -> FuseResult<(Self, &'o [u8])> { let (cstr, after_cstr): (&[u8], &[u8]) = if last { (bytes, &[]) } else { @@ -586,19 +626,24 @@ impl<'o> Structured<'o> for &'o CStr { } } -impl<'o, T: Pod> Structured<'o> for &'o T { - fn split_from(bytes: &'o [u8], _last: bool) -> FuseResult<(Self, &'o [u8])> { - let (bytes, next_bytes) = bytes.split_at(bytes.len().min(std::mem::size_of::<T>())); - match bytemuck::try_from_bytes(bytes) { - Ok(t) => Ok((t, next_bytes)), - Err(_) => Err(FuseError::Truncated), +impl<'o, L, R, const OP: u32> Structured<'o> for OpcodeSelect<L, R, OP> +where + L: Structured<'o>, + R: Structured<'o>, +{ + fn split_from(bytes: &'o [u8], header: &InHeader, last: bool) -> FuseResult<(Self, &'o [u8])> { + if header.opcode == OP { + L::split_from(bytes, header, last).map(|(l, end)| (OpcodeSelect::Match(l), end)) + } else { + R::split_from(bytes, header, last).map(|(r, end)| (OpcodeSelect::Alt(r), end)) } } } impl InHeader { pub fn from_bytes(bytes: &[u8]) -> FuseResult<(Self, Opcode)> { - let (header, _) = <&InHeader>::split_from(bytes, false)?; + let header_bytes = &bytes[..bytes.len().min(std::mem::size_of::<InHeader>())]; + let header = try_from_bytes::<InHeader>(header_bytes).map_err(|_| FuseError::Truncated)?; if header.len as usize != bytes.len() { return Err(FuseError::BadLength); |
