diff options
| author | Alejandro Soto <alejandro@34project.org> | 2022-01-04 06:49:48 -0600 |
|---|---|---|
| committer | Alejandro Soto <alejandro@34project.org> | 2022-01-04 06:49:52 -0600 |
| commit | 70baa472b2bee69f205cc1aada304d597b858005 (patch) | |
| tree | 7a0b1a0381b68fe0e091b87d00634ff13568bf6d /src/fuse/ops/dir.rs | |
| parent | 1955ec118a32d3fa174496abe5442c82c609273a (diff) | |
Move crate::fuse::* to the top-level
Diffstat (limited to 'src/fuse/ops/dir.rs')
| -rw-r--r-- | src/fuse/ops/dir.rs | 253 |
1 files changed, 0 insertions, 253 deletions
diff --git a/src/fuse/ops/dir.rs b/src/fuse/ops/dir.rs deleted file mode 100644 index 76267ec..0000000 --- a/src/fuse/ops/dir.rs +++ /dev/null @@ -1,253 +0,0 @@ -use std::{ - convert::Infallible, - ffi::{CStr, OsStr}, - marker::PhantomData, - os::unix::ffi::OsStrExt, -}; - -use crate::fuse::{ - io::{Entry, EntryType, Interruptible, Known, Stat}, - private_trait::Sealed, - Done, Operation, Reply, Request, -}; - -use super::{c_to_os, FromRequest}; -use crate::{proto, Errno, Ino, Ttl}; -use bytemuck::{bytes_of, Zeroable}; -use bytes::BufMut; -use nix::sys::stat::SFlag; - -pub enum Lookup {} -pub enum Readdir {} -pub struct BufferedReaddir<B>(Infallible, PhantomData<B>); - -pub struct ReaddirState<B> { - max_read: usize, - is_plus: bool, - buffer: B, -} - -impl Sealed for Lookup {} -impl Sealed for Readdir {} -impl<B> Sealed for BufferedReaddir<B> {} - -impl<'o> Operation<'o> for Lookup { - type RequestBody = &'o CStr; // name() - type ReplyTail = (); -} - -impl<'o> Operation<'o> for Readdir { - type RequestBody = proto::OpcodeSelect< - &'o proto::ReaddirPlusIn, - &'o proto::ReaddirIn, - { proto::Opcode::ReaddirPlus as u32 }, - >; - - type ReplyTail = ReaddirState<()>; -} - -impl<'o, B> Operation<'o> for BufferedReaddir<B> { - type RequestBody = (); // Never actually created - type ReplyTail = ReaddirState<B>; -} - -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<'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 - } - - /// 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), - )) - } - - /// 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> { - pub fn handle(&self) -> u64 { - self.read_in().fh - } - - /// Returns the base offset in the directory stream to read from. - pub fn offset(&self) -> u64 { - self.read_in().offset - } - - pub fn size(&self) -> u32 { - self.read_in().size - } - - fn read_in(&self) -> &proto::ReadIn { - use proto::OpcodeSelect::*; - - match &self.body { - Match(readdir_plus) => &readdir_plus.read_in, - Alt(readdir) => &readdir.read_in, - } - } -} - -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()); - - let ReaddirState { - max_read, - is_plus, - buffer: (), - } = self.tail; - - Reply { - session: self.session, - unique: self.unique, - tail: ReaddirState { - max_read, - is_plus, - buffer, - }, - } - } -} - -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 { - std::mem::size_of::<proto::DirentPlus>() - } else { - std::mem::size_of::<proto::Dirent>() - }; - - let name = entry.name.as_bytes(); - let padding_len = dirent_pad_bytes(entry_header_len + name.len()); - - let buffer = &mut self.tail.buffer; - let remaining = buffer - .remaining_mut() - .min(self.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)); - } - - return Interruptible::Interrupted(self.end()); - } - - let inode = entry.inode.inode(); - let entry_type = match inode.inode_type() { - EntryType::Fifo => SFlag::S_IFIFO, - EntryType::CharacterDevice => SFlag::S_IFCHR, - EntryType::Directory => SFlag::S_IFDIR, - EntryType::BlockDevice => SFlag::S_IFBLK, - EntryType::File => SFlag::S_IFREG, - EntryType::Symlink => SFlag::S_IFLNK, - EntryType::Socket => SFlag::S_IFSOCK, - }; - - let ino = inode.ino(); - let dirent = proto::Dirent { - ino: ino.as_raw(), - off: entry.offset, - namelen: name.len().try_into().unwrap(), - entry_type: entry_type.bits() >> 12, - }; - - enum Ent { - Dirent(proto::Dirent), - DirentPlus(proto::DirentPlus), - } - - let ent = if self.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)); - - if name != ".".as_bytes() && name != "..".as_bytes() { - entry.inode.unveil(); - } - - Ent::DirentPlus(proto::DirentPlus { entry_out, dirent }) - } else { - Ent::Dirent(dirent) - }; - - let entry_header = match &ent { - Ent::Dirent(dirent) => bytes_of(dirent), - Ent::DirentPlus(dirent_plus) => bytes_of(dirent_plus), - }; - - buffer.put_slice(entry_header); - buffer.put_slice(name); - buffer.put_slice(&[0; 7][..padding_len]); - - if remaining - record_len >= entry_header.len() + (1 << proto::DIRENT_ALIGNMENT_BITS) { - Interruptible::Completed(self, ()) - } else { - Interruptible::Interrupted(self.end()) - } - } - - pub fn end(self) -> Done<'o> { - self.inner(|this| this.tail.buffer.as_ref()) - } -} - -impl<'o> FromRequest<'o, Readdir> for ReaddirState<()> { - fn from_request(request: &Request<'o, Readdir>) -> Self { - ReaddirState { - max_read: request.size() as usize, - is_plus: matches!(request.body, proto::OpcodeSelect::Match(_)), - buffer: (), - } - } -} - -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 -} |
