Backwards-compatibly rewrite getdents to use special syscall.

This commit is contained in:
4lDO2
2024-09-08 22:21:24 +02:00
parent 198caa3bc5
commit c0e7af5289
22 changed files with 338 additions and 231 deletions
Generated
+51 -18
View File
@@ -67,9 +67,12 @@ dependencies = [
[[package]]
name = "cc"
version = "1.1.5"
version = "1.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "324c74f2155653c90b04f25b2a47a8a631360cb908f92a772695f430c7e31052"
checksum = "b62ac837cdb5cb22e10a256099b4fc502b1dfe560cb282963a974d7abd80e476"
dependencies = [
"shlex",
]
[[package]]
name = "cfg-if"
@@ -89,9 +92,9 @@ dependencies = [
[[package]]
name = "cpufeatures"
version = "0.2.12"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504"
checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0"
dependencies = [
"libc",
]
@@ -182,9 +185,9 @@ version = "0.1.0"
[[package]]
name = "libc"
version = "0.2.155"
version = "0.2.158"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
[[package]]
name = "libredox"
@@ -261,9 +264,12 @@ version = "0.1.0"
[[package]]
name = "ppv-lite86"
version = "0.2.17"
version = "0.2.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
dependencies = [
"zerocopy",
]
[[package]]
name = "proc-macro2"
@@ -276,9 +282,9 @@ dependencies = [
[[package]]
name = "quote"
version = "1.0.36"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
dependencies = [
"proc-macro2",
]
@@ -384,9 +390,9 @@ dependencies = [
[[package]]
name = "redox_syscall"
version = "0.5.3"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4"
checksum = "0884ad60e090bf1345b93da0a5de8923c93884cd03f40dfcfddd3b4bee661853"
dependencies = [
"bitflags",
]
@@ -491,6 +497,12 @@ dependencies = [
"digest",
]
[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "subtle"
version = "2.6.1"
@@ -499,9 +511,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]]
name = "syn"
version = "2.0.71"
version = "2.0.77"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b146dcf730474b4bcd16c311627b31ede9ab149045db4d6088b3becaea046462"
checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed"
dependencies = [
"proc-macro2",
"quote",
@@ -516,9 +528,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
[[package]]
name = "unicode-ident"
version = "1.0.12"
version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
[[package]]
name = "unicode-width"
@@ -528,9 +540,9 @@ checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d"
[[package]]
name = "version_check"
version = "0.9.4"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]]
name = "winapi"
@@ -553,3 +565,24 @@ name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "zerocopy"
version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
dependencies = [
"byteorder",
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
+1 -1
View File
@@ -59,7 +59,7 @@ features = ["c_api"]
sc = "0.2.3"
[target.'cfg(target_os = "redox")'.dependencies]
redox_syscall = "0.5.3"
redox_syscall = "0.5.4"
redox-rt = { path = "redox-rt" }
redox-path = "0.2"
redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git", default-features = false, features = ["redox_syscall"] }
+14 -6
View File
@@ -62,14 +62,22 @@ BUILTINS_VERSION=0.1.70
all: | headers libs
headers: $(HEADERS_DEPS)
globdefs="$$(cat cbindgen.globdefs.toml)"; \
for header in $(HEADERS_UNPARSED); do \
echo "Header $$header"; \
if test -f "src/header/$$header/cbindgen.toml"; then \
out=`echo "$$header" | sed 's/_/\//g'`; \
out="$(TARGET_HEADERS)/$$out.h"; \
cbindgen --output "$$out" \
--config="src/header/$$header/cbindgen.toml" \
"src/header/$$header/mod.rs"; \
sed -i "s/va_list __valist/.../g" "$$out"; \
out=`echo "$$header" | sed 's/_/\//g'`; \
out="$(TARGET_HEADERS)/$$out.h"; \
header_path="src/header/$$header/cbindgen.toml"; \
if ( grep -F '[defines]' "$$header_path" >/dev/null ); then \
config=$$(cat "$$header_path" | sed "s/\[defines\]/$$globdefs/"); \
else \
config=$$(cat "$$header_path" cbindgen.globdefs.toml); \
fi; \
echo "$$config" \
| tee "/tmp/a$$header.log" \
| cbindgen "src/header/$$header/mod.rs" --config=/dev/stdin --output "$$out"; \
sed -i "s/va_list __valist/.../g" "$$out"; \
fi \
done
+13
View File
@@ -0,0 +1,13 @@
# needs a leading newline
[defines]
"target_os=redox" = "__redox__"
"target_os=linux" = "__linux__"
"target_pointer_width=64" = "__LP64__"
"target_pointer_width=32" = "__LP32__"
"target_arch=x86" = "__i386__"
"target_arch=x86_64" = "__x86_64__"
"target_arch=aarch64" = "__aarch64__"
# XXX: silences a warning
"feature = no_std" = "__relibc__"
+27
View File
@@ -1,3 +1,5 @@
use alloc::boxed::Box;
use crate::{header::errno::STR_ERROR, platform::types::c_int};
/// Positive error codes (EINVAL, not -EINVAL).
@@ -52,3 +54,28 @@ impl<T: From<i8>> ResultExt<T> for Result<T, Errno> {
}
}
}
pub trait ResultExtPtrMut<T> {
fn or_errno_null_mut(self) -> *mut T;
}
impl<T> ResultExtPtrMut<T> for Result<*mut T, Errno> {
fn or_errno_null_mut(self) -> *mut T {
match self {
Self::Ok(ptr) => ptr,
Self::Err(Errno(errno)) => {
crate::platform::ERRNO.set(errno);
core::ptr::null_mut()
}
}
}
}
impl<T> ResultExtPtrMut<T> for Result<Box<T>, Errno> {
fn or_errno_null_mut(self) -> *mut T {
match self {
Self::Ok(ptr) => Box::into_raw(ptr),
Self::Err(Errno(errno)) => {
crate::platform::ERRNO.set(errno);
core::ptr::null_mut()
}
}
}
}
+136 -69
View File
@@ -1,29 +1,114 @@
//! dirent implementation following http://pubs.opengroup.org/onlinepubs/009695399/basedefs/dirent.h.html
use alloc::boxed::Box;
use alloc::{boxed::Box, vec::Vec};
use core::{mem, ptr};
use crate::{
c_str::CStr,
c_vec::CVec,
error::{Errno, ResultExtPtrMut},
fs::File,
header::{errno, fcntl, stdlib, string},
io::{Seek, SeekFrom},
header::{fcntl, stdlib, string},
platform::{self, types::*, Pal, Sys},
};
const DIR_BUF_SIZE: usize = mem::size_of::<dirent>() * 3;
use super::errno::{EINVAL, EIO, ENOMEM};
// No repr(C) needed, C won't see the content
const INITIAL_BUFSIZE: usize = 512;
// No repr(C) needed, as this is a completely opaque struct. Being accessed as a pointer, in C it's
// just defined as `struct DIR`.
pub struct DIR {
file: File,
buf: [c_char; DIR_BUF_SIZE],
// index and len are specified in bytes
index: usize,
len: usize,
buf: Vec<u8>,
buf_offset: usize,
// The last value of d_off, used by telldir
offset: usize,
opaque_offset: u64,
}
impl DIR {
pub fn new(path: CStr) -> Result<Box<Self>, Errno> {
Ok(Box::new(Self {
file: File::open(
path,
fcntl::O_RDONLY | fcntl::O_DIRECTORY | fcntl::O_CLOEXEC,
)?,
buf: Vec::with_capacity(INITIAL_BUFSIZE),
buf_offset: 0,
opaque_offset: 0,
}))
}
fn next_dirent(&mut self) -> Result<*mut dirent, Errno> {
let mut this_dent = self.buf.get(self.buf_offset..).ok_or(Errno(EIO))?;
if this_dent.is_empty() {
let size = loop {
self.buf.resize(self.buf.capacity(), 0_u8);
// TODO: uninitialized memory?
match Sys::getdents(*self.file, &mut self.buf, self.opaque_offset) {
Ok(size) => break size,
Err(Errno(EINVAL)) => {
self.buf
.try_reserve_exact(self.buf.len())
.map_err(|_| Errno(ENOMEM))?;
continue;
}
Err(Errno(other)) => return Err(Errno(other)),
}
};
self.buf.truncate(size);
self.buf_offset = 0;
if size == 0 {
return Ok(core::ptr::null_mut());
}
this_dent = &self.buf;
}
let (this_reclen, this_next_opaque) =
unsafe { Sys::dent_reclen_offset(this_dent, self.buf_offset).ok_or(Errno(EIO))? };
//println!("CDENT {} {}+{}", self.opaque_offset, self.buf_offset, this_reclen);
let next_off = self
.buf_offset
.checked_add(usize::from(this_reclen))
.ok_or(Errno(EIO))?;
if next_off > self.buf.len() {
return Err(Errno(EIO));
}
if this_dent.len() < usize::from(this_reclen) {
// Don't want memory corruption if a scheme is adversarial.
return Err(Errno(EIO));
}
let dent_ptr = this_dent.as_ptr() as *mut dirent;
self.opaque_offset = this_next_opaque;
self.buf_offset = next_off;
Ok(dent_ptr)
}
fn seek(&mut self, off: u64) {
let Ok(_) = Sys::dir_seek(*self.file, off) else {
return;
};
self.buf.clear();
self.buf_offset = 0;
self.opaque_offset = off;
}
fn rewind(&mut self) {
self.opaque_offset = 0;
let Ok(_) = Sys::dir_seek(*self.file, 0) else {
return;
};
self.buf.clear();
self.buf_offset = 0;
self.opaque_offset = 0;
}
fn close(mut self) -> c_int {
// Reference files aren't closed when dropped
self.file.reference = true;
// TODO: result
Sys::close(*self.file)
}
}
#[repr(C)]
@@ -36,68 +121,50 @@ pub struct dirent {
pub d_name: [c_char; 256],
}
#[cfg(target_os = "redox")]
const _: () = {
use core::mem::{offset_of, size_of};
use syscall::dirent::DirentHeader;
if offset_of!(dirent, d_ino) != offset_of!(DirentHeader, inode) {
panic!("struct dirent layout mismatch (inode)");
}
if offset_of!(dirent, d_off) != offset_of!(DirentHeader, next_opaque_id) {
panic!("struct dirent layout mismatch (inode)");
}
if offset_of!(dirent, d_reclen) != offset_of!(DirentHeader, record_len) {
panic!("struct dirent layout mismatch (len)");
}
if offset_of!(dirent, d_type) != offset_of!(DirentHeader, kind) {
panic!("struct dirent layout mismatch (kind)");
}
if offset_of!(dirent, d_name) != size_of::<DirentHeader>() {
panic!("struct dirent layout mismatch (name)");
}
};
#[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,
}))
DIR::new(path).or_errno_null_mut()
}
#[no_mangle]
pub unsafe extern "C" fn closedir(dir: *mut DIR) -> c_int {
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
pub extern "C" fn closedir(dir: Box<DIR>) -> c_int {
dir.close()
}
#[no_mangle]
pub unsafe extern "C" fn dirfd(dir: *mut DIR) -> c_int {
*((*dir).file)
pub 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 = Sys::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.set(-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
pub extern "C" fn readdir(dir: &mut DIR) -> *mut dirent {
dir.next_dirent().or_errno_null_mut()
}
// #[no_mangle]
pub extern "C" fn readdir_r(
_dir: *mut DIR,
@@ -108,19 +175,19 @@ pub extern "C" fn readdir_r(
}
#[no_mangle]
pub unsafe extern "C" fn telldir(dir: *mut DIR) -> c_long {
(*dir).offset as c_long
pub extern "C" fn telldir(dir: &mut DIR) -> c_long {
dir.opaque_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;
pub extern "C" fn seekdir(dir: &mut DIR, off: c_long) {
dir.seek(
off.try_into()
.expect("off must come from telldir, thus never negative"),
);
}
#[no_mangle]
pub unsafe extern "C" fn rewinddir(dir: *mut DIR) {
seekdir(dir, 0)
pub extern "C" fn rewinddir(dir: &mut DIR) {
dir.rewind();
}
#[no_mangle]
@@ -149,7 +216,7 @@ pub unsafe extern "C" fn scandir(
platform::ERRNO.set(0);
loop {
let entry: *mut dirent = readdir(dir);
let entry: *mut dirent = readdir(&mut *dir);
if entry.is_null() {
break;
}
@@ -170,7 +237,7 @@ pub unsafe extern "C" fn scandir(
}
}
closedir(dir);
closedir(Box::from_raw(dir));
let len = vec.len();
if let Err(_) = vec.shrink_to_fit() {
-4
View File
@@ -6,9 +6,5 @@ style = "Tag"
no_includes = true
cpp_compat = true
[defines]
"target_os=linux" = "__linux__"
"target_os=redox" = "__redox__"
[enum]
prefix_with_name = true
-4
View File
@@ -6,10 +6,6 @@ style = "Tag"
no_includes = true
cpp_compat = true
[defines]
"target_os=linux" = "__linux__"
"target_os=redox" = "__redox__"
[enum]
prefix_with_name = true
-3
View File
@@ -6,9 +6,6 @@ style = "Type"
no_includes = true
cpp_compat = true
[defines]
"target_pointer_width=64" = "__LP64__"
[enum]
prefix_with_name = true
-5
View File
@@ -5,10 +5,5 @@ style = "Tag"
no_includes = true
cpp_compat = true
[defines]
"target_os=linux" = "__linux__"
"target_os=redox" = "__redox__"
"target_pointer_width=64" = "__LP64__"
[enum]
prefix_with_name = true
-4
View File
@@ -4,10 +4,6 @@ style = "Tag"
no_includes = true
cpp_compat = true
[defines]
"target_os=linux" = "__linux__"
"target_os=redox" = "__redox__"
[enum]
prefix_with_name = true
-4
View File
@@ -6,9 +6,5 @@ style = "Tag"
no_includes = true
cpp_compat = true
[defines]
"target_os=linux" = "__linux__"
"target_os=redox" = "__redox__"
[enum]
prefix_with_name = true
-4
View File
@@ -6,10 +6,6 @@ style = "Tag"
no_includes = true
cpp_compat = true
[defines]
"target_os=linux" = "__linux__"
"target_os=redox" = "__redox__"
[enum]
prefix_with_name = true
-4
View File
@@ -6,10 +6,6 @@ style = "Tag"
no_includes = true
cpp_compat = true
[defines]
"target_os=linux" = "__linux__"
"target_os=redox" = "__redox__"
[enum]
prefix_with_name = true
-4
View File
@@ -5,10 +5,6 @@ style = "Tag"
no_includes = true
cpp_compat = true
[defines]
"target_os=linux" = "__linux__"
"target_os=redox" = "__redox__"
[enum]
prefix_with_name = true
-4
View File
@@ -7,7 +7,3 @@ cpp_compat = true
[enum]
prefix_with_name = true
[defines]
"target_os = linux" = "__linux__"
"target_os = redox" = "__redox__"
-4
View File
@@ -8,7 +8,3 @@ cpp_compat = true
[enum]
prefix_with_name = true
[defines]
"target_os = linux" = "__linux__"
"target_os = redox" = "__redox__"
+1
View File
@@ -12,6 +12,7 @@
#![feature(maybe_uninit_slice)]
#![feature(maybe_uninit_uninit_array)]
#![feature(lang_items)]
#![feature(let_chains)]
#![feature(linkage)]
#![feature(stmt_expr_attributes)]
#![feature(str_internals)]
+12 -3
View File
@@ -1,5 +1,5 @@
use crate::io::Write;
use core::{arch::asm, ptr};
use core::{arch::asm, mem::offset_of, ptr};
use super::{types::*, Pal, ERRNO};
use crate::{
@@ -12,6 +12,7 @@ use crate::header::{
sys_stat::stat,
sys_statvfs::statvfs,
sys_time::{timeval, timezone},
unistd::SEEK_SET,
};
// use header::sys_times::tms;
use crate::{
@@ -281,8 +282,16 @@ impl Pal for Sys {
}
}
fn getdents(fd: c_int, dirents: *mut dirent, bytes: usize) -> c_int {
unsafe { syscall!(GETDENTS64, fd, dirents, bytes) as c_int }
fn getdents(fd: c_int, buf: &mut [u8], _off: u64) -> Result<usize, Errno> {
e_raw(unsafe { syscall!(GETDENTS64, fd, buf.as_mut_ptr(), buf.len()) })
}
fn dir_seek(fd: c_int, off: u64) -> Result<(), Errno> {
e_raw(unsafe { syscall!(LSEEK, fd, off, SEEK_SET) })?;
Ok(())
}
unsafe fn dent_reclen_offset(this_dent: &[u8], offset: usize) -> Option<(u16, u64)> {
let dent = this_dent.as_ptr().cast::<dirent>();
Some(((*dent).d_reclen, (*dent).d_off as u64))
}
fn getegid() -> gid_t {
+7 -1
View File
@@ -93,7 +93,13 @@ pub trait Pal {
fn getcwd(buf: *mut c_char, size: size_t) -> *mut c_char;
fn getdents(fd: c_int, dirents: *mut dirent, bytes: usize) -> c_int;
fn getdents(fd: c_int, buf: &mut [u8], opaque_offset: u64) -> Result<usize, Errno>;
fn dir_seek(fd: c_int, opaque_offset: u64) -> Result<(), Errno>;
// SAFETY: This_dent must satisfy platform-specific size and alignment constraints. On Linux,
// this means the buffer came from a valid getdents64 invocation, whereas on Redox, every
// possible this_dent slice is safe (and will be validated).
unsafe fn dent_reclen_offset(this_dent: &[u8], offset: usize) -> Option<(u16, u64)>;
fn getegid() -> gid_t;
+74 -89
View File
@@ -1,8 +1,13 @@
use core::{convert::TryFrom, mem, ptr, slice, str};
use core::{
convert::TryFrom,
mem::{self, size_of},
ptr, slice, str,
};
use redox_rt::RtTcb;
use syscall::{
self,
data::{Map, Stat as redox_stat, StatVfs as redox_statvfs, TimeSpec as redox_timespec},
dirent::{DirentHeader, DirentKind},
Error, PtraceEvent, Result, EMFILE,
};
@@ -12,7 +17,10 @@ use crate::{
fs::File,
header::{
dirent::dirent,
errno::{EBADF, EBADFD, EBADR, EINVAL, EIO, ENOENT, ENOMEM, ENOSYS, EPERM, ERANGE},
errno::{
EBADF, EBADFD, EBADR, EINVAL, EIO, ENAMETOOLONG, ENOENT, ENOMEM, ENOSYS, EOPNOTSUPP,
EPERM, ERANGE,
},
fcntl, limits,
sys_mman::{MAP_ANONYMOUS, MAP_FAILED, PROT_READ, PROT_WRITE},
sys_random,
@@ -353,97 +361,74 @@ impl Pal for Sys {
buf
}
fn getdents(fd: c_int, mut dirents: *mut dirent, max_bytes: usize) -> c_int {
//TODO: rewrite this code. Originally the *dirents = dirent { ... } stuff below caused
// massive issues. This has been hacked around, but it still isn't perfect
fn getdents(fd: c_int, buf: &mut [u8], opaque: u64) -> Result<usize, Errno> {
//println!("GETDENTS {} into ({:p}+{})", fd, buf.as_ptr(), buf.len());
// Get initial reading position
let mut read = match syscall::lseek(fd as usize, 0, syscall::SEEK_CUR) {
Ok(pos) => pos as isize,
Err(err) => return -err.errno,
};
const HEADER_SIZE: usize = size_of::<DirentHeader>();
let mut written = 0;
let mut buf = [0; 1024];
let mut name = [0; 256];
let mut i = 0;
let mut flush = |written: &mut usize, i: &mut usize, name: &mut [c_char; 256]| {
if *i < name.len() {
// Set NUL byte
name[*i] = 0;
}
// Get size: full size - unused bytes
if *written + mem::size_of::<dirent>() > max_bytes {
// Seek back to after last read entry and return
match syscall::lseek(fd as usize, read, syscall::SEEK_SET) {
Ok(_) => return Some(*written as c_int),
Err(err) => return Some(-err.errno),
}
}
let size = mem::size_of::<dirent>() - name.len().saturating_sub(*i + 1);
unsafe {
//This is the offending code mentioned above
*dirents = dirent {
d_ino: 0,
d_off: read as off_t,
d_reclen: size as c_ushort,
d_type: 0,
d_name: *name,
};
dirents = (dirents as *mut u8).offset(size as isize) as *mut dirent;
}
read += *i as isize + /* newline */ 1;
*written += size;
*i = 0;
None
};
loop {
// Read a chunk from the directory
let len = match syscall::read(fd as usize, &mut buf) {
Ok(0) => {
if i > 0 {
if let Some(value) = flush(&mut written, &mut i, &mut name) {
return value;
}
}
return written as c_int;
}
Ok(n) => n,
Err(err) => return -err.errno,
};
// Handle everything
let mut start = 0;
while start < len {
let buf = &buf[start..len];
// Copy everything up until a newline
let newline = buf.iter().position(|&c| c == b'\n');
let pre_len = newline.unwrap_or(buf.len());
let post_len = newline.map(|i| i + 1).unwrap_or(buf.len());
if i < pre_len {
// Reserve space for NUL byte
let name_len = name.len() - 1;
let name = &mut name[i..name_len];
let copy = pre_len.min(name.len());
let buf = unsafe { slice::from_raw_parts(buf.as_ptr() as *const c_char, copy) };
name[..copy].copy_from_slice(buf);
}
i += pre_len;
start += post_len;
// Write the directory entry
if newline.is_some() {
if let Some(value) = flush(&mut written, &mut i, &mut name) {
return value;
}
}
// Use syscall if it exists.
match unsafe {
syscall::syscall5(
syscall::SYS_GETDENTS,
fd as usize,
buf.as_mut_ptr() as usize,
buf.len(),
HEADER_SIZE,
opaque as usize,
)
} {
Err(Error {
errno: EOPNOTSUPP | ENOSYS,
}) => (),
other => {
//println!("REAL GETDENTS {:?}", other);
return Ok(other?);
}
}
// Otherwise, for legacy schemes, assume the buffer is pre-arranged (all schemes do this in
// practice), and just read the name. If multiple names appear, pretend it didn't happen
// and just use the first entry.
let (header, name) = buf.split_at_mut(size_of::<DirentHeader>());
let bytes_read = Sys::pread(fd, name, opaque as i64)? as usize;
if bytes_read == 0 {
return Ok(0);
}
let (name_len, advance) = match name[..bytes_read].iter().position(|c| *c == b'\n') {
Some(idx) => (idx, idx + 1),
// Insufficient space for NUL byte, or entire entry was not read. Indicate we need a
// larger buffer.
None if bytes_read == name.len() => return Err(Errno(EINVAL)),
None => (bytes_read, name.len()),
};
name[name_len] = b'\0';
let record_len = u16::try_from(size_of::<DirentHeader>() + name_len + 1)
.map_err(|_| Error::new(ENAMETOOLONG))?;
header.copy_from_slice(&DirentHeader {
inode: 0,
next_opaque_id: opaque + advance as u64,
record_len,
kind: DirentKind::Unspecified as u8,
});
//println!("EMULATED GETDENTS");
Ok(record_len.into())
}
fn dir_seek(_fd: c_int, _off: u64) -> Result<(), Errno> {
// Redox getdents takes an explicit (opaque) offset, so this is a no-op.
Ok(())
}
// NOTE: fn is unsafe, but this just means we can assume more things. impl is safe
unsafe fn dent_reclen_offset(this_dent: &[u8], offset: usize) -> Option<(u16, u64)> {
let mut header = DirentHeader::default();
header.copy_from_slice(&this_dent.get(..size_of::<DirentHeader>())?);
Some((header.record_len, header.next_opaque_id))
}
fn getegid() -> gid_t {
+2
View File
@@ -1,3 +1,4 @@
#include <assert.h>
#include <dirent.h>
#include <errno.h>
#include <stdio.h>
@@ -26,6 +27,7 @@ int main(void) {
puts("--- Testing rewind ---");
rewinddir(dir);
entry = readdir(dir);
assert(entry != NULL);
puts(entry->d_name);
// puts("--- Testing seek ---");