diff --git a/Cargo.toml b/Cargo.toml index 29c631ece6..e4f42373de 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ preadv_pwritev = [] signalfd = [] [dependencies] -libc = { git = "https://github.com/rust-lang/libc" } +libc = { git = "https://github.com/Mic92/libc", branch = "master" } bitflags = "0.7" cfg-if = "0.1.0" void = "1.0.2" diff --git a/src/dirent.rs b/src/dirent.rs new file mode 100644 index 0000000000..98c97eebf1 --- /dev/null +++ b/src/dirent.rs @@ -0,0 +1,50 @@ +use {Result, Error, Errno, NixPath}; +use libc::{self, DIR}; +use std::os::unix::io::RawFd; +use errno; + +pub struct Dir { + handle: *mut DIR, +} + +impl Drop for Dir { + fn drop(&mut self) { + unsafe { libc::closedir(self.handle) }; + } +} + +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 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 }) + } +} + +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})) + } +} + 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..2d5cc131a2 --- /dev/null +++ b/test/test_dirent.rs @@ -0,0 +1,34 @@ + +mod test_dirent { + use nix::dirent::{opendir, fdopendir, readdir, Dir}; + use tempdir::TempDir; + use std::fs::File; + use std::path::Path; + use std::os::unix::io::IntoRawFd; + + 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..2], ['.' as i8, '\0' as i8]); + + let entry2 = readdir(&mut dir).unwrap().unwrap().clone(); + assert_eq!(entry2.d_name[0..2], ['.' as i8, '.' as i8]); + + assert!(readdir(&mut dir).unwrap().is_none()); + } + + #[test] + fn test_opendir() { + test_readdir(|path| opendir(path).unwrap() ); + } + + #[test] + fn test_fdopendir() { + test_readdir(|path| + fdopendir(File::open(path).unwrap().into_raw_fd()).unwrap() + ); + } + +}