diff options
| author | Alejandro Soto <alejandro@34project.org> | 2021-12-30 21:12:29 -0600 |
|---|---|---|
| committer | Alejandro Soto <alejandro@34project.org> | 2021-12-30 21:12:29 -0600 |
| commit | d6dead36761f4731951026f48bc3a8d83260b9e5 (patch) | |
| tree | ef36133994f78590cc995919bc7145a1d42bde6b | |
| parent | 59731f492f2f1094ed917d47f4369bc60cdc3385 (diff) | |
Add xattr filesystem calls
| -rw-r--r-- | src/fuse/ops.rs | 147 | ||||
| -rw-r--r-- | src/fuse/session.rs | 12 | ||||
| -rw-r--r-- | src/proto.rs | 26 |
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>())); |
