Skip to content

Commit 056657b

Browse files
author
Jakub Konka
committed
Delegate definition of OsDir to OS-specific modules
Delegates defining `OsDir` struct to OS-specific modules (BSD, Linux, Emscripten, Windows). This way, `OsDir` can safely re-use `OsHandle` for raw OS handle storage, and can store some aux data such as an initialized stream ptr in case of BSD. As a result, we can safely get rid of `OsDirHandle` which IMHO was causing unnecessary noise and overcomplicating the design. On the other hand, delegating definition of `OsDir` to OS-specific modules isn't super clean in and of itself either. Perhaps there's a better way of handling this?
1 parent add2d50 commit 056657b

File tree

14 files changed

+98
-122
lines changed

14 files changed

+98
-122
lines changed

crates/wasi-common/src/sys/osdir.rs

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,19 @@
1-
use super::sys_impl::oshandle::OsDirHandle;
1+
use super::sys_impl::oshandle::OsHandle;
22
use super::{fd, path, AsFile};
33
use crate::handle::{Handle, HandleRights};
44
use crate::wasi::{types, Errno, Result};
55
use log::{debug, error};
66
use std::any::Any;
7-
use std::cell::Cell;
87
use std::io;
98
use std::ops::Deref;
109

11-
#[derive(Debug)]
12-
pub(crate) struct OsDir {
13-
rights: Cell<HandleRights>,
14-
handle: OsDirHandle,
15-
}
16-
17-
impl OsDir {
18-
pub(super) fn new(rights: HandleRights, handle: OsDirHandle) -> Self {
19-
let rights = Cell::new(rights);
20-
Self { rights, handle }
21-
}
22-
}
10+
// TODO could this be cleaned up?
11+
// The actual `OsDir` struct is OS-dependent, therefore we delegate
12+
// its definition to OS-specific modules.
13+
pub(crate) use super::sys_impl::osdir::OsDir;
2314

2415
impl Deref for OsDir {
25-
type Target = OsDirHandle;
16+
type Target = OsHandle;
2617

2718
fn deref(&self) -> &Self::Target {
2819
&self.handle
@@ -35,8 +26,8 @@ impl Handle for OsDir {
3526
}
3627
fn try_clone(&self) -> io::Result<Box<dyn Handle>> {
3728
let handle = self.handle.try_clone()?;
38-
let rights = self.rights.clone();
39-
Ok(Box::new(Self { rights, handle }))
29+
let new = Self::new(self.rights.get(), handle)?;
30+
Ok(Box::new(new))
4031
}
4132
fn get_file_type(&self) -> types::Filetype {
4233
types::Filetype::Directory

crates/wasi-common/src/sys/osfile.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use std::io::{self, Read, Seek, SeekFrom, Write};
99
use std::ops::Deref;
1010

1111
pub(crate) trait OsFileExt {
12+
/// Create `OsFile` as `dyn Handle` from null device.
1213
fn from_null() -> io::Result<Box<dyn Handle>>;
1314
}
1415

crates/wasi-common/src/sys/stdio.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,11 @@ use std::cell::Cell;
88
use std::io::{self, Read, Write};
99

1010
pub(crate) trait StdioExt: Sized {
11+
/// Create `Stdio` from `io::stdin`.
1112
fn stdin() -> io::Result<Box<dyn Handle>>;
13+
/// Create `Stdio` from `io::stdout`.
1214
fn stdout() -> io::Result<Box<dyn Handle>>;
15+
/// Create `Stdio` from `io::stderr`.
1316
fn stderr() -> io::Result<Box<dyn Handle>>;
1417
}
1518

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
pub(crate) mod oshandle;
1+
pub(crate) mod osdir;
22
pub(crate) mod path;
33

44
pub(crate) const O_RSYNC: yanix::file::OFlag = yanix::file::OFlag::SYNC;
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
use crate::handle::HandleRights;
2+
use crate::sys::sys_impl::oshandle::OsHandle;
3+
use crate::wasi::Result;
4+
use std::cell::{Cell, RefCell, RefMut};
5+
use std::io;
6+
use yanix::dir::Dir;
7+
8+
#[derive(Debug)]
9+
pub(crate) struct OsDir {
10+
pub(crate) rights: Cell<HandleRights>,
11+
pub(crate) handle: OsHandle,
12+
// When the client makes a `fd_readdir` syscall on this descriptor,
13+
// we will need to cache the `libc::DIR` pointer manually in order
14+
// to be able to seek on it later. While on Linux, this is handled
15+
// by the OS, BSD Unixes require the client to do this caching.
16+
//
17+
// This comes directly from the BSD man pages on `readdir`:
18+
// > Values returned by telldir() are good only for the lifetime
19+
// > of the DIR pointer, dirp, from which they are derived.
20+
// > If the directory is closed and then reopened, prior values
21+
// > returned by telldir() will no longer be valid.
22+
stream_ptr: RefCell<Dir>,
23+
}
24+
25+
impl OsDir {
26+
pub(crate) fn new(rights: HandleRights, handle: OsHandle) -> io::Result<Self> {
27+
let rights = Cell::new(rights);
28+
// We need to duplicate the handle, because `opendir(3)`:
29+
// Upon successful return from fdopendir(), the file descriptor is under
30+
// control of the system, and if any attempt is made to close the file
31+
// descriptor, or to modify the state of the associated description other
32+
// than by means of closedir(), readdir(), readdir_r(), or rewinddir(),
33+
// the behaviour is undefined.
34+
let stream_ptr = Dir::from(handle.try_clone()?)?;
35+
let stream_ptr = RefCell::new(stream_ptr);
36+
Ok(Self {
37+
rights,
38+
handle,
39+
stream_ptr,
40+
})
41+
}
42+
/// Returns the `Dir` stream pointer associated with this `OsDir`.
43+
pub(crate) fn stream_ptr(&self) -> Result<RefMut<Dir>> {
44+
Ok(self.stream_ptr.borrow_mut())
45+
}
46+
}

crates/wasi-common/src/sys/unix/bsd/oshandle.rs

Lines changed: 0 additions & 42 deletions
This file was deleted.

crates/wasi-common/src/sys/unix/emscripten/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
#[path = "../linux/oshandle.rs"]
2-
pub(crate) mod oshandle;
1+
#[path = "../linux/osdir.rs"]
2+
pub(crate) mod osdir;
33
#[path = "../linux/path.rs"]
44
pub(crate) mod path;
55

crates/wasi-common/src/sys/unix/fd.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ pub(crate) fn readdir<'a>(
5454

5555
// Get an instance of `Dir`; this is host-specific due to intricasies
5656
// of managing a dir stream between Linux and BSD *nixes
57-
let mut dir = dirfd.dir_stream()?;
57+
let mut dir = dirfd.stream_ptr()?;
5858

5959
// Seek if needed. Unless cookie is wasi::__WASI_DIRCOOKIE_START,
6060
// new items may not be returned to the caller.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
pub(crate) mod oshandle;
1+
pub(crate) mod osdir;
22
pub(crate) mod path;
33

44
pub(crate) const O_RSYNC: yanix::file::OFlag = yanix::file::OFlag::RSYNC;
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,35 @@
1+
use crate::handle::HandleRights;
12
use crate::sys::sys_impl::oshandle::OsHandle;
23
use crate::wasi::Result;
4+
use std::cell::Cell;
35
use std::io;
4-
use std::ops::Deref;
56
use yanix::dir::Dir;
67

78
#[derive(Debug)]
8-
pub(crate) struct OsDirHandle(OsHandle);
9+
pub(crate) struct OsDir {
10+
pub(crate) rights: Cell<HandleRights>,
11+
pub(crate) handle: OsHandle,
12+
}
913

10-
impl OsDirHandle {
11-
/// Consumes the spcified `OsHandle`.
12-
pub(crate) fn new(handle: OsHandle) -> io::Result<Self> {
13-
Ok(Self(handle))
14-
}
15-
/// Tries clone `self`.
16-
pub(crate) fn try_clone(&self) -> io::Result<Self> {
17-
let handle = self.0.try_clone()?;
18-
Self::new(handle)
14+
impl OsDir {
15+
pub(crate) fn new(rights: HandleRights, handle: OsHandle) -> io::Result<Self> {
16+
let rights = Cell::new(rights);
17+
Ok(Self { rights, handle })
1918
}
20-
/// Gets current dir stream pointer.
21-
pub(crate) fn dir_stream(&self) -> Result<Box<Dir>> {
22-
// We need to duplicate the fd, because `opendir(3)`:
19+
/// Returns the `Dir` stream pointer associated with this `OsDir`.
20+
pub(crate) fn stream_ptr(&self) -> Result<Box<Dir>> {
21+
// We need to duplicate the handle, because `opendir(3)`:
2322
// After a successful call to fdopendir(), fd is used internally by the implementation,
2423
// and should not otherwise be used by the application.
2524
// `opendir(3p)` also says that it's undefined behavior to
2625
// modify the state of the fd in a different way than by accessing DIR*.
2726
//
2827
// Still, rewinddir will be needed because the two file descriptors
2928
// share progress. But we can safely execute closedir now.
30-
let file = self.0.try_clone()?;
29+
let file = self.handle.try_clone()?;
3130
// TODO This doesn't look very clean. Can we do something about it?
3231
// Boxing is needed here in order to satisfy `yanix`'s trait requirement for the `DirIter`
3332
// where `T: Deref<Target = Dir>`.
3433
Ok(Box::new(Dir::from(file)?))
3534
}
3635
}
37-
38-
impl Deref for OsDirHandle {
39-
type Target = OsHandle;
40-
41-
fn deref(&self) -> &Self::Target {
42-
&self.0
43-
}
44-
}

0 commit comments

Comments
 (0)