diff --git a/src/tools.rs b/src/tools.rs index 56a63f67..06b7eb18 100644 --- a/src/tools.rs +++ b/src/tools.rs @@ -25,6 +25,7 @@ pub mod wrapped_reader_stream; pub mod common_regex; pub mod ticket; pub mod borrow; +pub mod fs; /// The `BufferedReader` trait provides a single function /// `buffered_read`. It returns a reference to an internal buffer. The diff --git a/src/tools/fs.rs b/src/tools/fs.rs new file mode 100644 index 00000000..48abe436 --- /dev/null +++ b/src/tools/fs.rs @@ -0,0 +1,37 @@ +//! File system helper utilities. + +use std::os::unix::io::RawFd; + +use failure::Error; +use nix::dir; +use nix::dir::Dir; + +use crate::tools::borrow::Tied; + +// Since Tied implements Deref to U, a Tied already implements Iterator. +// This is simply a wrapper with a shorter type name mapping nix::Error to failure::Error. +/// Wrapper over a pair of `nix::dir::Dir` and `nix::dir::Iter`, returned by `read_subdir()`. +pub struct ReadDir { + iter: Tied>>, +} + +impl Iterator for ReadDir { + type Item = Result; + + fn next(&mut self) -> Option { + self.iter.next().map(|res| res.map_err(|e| Error::from(e))) + } +} + +/// Create an iterator over sub directory entries. +/// This uses `openat` on `dirfd`, so `path` can be relative to that or an absolute path. +pub fn read_subdir(dirfd: RawFd, path: &P) -> Result { + use nix::fcntl::OFlag; + use nix::sys::stat::Mode; + + let dir = Dir::openat(dirfd, path, OFlag::O_RDONLY, Mode::empty())?; + let iter = Tied::new(dir, |dir| { + Box::new(unsafe { (*dir).iter() }) as Box>> + }); + Ok(ReadDir { iter }) +}