Skip to content

Commit

Permalink
add support for dirent family
Browse files Browse the repository at this point in the history
  • Loading branch information
Mic92 committed Mar 20, 2017
1 parent 5c90289 commit 3ca111b
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 1 deletion.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ preadv_pwritev = []
signalfd = []

[dependencies]
libc = { git = "https://github.com/rust-lang/libc" }
libc = { git = "https://github.com/Mic92/libc" }
bitflags = "0.7"
cfg-if = "0.1.0"
void = "1.0.2"
Expand Down
55 changes: 55 additions & 0 deletions src/dirent.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
use {Result, Error, Errno, NixPath};
use errno;
use libc::{self, DIR, c_long};
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 fdopendir(fd: RawFd) -> Result<Dir> {
let dirp = unsafe { libc::fdopendir(fd) };
if dirp.is_null() {
Err(Error::last().into())
} else {
Ok(Dir { handle: dirp })
}
}

pub fn opendir<P: ?Sized + NixPath>(name: &P) -> Result<Dir> {
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<Option<&'a libc::dirent>> {
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) }
}
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions test/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
37 changes: 37 additions & 0 deletions test/test_dirent.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@

mod test_dirent {
use nix::dirent::{opendir, fdopendir, readdir, seekdir, telldir, Dir};
use std::fs::File;
use std::os::unix::io::IntoRawFd;
use std::path::Path;
use tempdir::TempDir;

fn test_readdir<OPEN>(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 pos = telldir(&mut dir);
seekdir(&mut dir, pos); // no-op

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());
}

}

0 comments on commit 3ca111b

Please sign in to comment.