Skip to content

Commit d22cfb1

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

File tree

5 files changed

+104
-1
lines changed

5 files changed

+104
-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" }
2626
bitflags = "0.7"
2727
cfg-if = "0.1.0"
2828
void = "1.0.2"

src/dirent.rs

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

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)