Skip to content
Snippets Groups Projects
Verified Commit 758f6815 authored by jD91mZM2's avatar jD91mZM2
Browse files

Implement scandir

parent 3c8cb95b
No related branches found
No related tags found
No related merge requests found
Pipeline #1448 failed
......@@ -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 \
......
File moved
#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
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment