|
@@ -4,19 +4,20 @@ use alloc::boxed::Box;
|
|
|
use core::{mem, ptr};
|
|
|
|
|
|
use c_str::CStr;
|
|
|
-use header::{errno, fcntl, unistd};
|
|
|
-use platform;
|
|
|
+use fs::File;
|
|
|
+use header::{errno, fcntl, stdlib, string};
|
|
|
+use io::{Seek, SeekFrom};
|
|
|
use platform::types::*;
|
|
|
use platform::{Pal, Sys};
|
|
|
+use platform;
|
|
|
|
|
|
const DIR_BUF_SIZE: usize = mem::size_of::<dirent>() * 3;
|
|
|
|
|
|
// No repr(C) needed, C won't see the content
|
|
|
-// TODO: ***THREAD SAFETY***
|
|
|
pub struct DIR {
|
|
|
- fd: c_int,
|
|
|
+ file: File,
|
|
|
buf: [c_char; DIR_BUF_SIZE],
|
|
|
- // index & len are specified in bytes
|
|
|
+ // index and len are specified in bytes
|
|
|
index: usize,
|
|
|
len: usize,
|
|
|
|
|
@@ -26,6 +27,7 @@ pub struct DIR {
|
|
|
}
|
|
|
|
|
|
#[repr(C)]
|
|
|
+#[derive(Clone)]
|
|
|
pub struct dirent {
|
|
|
pub d_ino: ino_t,
|
|
|
pub d_off: off_t,
|
|
@@ -37,18 +39,16 @@ pub struct dirent {
|
|
|
#[no_mangle]
|
|
|
pub extern "C" fn opendir(path: *const c_char) -> *mut DIR {
|
|
|
let path = unsafe { CStr::from_ptr(path) };
|
|
|
- let fd = Sys::open(
|
|
|
+ let file = match File::open(
|
|
|
path,
|
|
|
- fcntl::O_RDONLY | fcntl::O_DIRECTORY | fcntl::O_CLOEXEC,
|
|
|
- 0,
|
|
|
- );
|
|
|
-
|
|
|
- if fd < 0 {
|
|
|
- return ptr::null_mut();
|
|
|
- }
|
|
|
+ fcntl::O_RDONLY | fcntl::O_DIRECTORY | fcntl::O_CLOEXEC
|
|
|
+ ) {
|
|
|
+ Ok(file) => file,
|
|
|
+ Err(_) => return ptr::null_mut()
|
|
|
+ };
|
|
|
|
|
|
Box::into_raw(Box::new(DIR {
|
|
|
- fd,
|
|
|
+ file,
|
|
|
buf: [0; DIR_BUF_SIZE],
|
|
|
index: 0,
|
|
|
len: 0,
|
|
@@ -58,8 +58,13 @@ pub extern "C" fn opendir(path: *const c_char) -> *mut DIR {
|
|
|
|
|
|
#[no_mangle]
|
|
|
pub unsafe extern "C" fn closedir(dir: *mut DIR) -> c_int {
|
|
|
- let ret = Sys::close((*dir).fd);
|
|
|
- Box::from_raw(dir);
|
|
|
+ let mut dir = Box::from_raw(dir);
|
|
|
+
|
|
|
+ let ret = Sys::close(*dir.file);
|
|
|
+
|
|
|
+ // Reference files aren't closed when dropped
|
|
|
+ dir.file.reference = true;
|
|
|
+
|
|
|
ret
|
|
|
}
|
|
|
|
|
@@ -67,7 +72,7 @@ pub unsafe extern "C" fn closedir(dir: *mut DIR) -> c_int {
|
|
|
pub unsafe extern "C" fn readdir(dir: *mut DIR) -> *mut dirent {
|
|
|
if (*dir).index >= (*dir).len {
|
|
|
let read = Sys::getdents(
|
|
|
- (*dir).fd,
|
|
|
+ *(*dir).file,
|
|
|
(*dir).buf.as_mut_ptr() as *mut dirent,
|
|
|
(*dir).buf.len(),
|
|
|
);
|
|
@@ -116,7 +121,7 @@ pub unsafe extern "C" fn telldir(dir: *mut DIR) -> c_long {
|
|
|
}
|
|
|
#[no_mangle]
|
|
|
pub unsafe extern "C" fn seekdir(dir: *mut DIR, off: c_long) {
|
|
|
- unistd::lseek((*dir).fd, off, unistd::SEEK_SET);
|
|
|
+ let _ = (*dir).file.seek(SeekFrom::Start(off as u64));
|
|
|
(*dir).offset = off as usize;
|
|
|
(*dir).index = 0;
|
|
|
(*dir).len = 0;
|
|
@@ -125,3 +130,72 @@ pub unsafe extern "C" fn seekdir(dir: *mut DIR, off: c_long) {
|
|
|
pub unsafe extern "C" fn rewinddir(dir: *mut DIR) {
|
|
|
seekdir(dir, 0)
|
|
|
}
|
|
|
+
|
|
|
+#[no_mangle]
|
|
|
+pub unsafe extern "C" fn alphasort(
|
|
|
+ first: *mut *const dirent,
|
|
|
+ second: *mut *const dirent
|
|
|
+) -> c_int {
|
|
|
+ string::strcoll((**first).d_name.as_ptr(), (**second).d_name.as_ptr())
|
|
|
+}
|
|
|
+
|
|
|
+#[no_mangle]
|
|
|
+pub unsafe extern "C" fn scandir(
|
|
|
+ dirp: *const c_char,
|
|
|
+ namelist: *mut *mut *mut dirent,
|
|
|
+ filter: Option<extern "C" fn(_: *const dirent) -> c_int>,
|
|
|
+ compare: Option<extern "C" fn(_: *mut *const dirent, _: *mut *const dirent) -> c_int>
|
|
|
+) -> c_int {
|
|
|
+ let dir = opendir(dirp);
|
|
|
+ if dir.is_null() {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ let old_errno = platform::errno;
|
|
|
+
|
|
|
+ let mut len: isize = 0;
|
|
|
+ let mut cap: isize = 4;
|
|
|
+ *namelist = platform::alloc(cap as usize * mem::size_of::<*mut dirent>()) as *mut *mut dirent;
|
|
|
+
|
|
|
+ loop {
|
|
|
+ platform::errno = 0;
|
|
|
+ let entry = readdir(dir);
|
|
|
+ if entry.is_null() {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if let Some(filter) = filter {
|
|
|
+ if filter(entry) == 0 {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if len >= cap {
|
|
|
+ cap *= 2;
|
|
|
+ *namelist = platform::realloc(
|
|
|
+ *namelist as *mut c_void,
|
|
|
+ cap as usize * mem::size_of::<*mut dirent>()
|
|
|
+ ) as *mut *mut dirent;
|
|
|
+ }
|
|
|
+
|
|
|
+ let copy = platform::alloc(mem::size_of::<dirent>()) as *mut dirent;
|
|
|
+ *copy = (*entry).clone();
|
|
|
+ *(*namelist).offset(len) = copy;
|
|
|
+ len += 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ closedir(dir);
|
|
|
+
|
|
|
+ if platform::errno != 0 {
|
|
|
+ while len > 0 {
|
|
|
+ len -= 1;
|
|
|
+ platform::free(*(*namelist).offset(len) as *mut c_void);
|
|
|
+ }
|
|
|
+ platform::free(*namelist as *mut c_void);
|
|
|
+ -1
|
|
|
+ } else {
|
|
|
+ platform::errno = old_errno;
|
|
|
+ stdlib::qsort(*namelist as *mut c_void, len as size_t, mem::size_of::<*mut dirent>(), mem::transmute(compare));
|
|
|
+ len as c_int
|
|
|
+ }
|
|
|
+}
|