summaryrefslogtreecommitdiff
path: root/src/fuse/ops.rs
diff options
context:
space:
mode:
authorAlejandro Soto <alejandro@34project.org>2022-01-04 05:23:42 -0600
committerAlejandro Soto <alejandro@34project.org>2022-01-04 05:23:42 -0600
commit47cda6cd90d40a1b550d55f7181b34c21508c2fb (patch)
tree3904e239ce4fbcb42174a17b85569a9f280786e0 /src/fuse/ops.rs
parent1c02eebc71a0ede4e75fea516920697850bbe030 (diff)
Replace the op! macro in ops.rs with manual impls
Diffstat (limited to '')
-rw-r--r--src/fuse/ops.rs927
1 files changed, 460 insertions, 467 deletions
diff --git a/src/fuse/ops.rs b/src/fuse/ops.rs
index 1e22717..6f37c3f 100644
--- a/src/fuse/ops.rs
+++ b/src/fuse/ops.rs
@@ -26,586 +26,593 @@ pub trait FromRequest<'o, O: Operation<'o>> {
fn from_request(request: &Request<'o, O>) -> Self;
}
-macro_rules! op {
- { $name:ident $operation:tt } => {
- pub struct $name(Infallible);
-
- impl Sealed for $name {}
- impl<'o> Operation<'o> for $name $operation
- };
+pub enum Any {}
+pub enum Lookup {}
+pub enum Forget {}
+pub enum Getattr {}
+pub enum Readlink {}
+pub enum Open {}
+pub enum Read {}
+pub enum Write {}
+pub enum Init {}
+pub enum Statfs {}
+pub enum Release {}
+pub enum Setxattr {}
+pub enum Getxattr {}
+pub enum Listxattr {}
+pub enum Removexattr {}
+pub enum Flush {}
+pub enum Opendir {}
+pub enum Readdir {}
+pub struct BufferedReaddir<B>(Infallible, PhantomData<B>);
+pub enum Releasedir {}
+pub enum Access {}
+
+impl Sealed for Any {}
+impl Sealed for Lookup {}
+impl Sealed for Forget {}
+impl Sealed for Getattr {}
+impl Sealed for Readlink {}
+impl Sealed for Open {}
+impl Sealed for Read {}
+impl Sealed for Write {}
+impl Sealed for Init {}
+impl Sealed for Statfs {}
+impl Sealed for Release {}
+impl Sealed for Setxattr {}
+impl Sealed for Getxattr {}
+impl Sealed for Listxattr {}
+impl Sealed for Removexattr {}
+impl Sealed for Flush {}
+impl Sealed for Opendir {}
+impl Sealed for Readdir {}
+impl<B> Sealed for BufferedReaddir<B> {}
+impl Sealed for Releasedir {}
+impl Sealed for Access {}
- { $name:ident $operation:tt impl Request $request:tt $($next:tt)* } => {
- impl<'o> Request<'o, $name> $request
+impl<'o> Operation<'o> for Any {
+ type RequestBody = ();
+ type ReplyTail = ();
+}
- op! { $name $operation $($next)* }
- };
+impl<'o> Operation<'o> for Lookup {
+ type RequestBody = &'o CStr; // name()
+ type ReplyTail = ();
+}
- { $name:ident $operation:tt impl Reply $reply:tt $($next:tt)* } => {
- impl<'o> Reply<'o, $name> $reply
+impl<'o> Operation<'o> for Forget {
+ type RequestBody = proto::OpcodeSelect<
+ (&'o proto::BatchForgetIn, &'o [proto::ForgetOne]),
+ &'o proto::ForgetIn,
+ { proto::Opcode::BatchForget as u32 },
+ >;
- op! { $name $operation $($next)* }
- };
+ type ReplyTail = ();
}
-op! {
- Any {
- type RequestBody = ();
- type ReplyTail = ();
- }
+impl<'o> Operation<'o> for Getattr {
+ type RequestBody = &'o proto::GetattrIn;
+ type ReplyTail = ();
}
-op! {
- Lookup {
- type RequestBody = &'o CStr; // name()
- type ReplyTail = ();
- }
+impl<'o> Operation<'o> for Readlink {
+ type RequestBody = ();
+ type ReplyTail = ();
+}
- impl Request {
- /// Returns the name of the entry being looked up in this directory.
- pub fn name(&self) -> &OsStr {
- c_to_os(self.body)
- }
- }
+impl<'o> Operation<'o> for Open {
+ type RequestBody = &'o proto::OpenIn;
+ type ReplyTail = proto::OpenOutFlags;
+}
- impl Reply {
- /// 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());
+impl<'o> Operation<'o> for Read {
+ type RequestBody = &'o proto::ReadIn;
+ type ReplyTail = ();
+}
- let done = self.single(&make_entry((entry.inode().ino(), ttl), (attrs, attrs_ttl)));
- entry.unveil();
+impl<'o> Operation<'o> for Write {
+ type RequestBody = (&'o proto::WriteIn, &'o [u8]);
+ type ReplyTail = state::Write;
+}
- done
- }
+impl<'o> Operation<'o> for Init {
+ type RequestBody = &'o proto::InitIn;
+ type ReplyTail = state::Init;
+}
- /// 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((Ino::NULL, ttl), (Zeroable::zeroed(), Ttl::NULL)))
- }
+impl<'o> Operation<'o> for Statfs {
+ type RequestBody = ();
+ type ReplyTail = ();
+}
- /// 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> Operation<'o> for Release {
+ type RequestBody = &'o proto::ReleaseIn;
+ type ReplyTail = ();
}
-op! {
- Forget {
- type RequestBody = proto::OpcodeSelect<
- (&'o proto::BatchForgetIn, &'o [proto::ForgetOne]),
- &'o proto::ForgetIn,
- { proto::Opcode::BatchForget as u32 },
- >;
+impl<'o> Operation<'o> for Setxattr {
+ // header, name, value
+ type RequestBody = (&'o proto::SetxattrIn, &'o CStr, &'o [u8]);
+ type ReplyTail = ();
+}
- type ReplyTail = ();
- }
+impl<'o> Operation<'o> for Getxattr {
+ type RequestBody = (&'o proto::GetxattrIn, &'o CStr);
+ type ReplyTail = state::ReadXattr;
+}
- impl Request {
- pub fn forget_list(&self) -> impl '_ + Iterator<Item = (Ino, u64)> {
- use proto::OpcodeSelect::*;
+impl<'o> Operation<'o> for Listxattr {
+ type RequestBody = &'o proto::ListxattrIn;
+ type ReplyTail = state::ReadXattr;
+}
- enum List<'a> {
- Single(Option<(Ino, u64)>),
- Batch(std::slice::Iter<'a, proto::ForgetOne>),
- }
+impl<'o> Operation<'o> for Removexattr {
+ type RequestBody = &'o CStr;
+ type ReplyTail = ();
+}
- impl Iterator for List<'_> {
- type Item = (Ino, u64);
+impl<'o> Operation<'o> for Flush {
+ type RequestBody = &'o proto::FlushIn;
+ type ReplyTail = ();
+}
- fn next(&mut self) -> Option<Self::Item> {
- match self {
- List::Single(single) => single.take(),
- List::Batch(batch) => {
- let forget = batch.next()?;
- Some((Ino(forget.ino), forget.nlookup))
- }
- }
- }
- }
+impl<'o> Operation<'o> for Opendir {
+ type RequestBody = &'o proto::OpendirIn;
+ type ReplyTail = ();
+}
- match self.body {
- Match((_, slice)) => List::Batch(slice.iter()),
- Alt(single) => List::Single(Some((self.ino(), single.nlookup))),
- }
- }
- }
+impl<'o> Operation<'o> for Readdir {
+ type RequestBody = proto::OpcodeSelect<
+ &'o proto::ReaddirPlusIn,
+ &'o proto::ReaddirIn,
+ { proto::Opcode::ReaddirPlus as u32 },
+ >;
- impl Reply {
- pub fn ok(self) -> Done<'o> {
- // No reply for forget requests
- Done::new()
- }
- }
+ type ReplyTail = state::Readdir<()>;
}
-op! {
- Getattr {
- type RequestBody = &'o proto::GetattrIn;
- type ReplyTail = ();
- }
-
- impl Request {
- pub fn handle(&self) -> u64 {
- self.body.fh
- }
- }
+impl<'o> Operation<'o> for Releasedir {
+ type RequestBody = &'o proto::ReleasedirIn;
+ type ReplyTail = ();
+}
- impl Reply {
- pub fn known(self, inode: &impl Stat) -> Done<'o> {
- let (attrs, ttl) = inode.attrs();
- let attrs = attrs.finish(inode);
+impl<'o> Operation<'o> for Access {
+ type RequestBody = &'o proto::AccessIn;
+ type ReplyTail = ();
+}
- self.single(&proto::AttrOut {
- attr_valid: ttl.seconds,
- attr_valid_nsec: ttl.nanoseconds,
- dummy: Default::default(),
- attr: attrs,
- })
- }
- }
+impl<'o, B> Operation<'o> for BufferedReaddir<B> {
+ type RequestBody = (); // Never actually created
+ type ReplyTail = state::Readdir<B>;
}
-op! {
- Readlink {
- type RequestBody = ();
- type ReplyTail = ();
+impl<'o> Request<'o, Lookup> {
+ /// Returns the name of the entry being looked up in this directory.
+ pub fn name(&self) -> &OsStr {
+ c_to_os(self.body)
}
+}
- impl Reply {
- /// This inode corresponds to a symbolic link pointing to the given target path.
- pub fn target<T: AsRef<OsStr>>(self, target: T) -> Done<'o> {
- self.chain(OutputChain::tail(&[target.as_ref().as_bytes()]))
- }
+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());
- /// Same as [`Reply::target()`], except that the target path is taken from disjoint
- /// slices. This involves no additional allocation.
- pub fn gather_target(self, target: &[&[u8]]) -> Done<'o> {
- self.chain(OutputChain::tail(target))
- }
- }
-}
+ let done = self.single(&make_entry((entry.inode().ino(), ttl), (attrs, attrs_ttl)));
+ entry.unveil();
-op! {
- Open {
- type RequestBody = &'o proto::OpenIn;
- type ReplyTail = proto::OpenOutFlags;
+ done
}
- impl Request {
- pub fn flags(&self) -> OpenFlags {
- OpenFlags::from_bits_truncate(self.body.flags.try_into().unwrap_or_default())
- }
+ /// 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(
+ (Ino::NULL, ttl),
+ (Zeroable::zeroed(), Ttl::NULL),
+ ))
}
- impl Reply {
- pub fn force_direct_io(&mut self) {
- self.tail |= proto::OpenOutFlags::DIRECT_IO;
- }
-
- pub fn ok(self) -> Done<'o> {
- self.ok_with_handle(0)
- }
-
- pub fn ok_with_handle(self, handle: u64) -> Done<'o> {
- let open_flags = self.tail.bits();
-
- self.single(&proto::OpenOut {
- fh: handle,
- open_flags,
- padding: Default::default(),
- })
- }
+ /// 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)
}
}
-op! {
- Read {
- type RequestBody = &'o proto::ReadIn;
- type ReplyTail = ();
- }
+impl<'o> Request<'o, Forget> {
+ pub fn forget_list(&self) -> impl '_ + Iterator<Item = (Ino, u64)> {
+ use proto::OpcodeSelect::*;
- impl Request {
- pub fn handle(&self) -> u64 {
- self.body.fh
+ enum List<'a> {
+ Single(Option<(Ino, u64)>),
+ Batch(std::slice::Iter<'a, proto::ForgetOne>),
}
- pub fn offset(&self) -> u64 {
- self.body.offset
+ impl Iterator for List<'_> {
+ type Item = (Ino, u64);
+
+ fn next(&mut self) -> Option<Self::Item> {
+ match self {
+ List::Single(single) => single.take(),
+ List::Batch(batch) => {
+ let forget = batch.next()?;
+ Some((Ino(forget.ino), forget.nlookup))
+ }
+ }
+ }
}
- pub fn size(&self) -> u32 {
- self.body.size
+ match self.body {
+ Match((_, slice)) => List::Batch(slice.iter()),
+ Alt(single) => List::Single(Some((self.ino(), single.nlookup))),
}
}
+}
- impl Reply {
- pub fn slice(self, data: &[u8]) -> Done<'o> {
- self.chain(OutputChain::tail(&[data]))
- }
+impl<'o> Reply<'o, Forget> {
+ pub fn ok(self) -> Done<'o> {
+ // No reply for forget requests
+ Done::new()
}
}
-op! {
- Write {
- type RequestBody = (&'o proto::WriteIn, &'o [u8]);
- type ReplyTail = state::Write;
+impl<'o> Request<'o, Getattr> {
+ pub fn handle(&self) -> u64 {
+ self.body.fh
}
+}
- impl Request {
- pub fn handle(&self) -> u64 {
- self.body.0.fh
- }
+impl<'o> Reply<'o, Getattr> {
+ pub fn known(self, inode: &impl Stat) -> Done<'o> {
+ let (attrs, ttl) = inode.attrs();
+ let attrs = attrs.finish(inode);
- pub fn offset(&self) -> u64 {
- self.body.0.offset
- }
+ self.single(&proto::AttrOut {
+ attr_valid: ttl.seconds,
+ attr_valid_nsec: ttl.nanoseconds,
+ dummy: Default::default(),
+ attr: attrs,
+ })
+ }
+}
- pub fn data(&self) -> &[u8] {
- self.body.1
- }
+impl<'o> Reply<'o, Readlink> {
+ /// This inode corresponds to a symbolic link pointing to the given target path.
+ pub fn target<T: AsRef<OsStr>>(self, target: T) -> Done<'o> {
+ self.chain(OutputChain::tail(&[target.as_ref().as_bytes()]))
}
- impl Reply {
- pub fn all(self) -> Done<'o> {
- let size = self.tail.size;
- self.single(&proto::WriteOut {
- size,
- padding: Default::default(),
- })
- }
+ /// Same as [`Reply::target()`], except that the target path is taken from disjoint
+ /// slices. This involves no additional allocation.
+ pub fn gather_target(self, target: &[&[u8]]) -> Done<'o> {
+ self.chain(OutputChain::tail(target))
}
}
-op! {
- Init {
- type RequestBody = &'o proto::InitIn;
- type ReplyTail = state::Init;
- }
-
- impl Reply {
- pub fn ok(self) -> Done<'o> {
- let state::Init { kernel_flags, buffer_pages } = self.tail;
-
- let flags = {
- use proto::InitFlags;
-
- //TODO: Conditions for these feature flags
- // - Locks
- // - ASYNC_DIO
- // - WRITEBACK_CACHE
- // - NO_OPEN_SUPPORT
- // - HANDLE_KILLPRIV
- // - POSIX_ACL
- // - NO_OPENDIR_SUPPORT
- // - EXPLICIT_INVAL_DATA
-
- let supported = InitFlags::ASYNC_READ
- | InitFlags::FILE_OPS
- | InitFlags::ATOMIC_O_TRUNC
- | InitFlags::EXPORT_SUPPORT
- | InitFlags::BIG_WRITES
- | InitFlags::HAS_IOCTL_DIR
- | InitFlags::AUTO_INVAL_DATA
- | InitFlags::DO_READDIRPLUS
- | InitFlags::READDIRPLUS_AUTO
- | InitFlags::PARALLEL_DIROPS
- | InitFlags::ABORT_ERROR
- | InitFlags::MAX_PAGES
- | InitFlags::CACHE_SYMLINKS;
-
- kernel_flags & supported
- };
-
- let buffer_size = page_size() * buffer_pages;
-
- // See fs/fuse/dev.c in the kernel source tree for details about max_write
- let max_write = buffer_size - std::mem::size_of::<(proto::InHeader, proto::WriteIn)>();
-
- self.single(&proto::InitOut {
- major: proto::MAJOR_VERSION,
- minor: proto::TARGET_MINOR_VERSION,
- max_readahead: 0, //TODO
- flags: flags.bits(),
- max_background: 0, //TODO
- congestion_threshold: 0, //TODO
- max_write: max_write.try_into().unwrap(),
- time_gran: 1, //TODO
- max_pages: buffer_pages.try_into().unwrap(),
- padding: Default::default(),
- unused: Default::default(),
- })
- }
+impl<'o> Request<'o, Open> {
+ pub fn flags(&self) -> OpenFlags {
+ OpenFlags::from_bits_truncate(self.body.flags.try_into().unwrap_or_default())
}
}
-op! {
- Statfs {
- type RequestBody = ();
- type ReplyTail = ();
+impl<'o> Reply<'o, Open> {
+ pub fn force_direct_io(&mut self) {
+ self.tail |= proto::OpenOutFlags::DIRECT_IO;
}
- impl Reply {
- /// Replies with filesystem statistics.
- pub fn info(self, statfs: &FsInfo) -> Done<'o> {
- self.single(&proto::StatfsOut::from(*statfs))
- }
+ pub fn ok(self) -> Done<'o> {
+ self.ok_with_handle(0)
+ }
+
+ pub fn ok_with_handle(self, handle: u64) -> Done<'o> {
+ let open_flags = self.tail.bits();
+
+ self.single(&proto::OpenOut {
+ fh: handle,
+ open_flags,
+ padding: Default::default(),
+ })
}
}
-op! {
- Release {
- type RequestBody = &'o proto::ReleaseIn;
- type ReplyTail = ();
+impl<'o> Request<'o, Read> {
+ pub fn handle(&self) -> u64 {
+ self.body.fh
}
- impl Request {
- pub fn handle(&self) -> u64 {
- self.body.fh
- }
+ pub fn offset(&self) -> u64 {
+ self.body.offset
}
- impl Reply {
- pub fn ok(self) -> Done<'o> {
- self.empty()
- }
+ pub fn size(&self) -> u32 {
+ self.body.size
}
}
-op! {
- Setxattr {
- // header, name, value
- type RequestBody = (&'o proto::SetxattrIn, &'o CStr, &'o [u8]);
- type ReplyTail = ();
+impl<'o> Reply<'o, Read> {
+ pub fn slice(self, data: &[u8]) -> Done<'o> {
+ self.chain(OutputChain::tail(&[data]))
}
+}
- //TODO: flags
- impl Request {
- pub fn name(&self) -> &OsStr {
- let (_header, name, _value) = self.body;
- c_to_os(name)
- }
-
- pub fn value(&self) -> &[u8] {
- let (_header, _name, value) = self.body;
- value
- }
+impl<'o> Request<'o, Write> {
+ pub fn handle(&self) -> u64 {
+ self.body.0.fh
}
- impl Reply {
- pub fn ok(self) -> Done<'o> {
- self.empty()
- }
+ pub fn offset(&self) -> u64 {
+ self.body.0.offset
+ }
- pub fn not_found(self) -> Done<'o> {
- self.fail(Errno::ENODATA)
- }
+ pub fn data(&self) -> &[u8] {
+ self.body.1
}
}
-op! {
- Getxattr {
- type RequestBody = (&'o proto::GetxattrIn, &'o CStr);
- type ReplyTail = state::ReadXattr;
+impl<'o> Reply<'o, Write> {
+ pub fn all(self) -> Done<'o> {
+ let size = self.tail.size;
+ self.single(&proto::WriteOut {
+ size,
+ padding: Default::default(),
+ })
}
+}
- impl Request {
- pub fn size(&self) -> u32 {
- self.body.0.size
- }
+impl<'o> Reply<'o, Init> {
+ pub fn ok(self) -> Done<'o> {
+ let state::Init {
+ kernel_flags,
+ buffer_pages,
+ } = self.tail;
- pub fn name(&self) -> &OsStr {
- c_to_os(self.body.1)
- }
- }
+ let flags = {
+ use proto::InitFlags;
- impl Reply {
- pub fn slice(self, value: &[u8]) -> Done<'o> {
- let size = value.len().try_into().expect("Extremely large xattr");
- if self.tail.size == 0 {
- return self.value_size(size);
- } else if self.tail.size < size {
- return self.buffer_too_small();
- }
+ //TODO: Conditions for these feature flags
+ // - Locks
+ // - ASYNC_DIO
+ // - WRITEBACK_CACHE
+ // - NO_OPEN_SUPPORT
+ // - HANDLE_KILLPRIV
+ // - POSIX_ACL
+ // - NO_OPENDIR_SUPPORT
+ // - EXPLICIT_INVAL_DATA
- self.chain(OutputChain::tail(&[value]))
- }
+ let supported = InitFlags::ASYNC_READ
+ | InitFlags::FILE_OPS
+ | InitFlags::ATOMIC_O_TRUNC
+ | InitFlags::EXPORT_SUPPORT
+ | InitFlags::BIG_WRITES
+ | InitFlags::HAS_IOCTL_DIR
+ | InitFlags::AUTO_INVAL_DATA
+ | InitFlags::DO_READDIRPLUS
+ | InitFlags::READDIRPLUS_AUTO
+ | InitFlags::PARALLEL_DIROPS
+ | InitFlags::ABORT_ERROR
+ | InitFlags::MAX_PAGES
+ | InitFlags::CACHE_SYMLINKS;
- pub fn value_size(self, size: u32) -> Done<'o> {
- assert_eq!(self.tail.size, 0);
+ kernel_flags & supported
+ };
- self.single(&proto::GetxattrOut {
- size,
- padding: Default::default(),
- })
- }
+ let buffer_size = page_size() * buffer_pages;
- pub fn buffer_too_small(self) -> Done<'o> {
- self.fail(Errno::ERANGE)
- }
+ // See fs/fuse/dev.c in the kernel source tree for details about max_write
+ let max_write = buffer_size - std::mem::size_of::<(proto::InHeader, proto::WriteIn)>();
- pub fn not_found(self) -> Done<'o> {
- self.fail(Errno::ENODATA)
- }
+ self.single(&proto::InitOut {
+ major: proto::MAJOR_VERSION,
+ minor: proto::TARGET_MINOR_VERSION,
+ max_readahead: 0, //TODO
+ flags: flags.bits(),
+ max_background: 0, //TODO
+ congestion_threshold: 0, //TODO
+ max_write: max_write.try_into().unwrap(),
+ time_gran: 1, //TODO
+ max_pages: buffer_pages.try_into().unwrap(),
+ padding: Default::default(),
+ unused: Default::default(),
+ })
+ }
+}
+
+impl<'o> Reply<'o, Statfs> {
+ /// Replies with filesystem statistics.
+ pub fn info(self, statfs: &FsInfo) -> Done<'o> {
+ self.single(&proto::StatfsOut::from(*statfs))
}
}
-op! {
- Listxattr {
- type RequestBody = &'o proto::ListxattrIn;
- type ReplyTail = state::ReadXattr;
+impl<'o> Request<'o, Release> {
+ pub fn handle(&self) -> u64 {
+ self.body.fh
}
+}
- impl Request {
- pub fn size(&self) -> u32 {
- self.body.getxattr_in.size
- }
+impl<'o> Reply<'o, Release> {
+ pub fn ok(self) -> Done<'o> {
+ self.empty()
}
+}
- impl Reply {
- //TODO: buffered(), gather()
+//TODO: flags
+impl<'o> Request<'o, Setxattr> {
+ pub fn name(&self) -> &OsStr {
+ let (_header, name, _value) = self.body;
+ c_to_os(name)
+ }
- pub fn value_size(self, size: u32) -> Done<'o> {
- assert_eq!(self.tail.size, 0);
+ pub fn value(&self) -> &[u8] {
+ let (_header, _name, value) = self.body;
+ value
+ }
+}
- self.single(&proto::ListxattrOut {
- getxattr_out: proto::GetxattrOut {
- size,
- padding: Default::default(),
- },
- })
- }
+impl<'o> Reply<'o, Setxattr> {
+ pub fn ok(self) -> Done<'o> {
+ self.empty()
+ }
- pub fn buffer_too_small(self) -> Done<'o> {
- self.fail(Errno::ERANGE)
- }
+ pub fn not_found(self) -> Done<'o> {
+ self.fail(Errno::ENODATA)
}
}
-op! {
- Removexattr {
- type RequestBody = &'o CStr;
- type ReplyTail = ();
+impl<'o> Request<'o, Getxattr> {
+ pub fn size(&self) -> u32 {
+ self.body.0.size
}
- impl Request {
- pub fn name(&self) -> &OsStr {
- c_to_os(self.body)
- }
+ pub fn name(&self) -> &OsStr {
+ c_to_os(self.body.1)
}
+}
- impl Reply {
- pub fn ok(self) -> Done<'o> {
- self.empty()
+impl<'o> Reply<'o, Getxattr> {
+ pub fn slice(self, value: &[u8]) -> Done<'o> {
+ let size = value.len().try_into().expect("Extremely large xattr");
+ if self.tail.size == 0 {
+ return self.value_size(size);
+ } else if self.tail.size < size {
+ return self.buffer_too_small();
}
+
+ self.chain(OutputChain::tail(&[value]))
}
-}
-op! {
- Flush {
- type RequestBody = &'o proto::FlushIn;
- type ReplyTail = ();
+ pub fn value_size(self, size: u32) -> Done<'o> {
+ assert_eq!(self.tail.size, 0);
+
+ self.single(&proto::GetxattrOut {
+ size,
+ padding: Default::default(),
+ })
}
- impl Request {
- pub fn handle(&self) -> u64 {
- self.body.fh
- }
+ pub fn buffer_too_small(self) -> Done<'o> {
+ self.fail(Errno::ERANGE)
}
- impl Reply {
- pub fn ok(self) -> Done<'o> {
- self.empty()
- }
+ pub fn not_found(self) -> Done<'o> {
+ self.fail(Errno::ENODATA)
}
}
-op! {
- Opendir {
- type RequestBody = &'o proto::OpendirIn;
- type ReplyTail = ();
+impl<'o> Request<'o, Listxattr> {
+ pub fn size(&self) -> u32 {
+ self.body.getxattr_in.size
}
+}
- impl Reply {
- pub fn ok(self) -> Done<'o> {
- self.ok_with_handle(0)
- }
+impl<'o> Reply<'o, Listxattr> {
+ //TODO: buffered(), gather()
+
+ pub fn value_size(self, size: u32) -> Done<'o> {
+ assert_eq!(self.tail.size, 0);
- pub fn ok_with_handle(self, handle: u64) -> Done<'o> {
- self.single(&proto::OpenOut {
- fh: handle,
- open_flags: 0,
+ self.single(&proto::ListxattrOut {
+ getxattr_out: proto::GetxattrOut {
+ size,
padding: Default::default(),
- })
- }
+ },
+ })
+ }
+
+ pub fn buffer_too_small(self) -> Done<'o> {
+ self.fail(Errno::ERANGE)
}
}
-op! {
- Readdir {
- type RequestBody = proto::OpcodeSelect<
- &'o proto::ReaddirPlusIn,
- &'o proto::ReaddirIn,
- { proto::Opcode::ReaddirPlus as u32 },
- >;
+impl<'o> Request<'o, Removexattr> {
+ pub fn name(&self) -> &OsStr {
+ c_to_os(self.body)
+ }
+}
- type ReplyTail = state::Readdir<()>;
+impl<'o> Reply<'o, Removexattr> {
+ pub fn ok(self) -> Done<'o> {
+ self.empty()
}
+}
- impl Request {
- pub fn handle(&self) -> u64 {
- self.read_in().fh
- }
+impl<'o> Request<'o, Flush> {
+ pub fn handle(&self) -> u64 {
+ self.body.fh
+ }
+}
- /// Returns the base offset in the directory stream to read from.
- pub fn offset(&self) -> u64 {
- self.read_in().offset
- }
+impl<'o> Reply<'o, Flush> {
+ pub fn ok(self) -> Done<'o> {
+ self.empty()
+ }
+}
- pub fn size(&self) -> u32 {
- self.read_in().size
- }
+impl<'o> Reply<'o, Opendir> {
+ pub fn ok(self) -> Done<'o> {
+ self.ok_with_handle(0)
+ }
- fn read_in(&self) -> &proto::ReadIn {
- use proto::OpcodeSelect::*;
+ pub fn ok_with_handle(self, handle: u64) -> Done<'o> {
+ self.single(&proto::OpenOut {
+ fh: handle,
+ open_flags: 0,
+ padding: Default::default(),
+ })
+ }
+}
- match &self.body {
- Match(readdir_plus) => &readdir_plus.read_in,
- Alt(readdir) => &readdir.read_in,
- }
- }
+impl<'o> Request<'o, Readdir> {
+ pub fn handle(&self) -> u64 {
+ self.read_in().fh
}
- impl Reply {
- pub fn buffered<B>(self, buffer: B) -> Reply<'o, BufferedReaddir<B>>
- where
- B: BufMut + AsRef<[u8]>,
- {
- assert!(buffer.as_ref().is_empty());
+ /// Returns the base offset in the directory stream to read from.
+ pub fn offset(&self) -> u64 {
+ self.read_in().offset
+ }
- let state::Readdir { max_read, is_plus, buffer: (), } = self.tail;
+ pub fn size(&self) -> u32 {
+ self.read_in().size
+ }
- Reply {
- session: self.session,
- unique: self.unique,
- tail: state::Readdir { max_read, is_plus, buffer, },
- }
+ fn read_in(&self) -> &proto::ReadIn {
+ use proto::OpcodeSelect::*;
+
+ match &self.body {
+ Match(readdir_plus) => &readdir_plus.read_in,
+ Alt(readdir) => &readdir.read_in,
}
}
}
-pub struct BufferedReaddir<B>(Infallible, PhantomData<B>);
+impl<'o> Reply<'o, Readdir> {
+ pub fn buffered<B>(self, buffer: B) -> Reply<'o, BufferedReaddir<B>>
+ where
+ B: BufMut + AsRef<[u8]>,
+ {
+ assert!(buffer.as_ref().is_empty());
-impl<B> Sealed for BufferedReaddir<B> {}
+ let state::Readdir {
+ max_read,
+ is_plus,
+ buffer: (),
+ } = self.tail;
-impl<'o, B> Operation<'o> for BufferedReaddir<B> {
- type RequestBody = (); // Never actually created
- type ReplyTail = state::Readdir<B>;
+ Reply {
+ session: self.session,
+ unique: self.unique,
+ tail: state::Readdir {
+ max_read,
+ is_plus,
+ buffer,
+ },
+ }
+ }
}
impl<'o, B: BufMut + AsRef<[u8]>> Reply<'o, BufferedReaddir<B>> {
@@ -693,45 +700,31 @@ impl<'o, B: BufMut + AsRef<[u8]>> Reply<'o, BufferedReaddir<B>> {
}
}
-op! {
- Releasedir {
- type RequestBody = &'o proto::ReleasedirIn;
- type ReplyTail = ();
- }
-
- impl Request {
- pub fn handle(&self) -> u64 {
- self.body.release_in.fh
- }
+impl<'o> Request<'o, Releasedir> {
+ pub fn handle(&self) -> u64 {
+ self.body.release_in.fh
}
+}
- impl Reply {
- pub fn ok(self) -> Done<'o> {
- self.empty()
- }
+impl<'o> Reply<'o, Releasedir> {
+ pub fn ok(self) -> Done<'o> {
+ self.empty()
}
}
-op! {
- Access {
- type RequestBody = &'o proto::AccessIn;
- type ReplyTail = ();
+impl<'o> Request<'o, Access> {
+ pub fn mask(&self) -> AccessFlags {
+ AccessFlags::from_bits_truncate(self.body.mask as i32)
}
+}
- impl Request {
- pub fn mask(&self) -> AccessFlags {
- AccessFlags::from_bits_truncate(self.body.mask as i32)
- }
+impl<'o> Reply<'o, Access> {
+ pub fn ok(self) -> Done<'o> {
+ self.empty()
}
- impl Reply {
- pub fn ok(self) -> Done<'o> {
- self.empty()
- }
-
- pub fn permission_denied(self) -> Done<'o> {
- self.fail(Errno::EACCES)
- }
+ pub fn permission_denied(self) -> Done<'o> {
+ self.fail(Errno::EACCES)
}
}