diff --git a/src/tools.rs b/src/tools.rs index baf8cc4b..77e985ab 100644 --- a/src/tools.rs +++ b/src/tools.rs @@ -15,6 +15,7 @@ use std::io::Read; use std::io::ErrorKind; use std::time::Duration; +use std::os::unix::io::RawFd; use std::os::unix::io::AsRawFd; use serde_json::Value; @@ -230,6 +231,7 @@ pub fn file_chunker( Ok(()) } +/// Returns the hosts node name (UTS node name) pub fn nodename() -> &'static str { lazy_static!{ @@ -313,3 +315,43 @@ pub fn complete_file_name(arg: &str) -> Vec { result } + +/// Scan directory for matching file names. +/// +/// Scan through all directory entries and call `callback()` function +/// if the entry name matches the regular expression. This function +/// used unix `openat()`, so you can pass absolute or relative file +/// names. This function simply skips non-UTF8 encoded names. +pub fn scandir( + dirfd: RawFd, + path: P, + regex: ®ex::Regex, + callback: F +) -> Result<(), Error> + where F: Fn(RawFd, &str, nix::dir::Type) -> Result<(), Error>, + P: AsRef +{ + use nix::fcntl::OFlag; + use nix::sys::stat::Mode; + + let mut subdir = nix::dir::Dir::openat(dirfd, path.as_ref(), OFlag::O_RDONLY, Mode::empty())?; + let subdir_fd = subdir.as_raw_fd(); + + for entry in subdir.iter() { + let entry = entry?; + let file_type = match entry.file_type() { + Some(file_type) => file_type, + None => bail!("unable to detect file type"), + }; + let filename = entry.file_name(); + let filename_str = match filename.to_str() { + Ok(name) => name, + Err(_) => continue /* ignore non utf8 entries*/, + }; + + if !regex.is_match(filename_str) { continue; } + + (callback)(subdir_fd, filename_str, file_type)?; + } + Ok(()) +}