Skip to content

Commit 81ffa22

Browse files
committed
add support for dirent family
1 parent 5c90289 commit 81ffa22

File tree

4 files changed

+94
-0
lines changed

4 files changed

+94
-0
lines changed

src/dirent.rs

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

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

0 commit comments

Comments
 (0)