Implement dir ops and inode ops in Rust. Signed-off-by: Yiyang Wu <toolmanp@xxxxxxx> --- fs/erofs/rust/erofs_sys.rs | 1 + fs/erofs/rust/erofs_sys/data.rs | 4 ++ fs/erofs/rust/erofs_sys/operations.rs | 35 ++++++++++++++++ fs/erofs/rust/erofs_sys/superblock.rs | 59 +++++++++++++++++++++++++++ 4 files changed, 99 insertions(+) create mode 100644 fs/erofs/rust/erofs_sys/operations.rs diff --git a/fs/erofs/rust/erofs_sys.rs b/fs/erofs/rust/erofs_sys.rs index 20c0aa81a800..8c08ac347b2b 100644 --- a/fs/erofs/rust/erofs_sys.rs +++ b/fs/erofs/rust/erofs_sys.rs @@ -30,6 +30,7 @@ pub(crate) mod errnos; pub(crate) mod inode; pub(crate) mod map; +pub(crate) mod operations; pub(crate) mod superblock; pub(crate) mod xattrs; pub(crate) use errnos::{Errno, Errno::*}; diff --git a/fs/erofs/rust/erofs_sys/data.rs b/fs/erofs/rust/erofs_sys/data.rs index 21630673c24e..67bb66ce9efb 100644 --- a/fs/erofs/rust/erofs_sys/data.rs +++ b/fs/erofs/rust/erofs_sys/data.rs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: MIT or GPL-2.0-or-later pub(crate) mod backends; pub(crate) mod raw_iters; +use super::dir::*; use super::inode::*; use super::map::*; use super::superblock::*; @@ -26,6 +27,9 @@ pub(crate) trait Backend { /// DirEntries. pub(crate) trait Buffer { fn content(&self) -> &[u8]; + fn iter_dir(&self) -> DirCollection<'_> { + DirCollection::new(self.content()) + } } /// Represents a buffer that holds a reference to a slice of data that diff --git a/fs/erofs/rust/erofs_sys/operations.rs b/fs/erofs/rust/erofs_sys/operations.rs new file mode 100644 index 000000000000..070ba20908a2 --- /dev/null +++ b/fs/erofs/rust/erofs_sys/operations.rs @@ -0,0 +1,35 @@ +// Copyright 2024 Yiyang Wu +// SPDX-License-Identifier: MIT or GPL-2.0-or-later + +use super::inode::*; +use super::superblock::*; +use super::*; + +pub(crate) fn read_inode<'a, I, C>( + filesystem: &'a dyn FileSystem<I>, + collection: &'a mut C, + nid: Nid, +) -> PosixResult<&'a mut I> +where + I: Inode, + C: InodeCollection<I = I>, +{ + collection.iget(nid, filesystem) +} + +pub(crate) fn dir_lookup<'a, I, C>( + filesystem: &'a dyn FileSystem<I>, + collection: &'a mut C, + inode: &I, + name: &str, +) -> PosixResult<&'a mut I> +where + I: Inode, + C: InodeCollection<I = I>, +{ + filesystem + .find_nid(inode, name)? + .map_or(Err(Errno::ENOENT), |nid| { + read_inode(filesystem, collection, nid) + }) +} diff --git a/fs/erofs/rust/erofs_sys/superblock.rs b/fs/erofs/rust/erofs_sys/superblock.rs index f60657eff3d6..403ffdeb4573 100644 --- a/fs/erofs/rust/erofs_sys/superblock.rs +++ b/fs/erofs/rust/erofs_sys/superblock.rs @@ -8,6 +8,7 @@ use super::data::raw_iters::*; use super::data::*; use super::devices::*; +use super::dir::*; use super::inode::*; use super::map::*; use super::*; @@ -287,6 +288,64 @@ fn continuous_iter<'a>( offset: Off, len: Off, ) -> PosixResult<Box<dyn ContinuousBufferIter<'a> + 'a>>; + + // Inode related goes here. + fn read_inode_info(&self, nid: Nid) -> PosixResult<InodeInfo> { + (self.as_filesystem(), nid).try_into() + } + + fn find_nid(&self, inode: &I, name: &str) -> PosixResult<Option<Nid>> { + for buf in self.mapped_iter(inode, 0)? { + for dirent in buf?.iter_dir() { + if dirent.dirname() == name.as_bytes() { + return Ok(Some(dirent.desc.nid)); + } + } + } + Ok(None) + } + + // Readdir related goes here. + fn fill_dentries( + &self, + inode: &I, + offset: Off, + emitter: &mut dyn FnMut(Dirent<'_>, Off), + ) -> PosixResult<()> { + let sb = self.superblock(); + let accessor = sb.blk_access(offset); + if offset > inode.info().file_size() { + return Err(EUCLEAN); + } + + let map_offset = round!(DOWN, offset, sb.blksz()); + let blk_offset = round!(UP, accessor.off, size_of::<DirentDesc>() as Off); + + let mut map_iter = self.mapped_iter(inode, map_offset)?; + let first_buf = map_iter.next().unwrap()?; + let mut collection = first_buf.iter_dir(); + + let mut pos: Off = map_offset + blk_offset; + + if blk_offset as usize / size_of::<DirentDesc>() <= collection.total() { + collection.skip_dir(blk_offset as usize / size_of::<DirentDesc>()); + for dirent in collection { + emitter(dirent, pos); + pos += size_of::<DirentDesc>() as Off; + } + } + + pos = round!(UP, pos, sb.blksz()); + + for buf in map_iter { + for dirent in buf?.iter_dir() { + emitter(dirent, pos); + pos += size_of::<DirentDesc>() as Off; + } + pos = round!(UP, pos, sb.blksz()); + } + Ok(()) + } } pub(crate) struct SuperblockInfo<I, C, T> -- 2.46.0