Skip to content

Commit 1eb7cb7

Browse files
committed
add support for opendir/fdopendir
1 parent 5c90289 commit 1eb7cb7

File tree

5 files changed

+87
-1
lines changed

5 files changed

+87
-1
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ preadv_pwritev = []
2222
signalfd = []
2323

2424
[dependencies]
25-
libc = { git = "https://github.com/rust-lang/libc" }
25+
libc = { git = "https://github.com/Mic92/libc", branch = "master" }
2626
bitflags = "0.7"
2727
cfg-if = "0.1.0"
2828
void = "1.0.2"

src/dirent.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
use {Result, Error, Errno, NixPath};
2+
use libc::{self, DIR};
3+
use std::os::unix::io::RawFd;
4+
use errno;
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| {
27+
unsafe { libc::opendir(cstr.as_ptr()) }
28+
}));
29+
if dirp.is_null() {
30+
Err(Error::last().into())
31+
} else {
32+
Ok(Dir { handle: dirp })
33+
}
34+
}
35+
36+
pub fn readdir<'a>(dir: &'a mut Dir) -> Result<Option<&'a libc::dirent>> {
37+
let dirent = unsafe {
38+
Errno::clear();
39+
libc::readdir(dir.handle)
40+
};
41+
if dirent.is_null() {
42+
match Errno::last() {
43+
errno::UnknownErrno => Ok(None),
44+
_ => Err(Error::last().into()),
45+
}
46+
} else {
47+
Ok(Some(unsafe{&*dirent}))
48+
}
49+
}
50+

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: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
2+
mod test_dirent {
3+
use nix::dirent::{opendir, fdopendir, readdir, Dir};
4+
use tempdir::TempDir;
5+
use std::fs::File;
6+
use std::path::Path;
7+
use std::os::unix::io::IntoRawFd;
8+
9+
fn test_readdir<OPEN>(open_fn: OPEN) where OPEN: Fn(&Path) -> Dir {
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..2], ['.' as i8, '\0' as i8]);
15+
16+
let entry2 = readdir(&mut dir).unwrap().unwrap().clone();
17+
assert_eq!(entry2.d_name[0..2], ['.' as i8, '.' as i8]);
18+
19+
assert!(readdir(&mut dir).unwrap().is_none());
20+
}
21+
22+
#[test]
23+
fn test_opendir() {
24+
test_readdir(|path| opendir(path).unwrap() );
25+
}
26+
27+
#[test]
28+
fn test_fdopendir() {
29+
test_readdir(|path|
30+
fdopendir(File::open(path).unwrap().into_raw_fd()).unwrap()
31+
);
32+
}
33+
34+
}

0 commit comments

Comments
 (0)