From ff64bdbf2aee9ac4eb56d3b1f392b8187aada8eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Mon, 13 Mar 2017 16:42:41 +0100 Subject: [PATCH] add support for dirent family --- src/dirent.rs | 58 +++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + test/test.rs | 1 + test/test_dirent.rs | 37 +++++++++++++++++++++++++++++ 4 files changed, 97 insertions(+) create mode 100644 src/dirent.rs create mode 100644 test/test_dirent.rs diff --git a/src/dirent.rs b/src/dirent.rs new file mode 100644 index 0000000000..5089f7097e --- /dev/null +++ b/src/dirent.rs @@ -0,0 +1,58 @@ +use {Result, Error, Errno, NixPath}; +use errno; +use libc::{self, DIR, c_long}; + +#[cfg(not(any(target_os = "ios", target_os = "macos")))] +use std::os::unix::io::RawFd; + +pub struct Dir { + handle: *mut DIR, +} + +impl Drop for Dir { + fn drop(&mut self) { + unsafe { libc::closedir(self.handle) }; + } +} + +pub fn opendir(name: &P) -> Result { + let dirp = try!(name.with_nix_path(|cstr| unsafe { libc::opendir(cstr.as_ptr()) })); + if dirp.is_null() { + Err(Error::last().into()) + } else { + Ok(Dir { handle: dirp }) + } +} + +#[cfg(not(any(target_os = "ios", target_os = "macos")))] +pub fn fdopendir(fd: RawFd) -> Result { + let dirp = unsafe { libc::fdopendir(fd) }; + if dirp.is_null() { + Err(Error::last().into()) + } else { + Ok(Dir { handle: dirp }) + } +} + +pub fn readdir<'a>(dir: &'a mut Dir) -> Result> { + let dirent = unsafe { + Errno::clear(); + libc::readdir(dir.handle) + }; + if dirent.is_null() { + match Errno::last() { + errno::UnknownErrno => Ok(None), + _ => Err(Error::last().into()), + } + } else { + Ok(Some(unsafe { &*dirent })) + } +} + +pub fn seekdir<'a>(dir: &'a mut Dir, loc: c_long) { + unsafe { libc::seekdir(dir.handle, loc) }; +} + +pub fn telldir<'a>(dir: &'a mut Dir) -> c_long { + unsafe { libc::telldir(dir.handle) } +} diff --git a/src/lib.rs b/src/lib.rs index ecbf139dc6..49d4c5e591 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -34,6 +34,7 @@ pub mod libc { pub use libc::{c_int, c_void}; pub use errno::Errno; +pub mod dirent; pub mod errno; pub mod features; pub mod fcntl; diff --git a/test/test.rs b/test/test.rs index d10970d61d..fa9064fccc 100644 --- a/test/test.rs +++ b/test/test.rs @@ -8,6 +8,7 @@ extern crate tempfile; extern crate nix_test as nixtest; mod sys; +mod test_dirent; mod test_fcntl; mod test_net; mod test_nix_path; diff --git a/test/test_dirent.rs b/test/test_dirent.rs new file mode 100644 index 0000000000..501b929d8d --- /dev/null +++ b/test/test_dirent.rs @@ -0,0 +1,37 @@ + +mod test_dirent { + use nix::dirent::{self, opendir, readdir, seekdir, telldir, Dir}; + use std::path::Path; + use tempdir::TempDir; + + fn test_readdir(open_fn: OPEN) + where OPEN: Fn(&Path) -> Dir + { + let tempdir = TempDir::new("nix-test_readdir") + .unwrap_or_else(|e| panic!("tempdir failed: {}", e)); + let mut dir = open_fn(tempdir.path()); + let entry1 = readdir(&mut dir).unwrap().unwrap().clone(); + assert_eq!(entry1.d_name[0], '.' as i8); + + let pos = telldir(&mut dir); + seekdir(&mut dir, pos); // no-op + + let entry2 = readdir(&mut dir).unwrap().unwrap().clone(); + assert_eq!(entry2.d_name[0], '.' as i8); + + assert!(readdir(&mut dir).unwrap().is_none()); + } + + #[test] + fn test_opendir() { + test_readdir(|path| opendir(path).unwrap()); + } + + #[cfg(not(any(target_os = "ios", target_os = "macos")))] + #[test] + fn test_fdopendir() { + use std::os::unix::io::IntoRawFd; + use std::fs::File; + test_readdir(|path| dirent::fdopendir(File::open(path).unwrap().into_raw_fd()).unwrap()); + } +}