use core::mem::{offset_of, transmute};
use core::ptr::null_mut;
use errno::{set_errno, Errno};
use libc::{c_int, c_void};
use super::CScapeDir;
#[no_mangle]
unsafe extern "C" fn readdir64_r(
dir: *mut c_void,
entry: *mut libc::dirent64,
ptr: *mut *mut libc::dirent64,
) -> c_int {
libc!(libc::readdir64_r(dir.cast(), entry, ptr));
let c_scape_dir = dir.cast::<CScapeDir>();
let dir = &mut (*c_scape_dir).dir;
match dir.read() {
None => {
*ptr = null_mut();
0
}
Some(Ok(e)) => {
let file_type = match e.file_type() {
rustix::fs::FileType::RegularFile => libc::DT_REG,
rustix::fs::FileType::Directory => libc::DT_DIR,
rustix::fs::FileType::Symlink => libc::DT_LNK,
rustix::fs::FileType::Fifo => libc::DT_FIFO,
rustix::fs::FileType::Socket => libc::DT_SOCK,
rustix::fs::FileType::CharacterDevice => libc::DT_CHR,
rustix::fs::FileType::BlockDevice => libc::DT_BLK,
rustix::fs::FileType::Unknown => libc::DT_UNKNOWN,
};
*entry = libc::dirent64 {
d_ino: e.ino(),
d_off: 0, d_reclen: (offset_of!(libc::dirent64, d_name) + e.file_name().to_bytes().len() + 1)
.try_into()
.unwrap(),
d_type: file_type,
d_name: [0; 256],
};
let len = core::cmp::min(256, e.file_name().to_bytes().len());
(&mut *entry).d_name[..len].copy_from_slice(transmute(e.file_name().to_bytes()));
*ptr = entry;
0
}
Some(Err(err)) => err.raw_os_error(),
}
}
#[no_mangle]
unsafe extern "C" fn readdir64(dir: *mut libc::DIR) -> *mut libc::dirent64 {
libc!(libc::readdir64(dir.cast()));
let c_scape_dir = dir.cast::<CScapeDir>();
let dir = &mut (*c_scape_dir).dir;
match dir.read() {
None => null_mut(),
Some(Ok(e)) => {
let file_type = match e.file_type() {
rustix::fs::FileType::RegularFile => libc::DT_REG,
rustix::fs::FileType::Directory => libc::DT_DIR,
rustix::fs::FileType::Symlink => libc::DT_LNK,
rustix::fs::FileType::Fifo => libc::DT_FIFO,
rustix::fs::FileType::Socket => libc::DT_SOCK,
rustix::fs::FileType::CharacterDevice => libc::DT_CHR,
rustix::fs::FileType::BlockDevice => libc::DT_BLK,
rustix::fs::FileType::Unknown => libc::DT_UNKNOWN,
};
(*c_scape_dir).storage.dirent64 = libc::dirent64 {
d_ino: e.ino(),
d_off: 0, d_reclen: (offset_of!(libc::dirent64, d_name) + e.file_name().to_bytes().len() + 1)
.try_into()
.unwrap(),
d_type: file_type,
d_name: [0; 256],
};
let len = core::cmp::min(256, e.file_name().to_bytes().len());
(&mut *c_scape_dir).storage.dirent64.d_name[..len]
.copy_from_slice(transmute(e.file_name().to_bytes()));
&mut (*c_scape_dir).storage.dirent64
}
Some(Err(err)) => {
set_errno(Errno(err.raw_os_error()));
null_mut()
}
}
}
#[no_mangle]
unsafe extern "C" fn readdir(dir: *mut libc::DIR) -> *mut libc::dirent {
libc!(libc::readdir(dir.cast()));
let c_scape_dir = dir.cast::<CScapeDir>();
let dir = &mut (*c_scape_dir).dir;
match dir.read() {
None => null_mut(),
Some(Ok(e)) => {
let file_type = match e.file_type() {
rustix::fs::FileType::RegularFile => libc::DT_REG,
rustix::fs::FileType::Directory => libc::DT_DIR,
rustix::fs::FileType::Symlink => libc::DT_LNK,
rustix::fs::FileType::Fifo => libc::DT_FIFO,
rustix::fs::FileType::Socket => libc::DT_SOCK,
rustix::fs::FileType::CharacterDevice => libc::DT_CHR,
rustix::fs::FileType::BlockDevice => libc::DT_BLK,
rustix::fs::FileType::Unknown => libc::DT_UNKNOWN,
};
(*c_scape_dir).storage.dirent = libc::dirent {
d_ino: match e.ino().try_into() {
Ok(ino) => ino,
Err(_) => {
set_errno(Errno(libc::EOVERFLOW));
return null_mut();
}
},
d_off: 0, d_reclen: (offset_of!(libc::dirent64, d_name) + e.file_name().to_bytes().len() + 1)
.try_into()
.unwrap(),
d_type: file_type,
d_name: [0; 256],
};
let len = core::cmp::min(256, e.file_name().to_bytes().len());
(&mut *c_scape_dir).storage.dirent.d_name[..len]
.copy_from_slice(transmute(e.file_name().to_bytes()));
&mut (*c_scape_dir).storage.dirent
}
Some(Err(err)) => {
set_errno(Errno(err.raw_os_error()));
null_mut()
}
}
}
#[cfg(feature = "todo")]
#[no_mangle]
unsafe extern "C" fn rewinddir(dir: *mut libc::DIR) {
libc!(libc::rewinddir(dir));
let c_scape_dir = dir.cast::<CScapeDir>();
(*c_scape_dir).dir.rewind();
}
#[cfg(feature = "todo")]
#[no_mangle]
unsafe extern "C" fn scandir() {
todo!("scandir")
}
#[cfg(feature = "todo")]
#[no_mangle]
unsafe extern "C" fn seekdir() {
todo!("seekdir")
}
#[cfg(feature = "todo")]
#[no_mangle]
unsafe extern "C" fn telldir() {
todo!("telldir")
}