1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
use std::io;
use std::ptr;
use std::ffi::{CStr, OsStr};
use std::os::unix::io::AsRawFd;
use std::os::unix::ffi::OsStrExt;
use ffi;
use libc;
use {Dir, Entry, SimpleType};
const DOT: [i8; 2] = [b'.' as i8, 0];
const DOTDOT: [i8; 3] = [b'.' as i8, b'.' as i8, 0];
#[derive(Debug)]
pub struct DirIter {
dir: *mut libc::DIR,
}
impl Entry {
pub fn file_name(&self) -> &OsStr {
OsStr::from_bytes(self.name.to_bytes())
}
pub fn simple_type(&self) -> Option<SimpleType> {
self.file_type
}
}
impl DirIter {
unsafe fn next_entry(&mut self) -> io::Result<Option<*const libc::dirent>>
{
*libc::__errno_location() = 0;
let entry = ffi::readdir(self.dir);
if entry == ptr::null() {
if *libc::__errno_location() == 0 {
return Ok(None)
} else {
return Err(io::Error::last_os_error());
}
}
return Ok(Some(entry));
}
}
pub fn open_dir(dir: &Dir, path: &CStr) -> io::Result<DirIter> {
let dir_fd = unsafe {
libc::openat(dir.as_raw_fd(), path.as_ptr(), libc::O_DIRECTORY)
};
if dir_fd < 0 {
Err(io::Error::last_os_error())
} else {
let dir = unsafe { ffi::fdopendir(dir_fd) };
if dir == ptr::null_mut() {
Err(io::Error::last_os_error())
} else {
Ok(DirIter { dir: dir })
}
}
}
impl Iterator for DirIter {
type Item = io::Result<Entry>;
fn next(&mut self) -> Option<Self::Item> {
unsafe {
loop {
match self.next_entry() {
Err(e) => return Some(Err(e)),
Ok(None) => return None,
Ok(Some(e)) if (*e).d_name[..2] == DOT => continue,
Ok(Some(e)) if (*e).d_name[..3] == DOTDOT => continue,
Ok(Some(e)) => {
return Some(Ok(Entry {
name: CStr::from_ptr((&(*e).d_name).as_ptr())
.to_owned(),
file_type: match (*e).d_type {
0 => None,
libc::DT_REG => Some(SimpleType::File),
libc::DT_DIR => Some(SimpleType::Dir),
libc::DT_LNK => Some(SimpleType::Symlink),
_ => Some(SimpleType::Other),
},
}));
}
}
}
}
}
}
impl Drop for DirIter {
fn drop(&mut self) {
unsafe {
libc::closedir(self.dir);
}
}
}