summaryrefslogtreecommitdiff
path: root/src/ops/dir.rs
diff options
context:
space:
mode:
authorAlejandro Soto <alejandro@34project.org>2022-01-05 02:52:04 -0600
committerAlejandro Soto <alejandro@34project.org>2022-01-05 02:52:04 -0600
commit75cced9d4c101ec2f9f04ed95621ff3a3f750eae (patch)
treea8ff3fa46a75b18ee3c1133aa6fc0857132d6115 /src/ops/dir.rs
parentff17b04143dde5157808be5bcf1cbf8a942db4c4 (diff)
Refactor impls of Reply as individual traits
Diffstat (limited to 'src/ops/dir.rs')
-rw-r--r--src/ops/dir.rs106
1 files changed, 47 insertions, 59 deletions
diff --git a/src/ops/dir.rs b/src/ops/dir.rs
index cb3a4f7..e1998cd 100644
--- a/src/ops/dir.rs
+++ b/src/ops/dir.rs
@@ -11,7 +11,12 @@ use crate::{
Done, Operation, Reply, Request,
};
-use super::{c_to_os, FromRequest};
+use super::{
+ c_to_os, make_entry,
+ traits::{ReplyBuffered, ReplyKnown, ReplyNotFound},
+ FromRequest,
+};
+
use crate::{proto, Errno, Ino, Ttl};
use bytemuck::{bytes_of, Zeroable};
use bytes::BufMut;
@@ -21,6 +26,15 @@ pub enum Lookup {}
pub enum Readdir {}
pub struct BufferedReaddir<B>(Infallible, PhantomData<B>);
+pub trait ReplyFound<'o>: ReplyKnown<'o> {
+ fn not_found_for(reply: Reply<'o, Self>, ttl: Ttl) -> Done<'o>;
+}
+
+pub trait ReplyEntries<'o>: Operation<'o> {
+ fn entry(reply: Reply<'o, Self>, entry: Entry<impl Known>) -> Interruptible<'o, Self, ()>;
+ fn end(reply: Reply<'o, Self>) -> Done<'o>;
+}
+
pub struct ReaddirState<B> {
max_read: usize,
is_plus: bool,
@@ -58,34 +72,21 @@ impl<'o> Request<'o, Lookup> {
}
}
-impl<'o> Reply<'o, Lookup> {
- /// The requested entry was found. The FUSE client will become aware of the found inode if
- /// it wasn't before. This result may be cached by the client for up to the given TTL.
- pub fn found(self, entry: impl Known, ttl: Ttl) -> Done<'o> {
- let (attrs, attrs_ttl) = entry.inode().attrs();
- let attrs = attrs.finish(entry.inode());
-
- let done = self.single(&make_entry((entry.inode().ino(), ttl), (attrs, attrs_ttl)));
- entry.unveil();
-
- done
+impl<'o> ReplyNotFound<'o> for Lookup {
+ fn not_found(reply: Reply<'o, Self>) -> Done<'o> {
+ reply.fail(Errno::ENOENT)
}
+}
+
+impl<'o> ReplyKnown<'o> for Lookup {}
- /// The requested entry was not found in this directory. The FUSE clint may include this
- /// response in negative cache for up to the given TTL.
- pub fn not_found(self, ttl: Ttl) -> Done<'o> {
- self.single(&make_entry(
+impl<'o> ReplyFound<'o> for Lookup {
+ fn not_found_for(reply: Reply<'o, Self>, ttl: Ttl) -> Done<'o> {
+ reply.single(&make_entry(
(Ino::NULL, ttl),
(Zeroable::zeroed(), Ttl::NULL),
))
}
-
- /// The requested entry was not found in this directory, but unlike [`Reply::not_found()`]
- /// this does not report back a TTL to the FUSE client. The client should not cache the
- /// response.
- pub fn not_found_uncached(self) -> Done<'o> {
- self.fail(Errno::ENOENT)
- }
}
impl<'o> Request<'o, Readdir> {
@@ -112,22 +113,24 @@ impl<'o> Request<'o, Readdir> {
}
}
-impl<'o> Reply<'o, Readdir> {
- pub fn buffered<B>(self, buffer: B) -> Reply<'o, BufferedReaddir<B>>
- where
- B: BufMut + AsRef<[u8]>,
- {
+impl<'o, B> ReplyBuffered<'o, B> for Readdir
+where
+ B: BufMut + AsRef<[u8]>,
+{
+ type Buffered = BufferedReaddir<B>;
+
+ fn buffered(reply: Reply<'o, Self>, buffer: B) -> Reply<'o, Self::Buffered> {
assert!(buffer.as_ref().is_empty());
let ReaddirState {
max_read,
is_plus,
buffer: (),
- } = self.tail;
+ } = reply.tail;
Reply {
- session: self.session,
- unique: self.unique,
+ session: reply.session,
+ unique: reply.unique,
tail: ReaddirState {
max_read,
is_plus,
@@ -137,9 +140,9 @@ impl<'o> Reply<'o, Readdir> {
}
}
-impl<'o, B: BufMut + AsRef<[u8]>> Reply<'o, BufferedReaddir<B>> {
- pub fn entry(mut self, entry: Entry<impl Known>) -> Interruptible<'o, BufferedReaddir<B>, ()> {
- let entry_header_len = if self.tail.is_plus {
+impl<'o, B: BufMut + AsRef<[u8]>> ReplyEntries<'o> for BufferedReaddir<B> {
+ fn entry(mut reply: Reply<'o, Self>, entry: Entry<impl Known>) -> Interruptible<'o, Self, ()> {
+ let entry_header_len = if reply.tail.is_plus {
std::mem::size_of::<proto::DirentPlus>()
} else {
std::mem::size_of::<proto::Dirent>()
@@ -148,19 +151,19 @@ impl<'o, B: BufMut + AsRef<[u8]>> Reply<'o, BufferedReaddir<B>> {
let name = entry.name.as_bytes();
let padding_len = dirent_pad_bytes(entry_header_len + name.len());
- let buffer = &mut self.tail.buffer;
+ let buffer = &mut reply.tail.buffer;
let remaining = buffer
.remaining_mut()
- .min(self.tail.max_read - buffer.as_ref().len());
+ .min(reply.tail.max_read - buffer.as_ref().len());
let record_len = entry_header_len + name.len() + padding_len;
if remaining < record_len {
if buffer.as_ref().is_empty() {
- log::error!("Buffer for readdir req #{} is too small", self.unique);
- return Interruptible::Interrupted(self.fail(Errno::ENOBUFS));
+ log::error!("Buffer for readdir req #{} is too small", reply.unique);
+ return Interruptible::Interrupted(reply.fail(Errno::ENOBUFS));
}
- return Interruptible::Interrupted(self.end());
+ return Interruptible::Interrupted(reply.end());
}
let inode = entry.inode.inode();
@@ -187,7 +190,7 @@ impl<'o, B: BufMut + AsRef<[u8]>> Reply<'o, BufferedReaddir<B>> {
DirentPlus(proto::DirentPlus),
}
- let ent = if self.tail.is_plus {
+ let ent = if reply.tail.is_plus {
let (attrs, attrs_ttl) = inode.attrs();
let attrs = attrs.finish(inode);
let entry_out = make_entry((ino, entry.ttl), (attrs, attrs_ttl));
@@ -211,14 +214,14 @@ impl<'o, B: BufMut + AsRef<[u8]>> Reply<'o, BufferedReaddir<B>> {
buffer.put_slice(&[0; 7][..padding_len]);
if remaining - record_len >= entry_header.len() + (1 << proto::DIRENT_ALIGNMENT_BITS) {
- Interruptible::Completed(self, ())
+ Interruptible::Completed(reply, ())
} else {
- Interruptible::Interrupted(self.end())
+ Interruptible::Interrupted(reply.end())
}
}
- pub fn end(self) -> Done<'o> {
- self.inner(|this| this.tail.buffer.as_ref())
+ fn end(reply: Reply<'o, Self>) -> Done<'o> {
+ reply.inner(|reply| reply.tail.buffer.as_ref())
}
}
@@ -232,21 +235,6 @@ impl<'o> FromRequest<'o, Readdir> for ReaddirState<()> {
}
}
-fn make_entry(
- (Ino(ino), entry_ttl): (Ino, Ttl),
- (attrs, attr_ttl): (proto::Attrs, Ttl),
-) -> proto::EntryOut {
- proto::EntryOut {
- nodeid: ino,
- generation: 0, //TODO
- entry_valid: entry_ttl.seconds,
- attr_valid: attr_ttl.seconds,
- entry_valid_nsec: entry_ttl.nanoseconds,
- attr_valid_nsec: attr_ttl.nanoseconds,
- attr: attrs,
- }
-}
-
fn dirent_pad_bytes(entry_len: usize) -> usize {
const ALIGN_MASK: usize = (1 << proto::DIRENT_ALIGNMENT_BITS) - 1;
((entry_len + ALIGN_MASK) & !ALIGN_MASK) - entry_len