123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188 |
- //! ::dirent implementation following http://pubs.opengroup.org/onlinepubs/009695399/basedefs/dirent.h.html
- use alloc::boxed::Box;
- use core::{mem, ptr};
- use crate::unix::{
- c_str::CStr,
- c_vec::CVec,
- fs::File,
- header::{errno, fcntl, stdlib, string},
- io::{Seek, SeekFrom},
- platform,
- };
- const DIR_BUF_SIZE: usize = mem::size_of::<::dirent>() * 3;
- // No repr(C) needed, C won't see the content
- pub struct DIR {
- file: File,
- buf: [::c_char; DIR_BUF_SIZE],
- // index and len are specified in bytes
- index: usize,
- len: usize,
- // The last value of d_off, used by telldir
- offset: usize,
- }
- #[no_mangle]
- pub unsafe extern "C" fn opendir(path: *const ::c_char) -> *mut DIR {
- let path = CStr::from_ptr(path);
- let file = match File::open(
- path,
- fcntl::O_RDONLY | fcntl::O_DIRECTORY | fcntl::O_CLOEXEC,
- ) {
- Ok(file) => file,
- Err(_) => return ptr::null_mut(),
- };
- Box::into_raw(Box::new(DIR {
- file,
- buf: [0; DIR_BUF_SIZE],
- index: 0,
- len: 0,
- offset: 0,
- }))
- }
- #[no_mangle]
- pub unsafe extern "C" fn closedir(dir: *mut DIR) -> ::c_int {
- let mut dir = Box::from_raw(dir);
- let ret = platform::pal::close(*dir.file);
- // Reference files aren't closed when dropped
- dir.file.reference = true;
- ret
- }
- #[no_mangle]
- pub unsafe extern "C" fn dirfd(dir: *mut DIR) -> ::c_int {
- *((*dir).file)
- }
- #[no_mangle]
- pub unsafe extern "C" fn readdir(dir: *mut DIR) -> *mut ::dirent {
- if (*dir).index >= (*dir).len {
- let read = platform::pal::getdents(
- *(*dir).file,
- (*dir).buf.as_mut_ptr() as *mut ::dirent,
- (*dir).buf.len(),
- );
- if read <= 0 {
- if read != 0 && read != -errno::ENOENT {
- platform::errno = -read;
- }
- return ptr::null_mut();
- }
- (*dir).index = 0;
- (*dir).len = read as usize;
- }
- let ptr = (*dir).buf.as_mut_ptr().add((*dir).index) as *mut ::dirent;
- (*dir).offset = (*ptr).d_off as usize;
- (*dir).index += (*ptr).d_reclen as usize;
- ptr
- }
- // #[no_mangle]
- pub extern "C" fn readdir_r(
- _dir: *mut DIR,
- _entry: *mut ::dirent,
- _result: *mut *mut ::dirent,
- ) -> *mut ::dirent {
- unimplemented!(); // plus, deprecated
- }
- #[no_mangle]
- pub unsafe extern "C" fn telldir(dir: *mut DIR) -> ::c_long {
- (*dir).offset as ::c_long
- }
- #[no_mangle]
- pub unsafe extern "C" fn seekdir(dir: *mut DIR, off: ::c_long) {
- let _ = (*dir).file.seek(SeekFrom::Start(off as u64));
- (*dir).offset = off as usize;
- (*dir).index = 0;
- (*dir).len = 0;
- }
- #[no_mangle]
- 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 mut vec = match CVec::with_capacity(4) {
- Ok(vec) => vec,
- Err(err) => return -1,
- };
- let old_errno = platform::errno;
- platform::errno = 0;
- loop {
- let entry: *mut ::dirent = readdir(dir);
- if entry.is_null() {
- break;
- }
- if let Some(filter) = filter {
- if filter(entry) == 0 {
- continue;
- }
- }
- let copy = platform::alloc(mem::size_of::<::dirent>()) as *mut ::dirent;
- if copy.is_null() {
- break;
- }
- ptr::write(copy, (*entry).clone());
- if let Err(_) = vec.push(copy) {
- break;
- }
- }
- closedir(dir);
- let len = vec.len();
- if let Err(_) = vec.shrink_to_fit() {
- return -1;
- }
- if platform::errno != 0 {
- for ptr in &mut vec {
- platform::free(*ptr as *mut ::c_void);
- }
- -1
- } else {
- *namelist = vec.leak();
- 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
- }
- }
|