Support fd_fdstat_get and fd_renumber on stdin/stdout/stderr (#631)

* Support fd_fdstat_get on stdin/stdout/stderr.

Add a routine for obtaining an `OsFile` containing a file descriptor for
stdin/stdout/stderr so that we can do fd_fdstat_get on them.

* Add a testcase for fd_fdstat_get etc. on stdin etc.

* Don't dup file descriptors in fd_renumber.

* Fix compilation on macOS

* Rename OsFile to OsHandle

This commits renames `OsFile` to `OsHandle` which seems to make
more sense semantically as it is permitted to hold a valid OS handle
to OS entities other than simply file/dir (e.g., socket, stream, etc.).
As such, this commit also renames methods on `Descriptor` struct
from `as_actual_file` to `as_file` as this in reality does pertain
ops on FS entities such as files/dirs, and `as_file` to `as_os_handle`
as in this case it can be anything, from file, through a socket, to
a stream.

* Fix compilation on Linux

* Introduce `OsHandleRef` for borrowing OS resources.

To prevent a `ManuallyDrop<OsHandleRef>` from outliving the resource it
holds on to, create an `OsHandleRef` class parameterized on the lifetime
of the `Descriptor`.

* Fix scoping to pub-priv and backport to snapshot_0
This commit is contained in:
Dan Gohman
2019-11-28 05:36:18 -08:00
committed by Jakub Konka
parent b69758f672
commit 1f9d764d5d
22 changed files with 278 additions and 191 deletions

View File

@@ -161,7 +161,7 @@ pub(crate) unsafe fn fd_read(
.get_fd_entry_mut(fd)?
.as_descriptor_mut(wasi::__WASI_RIGHTS_FD_READ, 0)?
{
Descriptor::OsFile(file) => file.read_vectored(&mut iovs),
Descriptor::OsHandle(file) => file.read_vectored(&mut iovs),
Descriptor::Stdin => io::stdin().lock().read_vectored(&mut iovs),
_ => return Err(Error::EBADF),
};
@@ -180,33 +180,25 @@ pub(crate) unsafe fn fd_renumber(
) -> Result<()> {
trace!("fd_renumber(from={:?}, to={:?})", from, to);
if !wasi_ctx.contains_fd_entry(from) || !wasi_ctx.contains_fd_entry(to) {
if !wasi_ctx.contains_fd_entry(from) {
return Err(Error::EBADF);
}
let from_fe = wasi_ctx.get_fd_entry(from)?;
let to_fe = wasi_ctx.get_fd_entry(to)?;
// Don't allow renumbering over a pre-opened resource.
// TODO: Eventually, we do want to permit this, once libpreopen in
// userspace is capable of removing entries from its tables as well.
if from_fe.preopen_path.is_some() || to_fe.preopen_path.is_some() {
let from_fe = wasi_ctx.get_fd_entry(from)?;
if from_fe.preopen_path.is_some() {
return Err(Error::ENOTSUP);
}
// check if stdio fds
// TODO should we renumber stdio fds?
if !from_fe.as_descriptor(0, 0)?.is_file() || !to_fe.as_descriptor(0, 0)?.is_file() {
return Err(Error::EBADF);
if let Ok(to_fe) = wasi_ctx.get_fd_entry(to) {
if to_fe.preopen_path.is_some() {
return Err(Error::ENOTSUP);
}
}
let fe_from_dup = from_fe
.as_descriptor(0, 0)?
.as_file()
.and_then(|file| FdEntry::duplicate(file))?;
wasi_ctx.insert_fd_entry_at(to, fe_from_dup);
wasi_ctx.remove_fd_entry(from)?;
let fe = wasi_ctx.remove_fd_entry(from)?;
wasi_ctx.insert_fd_entry_at(to, fe);
Ok(())
}
@@ -279,9 +271,12 @@ pub(crate) unsafe fn fd_fdstat_get(
trace!("fd_fdstat_get(fd={:?}, fdstat_ptr={:#x?})", fd, fdstat_ptr);
let mut fdstat = dec_fdstat_byref(memory, fdstat_ptr)?;
let wasi_fd = wasi_ctx.get_fd_entry(fd)?.as_descriptor(0, 0)?.as_file()?;
let host_fd = wasi_ctx
.get_fd_entry(fd)?
.as_descriptor(0, 0)?
.as_os_handle();
let fs_flags = hostcalls_impl::fd_fdstat_get(wasi_fd)?;
let fs_flags = hostcalls_impl::fd_fdstat_get(&host_fd)?;
let fe = wasi_ctx.get_fd_entry(fd)?;
fdstat.fs_filetype = fe.file_type;
@@ -301,9 +296,12 @@ pub(crate) unsafe fn fd_fdstat_set_flags(
) -> Result<()> {
trace!("fd_fdstat_set_flags(fd={:?}, fdflags={:#x?})", fd, fdflags);
let fd = wasi_ctx.get_fd_entry(fd)?.as_descriptor(0, 0)?.as_file()?;
let fd = wasi_ctx
.get_fd_entry(fd)?
.as_descriptor(0, 0)?
.as_os_handle();
hostcalls_impl::fd_fdstat_set_flags(fd, fdflags)
hostcalls_impl::fd_fdstat_set_flags(&fd, fdflags)
}
pub(crate) unsafe fn fd_fdstat_set_rights(
@@ -365,7 +363,7 @@ pub(crate) unsafe fn fd_write(
.get_fd_entry_mut(fd)?
.as_descriptor_mut(wasi::__WASI_RIGHTS_FD_WRITE, 0)?
{
Descriptor::OsFile(file) => file.write_vectored(&iovs)?,
Descriptor::OsHandle(file) => file.write_vectored(&iovs)?,
Descriptor::Stdin => return Err(Error::EBADF),
Descriptor::Stdout => {
// lock for the duration of the scope