Implement posix_getdents
This commit is contained in:
committed by
Jeremy Soller
parent
dc7491387b
commit
7416ba6ff3
@@ -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>.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<()>;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -189,6 +189,7 @@ DYNAMIC_ONLY_NAMES=\
|
||||
NAMES=\
|
||||
$(EXPECT_NAMES) \
|
||||
dirent/main \
|
||||
dirent/posix_getdents \
|
||||
kill-waitpid \
|
||||
net/if \
|
||||
pty/forkpty \
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
Reference in New Issue
Block a user