Skip to content

Commit ff64bdb

Browse files
committed
add support for dirent family
1 parent c086d23 commit ff64bdb

File tree

4 files changed

+97
-0
lines changed

4 files changed

+97
-0
lines changed

src/dirent.rs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
use {Result, Error, Errno, NixPath};
2+
use errno;
3+
use libc::{self, DIR, c_long};
4+
5+
#[cfg(not(any(target_os = "ios", target_os = "macos")))]
6+
use std::os::unix::io::RawFd;
7+
8+
pub struct Dir {
9+
handle: *mut DIR,
10+
}
11+
12+
impl Drop for Dir {
13+
fn drop(&mut self) {
14+
unsafe { libc::closedir(self.handle) };
15+
}
16+
}
17+
18+
pub fn opendir<P: ?Sized + NixPath>(name: &P) -> Result<Dir> {
19+
let dirp = try!(name.with_nix_path(|cstr| unsafe { libc::opendir(cstr.as_ptr()) }));
20+
if dirp.is_null() {
21+
Err(Error::last().into())
22+
} else {
23+
Ok(Dir { handle: dirp })
24+
}
25+
}
26+
27+
#[cfg(not(any(target_os = "ios", target_os = "macos")))]
28+
pub fn fdopendir(fd: RawFd) -> Result<Dir> {
29+
let dirp = unsafe { libc::fdopendir(fd) };
30+
if dirp.is_null() {
31+
Err(Error::last().into())
32+
} else {
33+
Ok(Dir { handle: dirp })
34+
}
35+
}
36+
37+
pub fn readdir<'a>(dir: &'a mut Dir) -> Result<Option<&'a libc::dirent>> {
38+
let dirent = unsafe {
39+
Errno::clear();
40+
libc::readdir(dir.handle)
41+
};
42+
if dirent.is_null() {
43+
match Errno::last() {
44+
errno::UnknownErrno => Ok(None),
45+
_ => Err(Error::last().into()),
46+
}
47+
} else {
48+
Ok(Some(unsafe { &*dirent }))
49+
}
50+
}
51+
52+
pub fn seekdir<'a>(dir: &'a mut Dir, loc: c_long) {
53+
unsafe { libc::seekdir(dir.handle, loc) };
54+
}
55+
56+
pub fn telldir<'a>(dir: &'a mut Dir) -> c_long {
57+
unsafe { libc::telldir(dir.handle) }
58+
}

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ pub mod libc {
3434
pub use libc::{c_int, c_void};
3535
pub use errno::Errno;
3636

37+
pub mod dirent;
3738
pub mod errno;
3839
pub mod features;
3940
pub mod fcntl;

test/test.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ extern crate tempfile;
88
extern crate nix_test as nixtest;
99

1010
mod sys;
11+
mod test_dirent;
1112
mod test_fcntl;
1213
mod test_net;
1314
mod test_nix_path;

test/test_dirent.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
2+
mod test_dirent {
3+
use nix::dirent::{self, opendir, readdir, seekdir, telldir, Dir};
4+
use std::path::Path;
5+
use tempdir::TempDir;
6+
7+
fn test_readdir<OPEN>(open_fn: OPEN)
8+
where OPEN: Fn(&Path) -> Dir
9+
{
10+
let tempdir = TempDir::new("nix-test_readdir")
11+
.unwrap_or_else(|e| panic!("tempdir failed: {}", e));
12+
let mut dir = open_fn(tempdir.path());
13+
let entry1 = readdir(&mut dir).unwrap().unwrap().clone();
14+
assert_eq!(entry1.d_name[0], '.' as i8);
15+
16+
let pos = telldir(&mut dir);
17+
seekdir(&mut dir, pos); // no-op
18+
19+
let entry2 = readdir(&mut dir).unwrap().unwrap().clone();
20+
assert_eq!(entry2.d_name[0], '.' as i8);
21+
22+
assert!(readdir(&mut dir).unwrap().is_none());
23+
}
24+
25+
#[test]
26+
fn test_opendir() {
27+
test_readdir(|path| opendir(path).unwrap());
28+
}
29+
30+
#[cfg(not(any(target_os = "ios", target_os = "macos")))]
31+
#[test]
32+
fn test_fdopendir() {
33+
use std::os::unix::io::IntoRawFd;
34+
use std::fs::File;
35+
test_readdir(|path| dirent::fdopendir(File::open(path).unwrap().into_raw_fd()).unwrap());
36+
}
37+
}

0 commit comments

Comments
 (0)