Implement posix_getdents

This commit is contained in:
Wildan Mubarok
2025-09-23 16:57:13 +00:00
committed by Jeremy Soller
parent dc7491387b
commit 7416ba6ff3
6 changed files with 118 additions and 8 deletions
+12 -4
View File
@@ -4,8 +4,12 @@
#![deny(unsafe_op_in_unsafe_fn)]
use crate::{
header::unistd::{SEEK_CUR, SEEK_SET},
platform::types::{c_int, c_void, off_t, size_t, ssize_t},
};
use alloc::{boxed::Box, vec::Vec};
use core::{mem, ptr};
use core::{mem, ptr, slice};
use crate::{
c_str::CStr,
@@ -219,14 +223,18 @@ pub extern "C" fn fdopendir(fd: c_int) -> *mut DIR {
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/posix_getdents.html>.
// #[no_mangle]
#[no_mangle]
pub extern "C" fn posix_getdents(
fildes: c_int,
buf: *mut c_void,
nbyte: size_t,
flags: c_int,
_flags: c_int,
) -> ssize_t {
unimplemented!();
let slice = unsafe { slice::from_raw_parts_mut(buf as *mut u8, nbyte) };
Sys::posix_getdents(fildes, slice)
.map(|s| s as ssize_t)
.or_minus_one_errno()
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/readdir.html>.
+29 -3
View File
@@ -1,4 +1,3 @@
use crate::{header::errno::EOPNOTSUPP, io::Write, out::Out};
use core::{arch::asm, ptr};
use super::{types::*, Pal, ERRNO};
@@ -6,15 +5,16 @@ use crate::{
c_str::CStr,
header::{
dirent::dirent,
errno::EINVAL,
errno::{EINVAL, EIO, EOPNOTSUPP},
fcntl::{AT_EMPTY_PATH, AT_FDCWD, AT_REMOVEDIR, AT_SYMLINK_NOFOLLOW},
signal::SIGCHLD,
sys_resource::{rlimit, rusage},
sys_stat::{stat, S_IFIFO},
sys_statvfs::statvfs,
sys_time::{timeval, timezone},
unistd::SEEK_SET,
unistd::{SEEK_CUR, SEEK_SET},
},
io::Write,
};
// use header::sys_times::tms;
use crate::{
@@ -558,6 +558,32 @@ impl Pal for Sys {
e_raw(unsafe { syscall!(PIPE2, fildes.as_mut_ptr(), flags) }).map(|_| ())
}
fn posix_getdents(fildes: c_int, buf: &mut [u8]) -> Result<usize> {
let current_offset = Self::lseek(fildes, 0, SEEK_CUR)? as u64;
let bytes_read = Self::getdents(fildes, buf, current_offset)?;
if bytes_read == 0 {
return Ok(0);
}
let mut bytes_processed = 0;
let mut next_offset = current_offset;
while bytes_processed < bytes_read {
let remaining_slice = &buf[bytes_processed..];
let (reclen, opaque_next) =
unsafe { Self::dent_reclen_offset(remaining_slice, bytes_processed) }
.ok_or(Errno(EIO))?;
if reclen == 0 {
return Err(Errno(EIO));
}
bytes_processed += reclen as usize;
next_offset = opaque_next;
}
Self::lseek(fildes, next_offset as off_t, SEEK_SET)?;
Ok(bytes_read)
}
#[cfg(target_arch = "x86_64")]
unsafe fn rlct_clone(stack: *mut usize) -> Result<crate::pthread::OsTid> {
let flags = CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD;
+2
View File
@@ -216,6 +216,8 @@ pub trait Pal {
fn pipe2(fildes: Out<[c_int; 2]>, flags: c_int) -> Result<()>;
fn posix_getdents(fildes: c_int, buf: &mut [u8]) -> Result<usize>;
unsafe fn rlct_clone(stack: *mut usize) -> Result<pthread::OsTid, Errno>;
unsafe fn rlct_kill(os_tid: pthread::OsTid, signal: usize) -> Result<()>;
+28 -1
View File
@@ -36,7 +36,7 @@ use crate::{
sys_utsname::{utsname, UTSLENGTH},
sys_wait,
time::timespec,
unistd::{F_OK, R_OK, W_OK, X_OK},
unistd::{F_OK, R_OK, SEEK_CUR, SEEK_SET, W_OK, X_OK},
},
io::{self, prelude::*, BufReader},
out::Out,
@@ -419,6 +419,7 @@ impl Pal for Sys {
Ok(record_len.into())
}
fn dir_seek(_fd: c_int, _off: u64) -> Result<()> {
// Redox getdents takes an explicit (opaque) offset, so this is a no-op.
Ok(())
@@ -814,6 +815,32 @@ impl Pal for Sys {
Ok(())
}
fn posix_getdents(fildes: c_int, buf: &mut [u8]) -> Result<usize> {
let current_offset = Self::lseek(fildes, 0, SEEK_CUR)? as u64;
let bytes_read = Self::getdents(fildes, buf, current_offset)?;
if bytes_read == 0 {
return Ok(0);
}
let mut bytes_processed = 0;
let mut next_offset = current_offset;
while bytes_processed < bytes_read {
let remaining_slice = &buf[bytes_processed..];
let (reclen, opaque_next) =
unsafe { Self::dent_reclen_offset(remaining_slice, bytes_processed) }
.ok_or(Errno(EIO))?;
if reclen == 0 {
return Err(Errno(EIO));
}
bytes_processed += reclen as usize;
next_offset = opaque_next;
}
Self::lseek(fildes, next_offset as off_t, SEEK_SET)?;
Ok(bytes_read)
}
unsafe fn rlct_clone(stack: *mut usize) -> Result<crate::pthread::OsTid> {
let _guard = CLONE_LOCK.read();
let res = clone::rlct_clone_impl(stack);
+1
View File
@@ -189,6 +189,7 @@ DYNAMIC_ONLY_NAMES=\
NAMES=\
$(EXPECT_NAMES) \
dirent/main \
dirent/posix_getdents \
kill-waitpid \
net/if \
pty/forkpty \
+46
View File
@@ -0,0 +1,46 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#include <errno.h>
#include <sys/stat.h>
#include "test_helpers.h"
#define BUFFER_SIZE 4096
void read_and_print_directory(int fd) {
char buffer[BUFFER_SIZE];
long nread;
long bpos;
struct dirent *d;
for (;;) {
nread = posix_getdents(fd, buffer, BUFFER_SIZE, 0);
ERROR_IF(posix_getdents, nread, == -1);
UNEXP_IF(posix_getdents, nread, < 0);
if (nread == 0) {
break;
}
for (bpos = 0; bpos < nread;) {
d = (struct dirent *) (buffer + bpos);
printf(" ino = %-10lu name = %s\n", (unsigned long)d->d_ino, d->d_name);
bpos += d->d_reclen;
}
}
}
int main(void) {
int fd = open("example_dir/", O_RDONLY | O_DIRECTORY);
ERROR_IF(open, fd, == -1);
read_and_print_directory(fd);
off_t seek_result = lseek(fd, 0, SEEK_SET);
ERROR_IF(lseek, seek_result, == -1);
read_and_print_directory(fd);
close(fd);
}