summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/fuse/ops.rs147
-rw-r--r--src/fuse/session.rs12
-rw-r--r--src/proto.rs26
3 files changed, 180 insertions, 5 deletions
diff --git a/src/fuse/ops.rs b/src/fuse/ops.rs
index e6de185..e55511a 100644
--- a/src/fuse/ops.rs
+++ b/src/fuse/ops.rs
@@ -63,7 +63,7 @@ op! {
impl Request {
/// Returns the name of the entry being looked up in this directory.
pub fn name(&self) -> &OsStr {
- OsStr::from_bytes(self.body.to_bytes())
+ c_to_os(self.body)
}
}
@@ -361,6 +361,135 @@ op! {
}
op! {
+ Setxattr {
+ // header, name, value
+ type RequestBody = (&'o proto::SetxattrIn, &'o CStr, &'o [u8]);
+ type ReplyTail = ();
+ }
+
+ //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 Reply {
+ pub fn ok(self) -> Done<'o> {
+ self.empty()
+ }
+
+ pub fn not_found(self) -> Done<'o> {
+ self.fail(Errno::ENODATA)
+ }
+ }
+}
+
+op! {
+ Getxattr {
+ type RequestBody = (&'o proto::GetxattrIn, &'o CStr);
+ type ReplyTail = state::ReadXattr;
+ }
+
+ impl Request {
+ pub fn size(&self) -> u32 {
+ self.body.0.size
+ }
+
+ pub fn name(&self) -> &OsStr {
+ c_to_os(self.body.1)
+ }
+ }
+
+ 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();
+ }
+
+ 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)
+ }
+ }
+}
+
+op! {
+ Listxattr {
+ type RequestBody = &'o proto::ListxattrIn;
+ type ReplyTail = state::ReadXattr;
+ }
+
+ impl Request {
+ pub fn size(&self) -> u32 {
+ self.body.getxattr_in.size
+ }
+ }
+
+ impl Reply {
+ //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)
+ }
+ }
+}
+
+op! {
+ Removexattr {
+ type RequestBody = &'o CStr;
+ type ReplyTail = ();
+ }
+
+ impl Request {
+ pub fn name(&self) -> &OsStr {
+ c_to_os(self.body)
+ }
+ }
+
+ impl Reply {
+ pub fn ok(self) -> Done<'o> {
+ self.empty()
+ }
+ }
+}
+
+op! {
Opendir {
type RequestBody = &'o proto::OpendirIn;
type ReplyTail = ();
@@ -578,13 +707,17 @@ pub(crate) mod state {
}
pub struct Readdir<B> {
- pub max_read: usize,
- pub is_plus: bool,
- pub buffer: B,
+ pub(super) max_read: usize,
+ pub(super) is_plus: bool,
+ pub(super) buffer: B,
}
pub struct Write {
- pub size: u32,
+ pub(super) size: u32,
+ }
+
+ pub struct ReadXattr {
+ pub(super) size: u32,
}
}
@@ -667,3 +800,7 @@ 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
}
+
+fn c_to_os(c_str: &CStr) -> &OsStr {
+ OsStr::from_bytes(c_str.to_bytes())
+}
diff --git a/src/fuse/session.rs b/src/fuse/session.rs
index 8b31706..1fbcb68 100644
--- a/src/fuse/session.rs
+++ b/src/fuse/session.rs
@@ -62,6 +62,10 @@ pub enum Dispatch<'o> {
Write(Incoming<'o, ops::Write>),
Statfs(Incoming<'o, ops::Statfs>),
Release(Incoming<'o, ops::Release>),
+ Setxattr(Incoming<'o, ops::Setxattr>),
+ Getxattr(Incoming<'o, ops::Getxattr>),
+ Listxattr(Incoming<'o, ops::Listxattr>),
+ Removexattr(Incoming<'o, ops::Removexattr>),
Opendir(Incoming<'o, ops::Opendir>),
Readdir(Incoming<'o, ops::Readdir>),
Releasedir(Incoming<'o, ops::Releasedir>),
@@ -229,6 +233,10 @@ impl<'o> Dispatch<'o> {
Write(incoming) => incoming.common,
Statfs(incoming) => incoming.common,
Release(incoming) => incoming.common,
+ Setxattr(incoming) => incoming.common,
+ Getxattr(incoming) => incoming.common,
+ Listxattr(incoming) => incoming.common,
+ Removexattr(incoming) => incoming.common,
Opendir(incoming) => incoming.common,
Readdir(incoming) => incoming.common,
Releasedir(incoming) => incoming.common,
@@ -299,6 +307,10 @@ impl Endpoint<'_> {
Write => dispatch!(Write),
Statfs => dispatch!(Statfs),
Release => dispatch!(Release),
+ Setxattr => dispatch!(Setxattr),
+ Getxattr => dispatch!(Getxattr),
+ Listxattr => dispatch!(Listxattr),
+ Removexattr => dispatch!(Removexattr),
Opendir => dispatch!(Opendir),
Readdir => dispatch!(Readdir),
Releasedir => dispatch!(Releasedir),
diff --git a/src/proto.rs b/src/proto.rs
index 128112d..2d53fe6 100644
--- a/src/proto.rs
+++ b/src/proto.rs
@@ -348,12 +348,25 @@ pub struct GetxattrIn {
#[derive(Pod, Zeroable, Copy, Clone)]
#[repr(C)]
+pub struct GetxattrOut {
+ pub size: u32,
+ pub padding: u32,
+}
+
+#[derive(Pod, Zeroable, Copy, Clone)]
+#[repr(C)]
pub struct ListxattrIn {
pub getxattr_in: GetxattrIn,
}
#[derive(Pod, Zeroable, Copy, Clone)]
#[repr(C)]
+pub struct ListxattrOut {
+ pub getxattr_out: GetxattrOut,
+}
+
+#[derive(Pod, Zeroable, Copy, Clone)]
+#[repr(C)]
pub struct FlushIn {
pub fh: u64,
pub unused: u32,
@@ -596,6 +609,19 @@ where
}
}
+impl<'o, T, U, V> Structured<'o> for (T, U, V)
+where
+ T: Structured<'o>,
+ U: Structured<'o>,
+ V: 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, third), end) = <(U, V)>::split_from(bytes, header, last)?;
+ Ok(((first, second, third), 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>()));