Implement scandir
This commit is contained in:
+92
-18
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -4,6 +4,7 @@ EXPECT_BINS=\
|
||||
arpainet \
|
||||
assert \
|
||||
ctype \
|
||||
dirent/scandir \
|
||||
error \
|
||||
fcntl/create \
|
||||
fcntl/fcntl \
|
||||
@@ -80,7 +81,7 @@ EXPECT_BINS=\
|
||||
# Binaries that may generate varied output
|
||||
BINS=\
|
||||
$(EXPECT_BINS) \
|
||||
dirent \
|
||||
dirent/main \
|
||||
pwd \
|
||||
stdlib/alloc \
|
||||
stdlib/bsearch \
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
#include <dirent.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
int filter(const struct dirent* dirent) {
|
||||
return strstr(dirent->d_name, "3") == NULL;
|
||||
}
|
||||
|
||||
int main() {
|
||||
struct dirent** array;
|
||||
int len = scandir("example_dir/", &array, filter, alphasort);
|
||||
if (len < 0) {
|
||||
perror("scandir");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for(int i = 0; i < len; i += 1) {
|
||||
puts(array[i]->d_name);
|
||||
free(array[i]);
|
||||
}
|
||||
free(array);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
.
|
||||
..
|
||||
1-never-gonna-give-you-up
|
||||
2-never-gonna-let-you-down
|
||||
4-and-desert-you
|
||||
5-never-gonna-make-you-cry
|
||||
6-never-gonna-say-goodbye
|
||||
7-never-gonna-tell-a-lie
|
||||
8-and-hurt-you
|
||||
Reference in New Issue
Block a user