summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlejandro Soto <alejandro@34project.org>2021-12-28 19:08:33 -0600
committerAlejandro Soto <alejandro@34project.org>2021-12-28 19:43:45 -0600
commit5308f999f95343d3d232e6e9258ea607f0a05dad (patch)
tree7158dd1dc3320d0aeb07d364a48f853e238091b4
parent47cbb3373edb5ddb882a2cbadb8fbf3d64732bf9 (diff)
Reimplement Forget/BatchForget
Diffstat (limited to '')
-rw-r--r--src/fuse/ops.rs19
-rw-r--r--src/fuse/session.rs10
-rw-r--r--src/proto.rs71
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);