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; ...@@ -4,19 +4,20 @@ use alloc::boxed::Box;
use core::{mem, ptr}; use core::{mem, ptr};
use c_str::CStr; use c_str::CStr;
use header::{errno, fcntl, unistd}; use fs::File;
use platform; use header::{errno, fcntl, stdlib, string};
use io::{Seek, SeekFrom};
use platform::types::*; use platform::types::*;
use platform::{Pal, Sys}; use platform::{Pal, Sys};
use platform;
const DIR_BUF_SIZE: usize = mem::size_of::<dirent>() * 3; const DIR_BUF_SIZE: usize = mem::size_of::<dirent>() * 3;
// No repr(C) needed, C won't see the content // No repr(C) needed, C won't see the content
// TODO: ***THREAD SAFETY***
pub struct DIR { pub struct DIR {
fd: c_int, file: File,
buf: [c_char; DIR_BUF_SIZE], buf: [c_char; DIR_BUF_SIZE],
// index & len are specified in bytes // index and len are specified in bytes
index: usize, index: usize,
len: usize, len: usize,
...@@ -26,6 +27,7 @@ pub struct DIR { ...@@ -26,6 +27,7 @@ pub struct DIR {
} }
#[repr(C)] #[repr(C)]
#[derive(Clone)]
pub struct dirent { pub struct dirent {
pub d_ino: ino_t, pub d_ino: ino_t,
pub d_off: off_t, pub d_off: off_t,
...@@ -37,18 +39,16 @@ pub struct dirent { ...@@ -37,18 +39,16 @@ pub struct dirent {
#[no_mangle] #[no_mangle]
pub extern "C" fn opendir(path: *const c_char) -> *mut DIR { pub extern "C" fn opendir(path: *const c_char) -> *mut DIR {
let path = unsafe { CStr::from_ptr(path) }; let path = unsafe { CStr::from_ptr(path) };
let fd = Sys::open( let file = match File::open(
path, path,
fcntl::O_RDONLY | fcntl::O_DIRECTORY | fcntl::O_CLOEXEC, fcntl::O_RDONLY | fcntl::O_DIRECTORY | fcntl::O_CLOEXEC
0, ) {
); Ok(file) => file,
Err(_) => return ptr::null_mut()
if fd < 0 { };
return ptr::null_mut();
}
Box::into_raw(Box::new(DIR { Box::into_raw(Box::new(DIR {
fd, file,
buf: [0; DIR_BUF_SIZE], buf: [0; DIR_BUF_SIZE],
index: 0, index: 0,
len: 0, len: 0,
...@@ -58,8 +58,13 @@ pub extern "C" fn opendir(path: *const c_char) -> *mut DIR { ...@@ -58,8 +58,13 @@ pub extern "C" fn opendir(path: *const c_char) -> *mut DIR {
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn closedir(dir: *mut DIR) -> c_int { pub unsafe extern "C" fn closedir(dir: *mut DIR) -> c_int {
let ret = Sys::close((*dir).fd); let mut dir = Box::from_raw(dir);
Box::from_raw(dir);
let ret = Sys::close(*dir.file);
// Reference files aren't closed when dropped
dir.file.reference = true;
ret ret
} }
...@@ -67,7 +72,7 @@ pub unsafe extern "C" fn closedir(dir: *mut DIR) -> c_int { ...@@ -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 { pub unsafe extern "C" fn readdir(dir: *mut DIR) -> *mut dirent {
if (*dir).index >= (*dir).len { if (*dir).index >= (*dir).len {
let read = Sys::getdents( let read = Sys::getdents(
(*dir).fd, *(*dir).file,
(*dir).buf.as_mut_ptr() as *mut dirent, (*dir).buf.as_mut_ptr() as *mut dirent,
(*dir).buf.len(), (*dir).buf.len(),
); );
...@@ -116,7 +121,7 @@ pub unsafe extern "C" fn telldir(dir: *mut DIR) -> c_long { ...@@ -116,7 +121,7 @@ pub unsafe extern "C" fn telldir(dir: *mut DIR) -> c_long {
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn seekdir(dir: *mut DIR, off: c_long) { 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).offset = off as usize;
(*dir).index = 0; (*dir).index = 0;
(*dir).len = 0; (*dir).len = 0;
...@@ -125,3 +130,72 @@ pub unsafe extern "C" fn seekdir(dir: *mut DIR, off: c_long) { ...@@ -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) { pub unsafe extern "C" fn rewinddir(dir: *mut DIR) {
seekdir(dir, 0) 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=\ ...@@ -4,6 +4,7 @@ EXPECT_BINS=\
arpainet \ arpainet \
assert \ assert \
ctype \ ctype \
dirent/scandir \
error \ error \
fcntl/create \ fcntl/create \
fcntl/fcntl \ fcntl/fcntl \
...@@ -80,7 +81,7 @@ EXPECT_BINS=\ ...@@ -80,7 +81,7 @@ EXPECT_BINS=\
# Binaries that may generate varied output # Binaries that may generate varied output
BINS=\ BINS=\
$(EXPECT_BINS) \ $(EXPECT_BINS) \
dirent \ dirent/main \
pwd \ pwd \
stdlib/alloc \ stdlib/alloc \
stdlib/bsearch \ 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