Verified Commit 758f6815 authored by jD91mZM2's avatar jD91mZM2
Browse files

Implement scandir

parent 3c8cb95b
Pipeline #1448 failed with stages
in 9 minutes and 44 seconds
......@@ -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
}
}
......@@ -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 \
......
#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);
}
.
..
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
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment