Fix fd_readdir on BSD-style nixes (#81)

* Fix fd_readdir on BSD-style nixes

The fix was tested on Darwin-XNU and FreeBSD. The change introduces
thread-safe cache of (RawFd, *mut libc::DIR) pairs so that
libc::fdopendir syscall is called only once when invoking fd_readdir
for the first time, and then the pointer to the directory stream,
*mut libc::DIR, is reused until the matching raw file descriptor
is closed.

This fix allows then correct use (and matching to the implementation
on Linux kernels) of libc::seekdir and libc::rewinddir to seek through
and rewind the existing directory stream, *mut libc::DIR, which
otherwise seems to be reset/invalidated every time libc::fdopendir
is called (unlike on Linux, where this behaviour is not observed).

* Store dir stream as part of the FdEntry's Descriptor

* Move bsd specifics into separate module

* Add todo comments and fix formatting

* Refactor int conversions

* Emphasise in debug logs that we're looking at fd_readdir entry

* Change visibility of FdEntry and related to public-private

* Rewrite creating DirStream for the first time
This commit is contained in:
Jakub Konka
2019-09-14 21:01:39 +02:00
committed by GitHub
parent 500e32a3b2
commit c98b3d10ec
15 changed files with 484 additions and 219 deletions

View File

@@ -1,48 +1,57 @@
use crate::sys::fdentry_impl;
use crate::sys::fdentry_impl::{determine_type_and_access_rights, OsFile};
use crate::{host, Error, Result};
use std::mem::ManuallyDrop;
use std::path::PathBuf;
use std::{fs, io};
#[derive(Debug)]
pub enum Descriptor {
File(fs::File),
pub(crate) enum Descriptor {
OsFile(OsFile),
Stdin,
Stdout,
Stderr,
}
impl Descriptor {
pub fn as_file(&self) -> Result<&fs::File> {
pub(crate) fn as_file(&self) -> Result<&OsFile> {
match self {
Descriptor::File(f) => Ok(f),
Descriptor::OsFile(file) => Ok(file),
_ => Err(Error::EBADF),
}
}
pub fn is_file(&self) -> bool {
pub(crate) fn as_file_mut(&mut self) -> Result<&mut OsFile> {
match self {
Descriptor::File(_) => true,
Descriptor::OsFile(file) => Ok(file),
_ => Err(Error::EBADF),
}
}
pub(crate) fn is_file(&self) -> bool {
match self {
Descriptor::OsFile(_) => true,
_ => false,
}
}
pub fn is_stdin(&self) -> bool {
#[allow(unused)]
pub(crate) fn is_stdin(&self) -> bool {
match self {
Descriptor::Stdin => true,
_ => false,
}
}
pub fn is_stdout(&self) -> bool {
#[allow(unused)]
pub(crate) fn is_stdout(&self) -> bool {
match self {
Descriptor::Stdout => true,
_ => false,
}
}
pub fn is_stderr(&self) -> bool {
#[allow(unused)]
pub(crate) fn is_stderr(&self) -> bool {
match self {
Descriptor::Stderr => true,
_ => false,
@@ -51,19 +60,19 @@ impl Descriptor {
}
#[derive(Debug)]
pub struct FdObject {
pub file_type: host::__wasi_filetype_t,
pub descriptor: ManuallyDrop<Descriptor>,
pub needs_close: bool,
pub(crate) struct FdObject {
pub(crate) file_type: host::__wasi_filetype_t,
pub(crate) descriptor: ManuallyDrop<Descriptor>,
pub(crate) needs_close: bool,
// TODO: directories
}
#[derive(Debug)]
pub struct FdEntry {
pub fd_object: FdObject,
pub rights_base: host::__wasi_rights_t,
pub rights_inheriting: host::__wasi_rights_t,
pub preopen_path: Option<PathBuf>,
pub(crate) struct FdEntry {
pub(crate) fd_object: FdObject,
pub(crate) rights_base: host::__wasi_rights_t,
pub(crate) rights_inheriting: host::__wasi_rights_t,
pub(crate) preopen_path: Option<PathBuf>,
}
impl Drop for FdObject {
@@ -75,12 +84,12 @@ impl Drop for FdObject {
}
impl FdEntry {
pub fn from(file: fs::File) -> Result<Self> {
fdentry_impl::determine_type_and_access_rights(&file).map(
pub(crate) fn from(file: fs::File) -> Result<Self> {
determine_type_and_access_rights(&file).map(
|(file_type, rights_base, rights_inheriting)| Self {
fd_object: FdObject {
file_type,
descriptor: ManuallyDrop::new(Descriptor::File(file)),
descriptor: ManuallyDrop::new(Descriptor::OsFile(OsFile::from(file))),
needs_close: true,
},
rights_base,
@@ -90,12 +99,12 @@ impl FdEntry {
)
}
pub fn duplicate(file: &fs::File) -> Result<Self> {
pub(crate) fn duplicate(file: &fs::File) -> Result<Self> {
Self::from(file.try_clone()?)
}
pub fn duplicate_stdin() -> Result<Self> {
fdentry_impl::determine_type_and_access_rights(&io::stdin()).map(
pub(crate) fn duplicate_stdin() -> Result<Self> {
determine_type_and_access_rights(&io::stdin()).map(
|(file_type, rights_base, rights_inheriting)| Self {
fd_object: FdObject {
file_type,
@@ -109,8 +118,8 @@ impl FdEntry {
)
}
pub fn duplicate_stdout() -> Result<Self> {
fdentry_impl::determine_type_and_access_rights(&io::stdout()).map(
pub(crate) fn duplicate_stdout() -> Result<Self> {
determine_type_and_access_rights(&io::stdout()).map(
|(file_type, rights_base, rights_inheriting)| Self {
fd_object: FdObject {
file_type,
@@ -124,8 +133,8 @@ impl FdEntry {
)
}
pub fn duplicate_stderr() -> Result<Self> {
fdentry_impl::determine_type_and_access_rights(&io::stderr()).map(
pub(crate) fn duplicate_stderr() -> Result<Self> {
determine_type_and_access_rights(&io::stderr()).map(
|(file_type, rights_base, rights_inheriting)| Self {
fd_object: FdObject {
file_type,