summaryrefslogtreecommitdiff
path: root/src/fuse/ops/xattr.rs
diff options
context:
space:
mode:
authorAlejandro Soto <alejandro@34project.org>2022-01-04 06:23:02 -0600
committerAlejandro Soto <alejandro@34project.org>2022-01-04 06:23:04 -0600
commitc3c7a5b25a47e54df5d6b887d19f23c6fb20be8b (patch)
tree7edf6f3a6c4ae2fd0fb6f8cb4139c80f0a365e01 /src/fuse/ops/xattr.rs
parent47cda6cd90d40a1b550d55f7181b34c21508c2fb (diff)
Split crate::fuse::ops into submodules
Diffstat (limited to '')
-rw-r--r--src/fuse/ops/xattr.rs139
1 files changed, 139 insertions, 0 deletions
diff --git a/src/fuse/ops/xattr.rs b/src/fuse/ops/xattr.rs
new file mode 100644
index 0000000..48d10bf
--- /dev/null
+++ b/src/fuse/ops/xattr.rs
@@ -0,0 +1,139 @@
+use std::ffi::{CStr, OsStr};
+use crate::{proto, util::OutputChain, Errno};
+use crate::fuse::{private_trait::Sealed, Done, Operation, Reply, Request};
+use super::c_to_os;
+
+pub enum Setxattr {}
+pub enum Getxattr {}
+pub enum Listxattr {}
+pub enum Removexattr {}
+
+pub struct XattrReadState {
+ size: u32,
+}
+
+impl Sealed for Setxattr {}
+impl Sealed for Getxattr {}
+impl Sealed for Listxattr {}
+impl Sealed for Removexattr {}
+
+impl<'o> Operation<'o> for Setxattr {
+ // header, name, value
+ type RequestBody = (&'o proto::SetxattrIn, &'o CStr, &'o [u8]);
+ type ReplyTail = ();
+}
+
+impl<'o> Operation<'o> for Getxattr {
+ type RequestBody = (&'o proto::GetxattrIn, &'o CStr);
+ type ReplyTail = XattrReadState;
+}
+
+impl<'o> Operation<'o> for Listxattr {
+ type RequestBody = &'o proto::ListxattrIn;
+ type ReplyTail = XattrReadState;
+}
+
+impl<'o> Operation<'o> for Removexattr {
+ type RequestBody = &'o CStr;
+ type ReplyTail = ();
+}
+
+//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(&self) -> &[u8] {
+ let (_header, _name, value) = self.body;
+ value
+ }
+}
+
+impl<'o> Reply<'o, Setxattr> {
+ pub fn ok(self) -> Done<'o> {
+ self.empty()
+ }
+
+ pub fn not_found(self) -> Done<'o> {
+ self.fail(Errno::ENODATA)
+ }
+}
+
+impl<'o> Request<'o, Getxattr> {
+ pub fn size(&self) -> u32 {
+ self.body.0.size
+ }
+
+ pub fn name(&self) -> &OsStr {
+ c_to_os(self.body.1)
+ }
+}
+
+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]))
+ }
+
+ pub fn value_size(self, size: u32) -> Done<'o> {
+ assert_eq!(self.tail.size, 0);
+
+ self.single(&proto::GetxattrOut {
+ size,
+ padding: Default::default(),
+ })
+ }
+
+ pub fn buffer_too_small(self) -> Done<'o> {
+ self.fail(Errno::ERANGE)
+ }
+
+ pub fn not_found(self) -> Done<'o> {
+ self.fail(Errno::ENODATA)
+ }
+}
+
+impl<'o> Request<'o, Listxattr> {
+ pub fn size(&self) -> u32 {
+ self.body.getxattr_in.size
+ }
+}
+
+impl<'o> Reply<'o, Listxattr> {
+ //TODO: buffered(), gather()
+
+ pub fn value_size(self, size: u32) -> Done<'o> {
+ assert_eq!(self.tail.size, 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)
+ }
+}
+
+impl<'o> Request<'o, Removexattr> {
+ pub fn name(&self) -> &OsStr {
+ c_to_os(self.body)
+ }
+}
+
+impl<'o> Reply<'o, Removexattr> {
+ pub fn ok(self) -> Done<'o> {
+ self.empty()
+ }
+}