Files
wasmtime/src/sys/unix/fdentry_impl.rs
Jakub Konka 667f272edd Rewrite majority of impl reusing libstd (#34)
* Rewrite FdEntry reusing as much libstd as possible

* Use the new FdEntry, FdObject, Descriptor struct in *nix impl

* Adapt Windows impl

* Remove unnecessary check in fd_read

Check `host_nread == 0` caused premature FdEntry closure and removal
which ultimately was resulting in an attempt at "double closing" of
the same file descriptor at the end of the Wasm program:
...
fd_close(fd=4)
    -> errno=WASI_ESUCCESS
fd_close(fd=4)
    -> errno=WASI_EBADF

* Use libstd vectored IO

* Use std:🧵:yield_now to implement sched_yield

* Add logging to integration tests

* Add preliminary support for host-specific errors

* Operate on std::fs::File in path_get on *nix

* Add cross-platform RawString type encapsulating OsStrExt

* Fix Windows build

* Update Travis and README to Rust v1.36

* Remove unused winx::handle::close helper

* Refactor Descriptor into raw handles/fds

* Strip readlinkat in prep for path_get host-independent

* Strip openat in prep for path_get host-independent

* Move ManuallyDrop up one level from Descriptor to FdObject

* Make (c)iovec host fns unsafe

* Swap unwraps/expects for Results in fdentry_impl on nix

* Rewrite fd_pread/write and implement for Win

* Use File::sync_all to impl fd_sync

* Use File::sync_data to impl fd_datasync

* Rewind file cursor after fd_p{read, write} on Windows

* Add fd_p{read, write} tests

* Handle errors instead of panicking in path_get

* Use File::set_len to impl fd_allocate

* Add test for fd_allocate

* Replace all panics with Results

* Document the point of RawString
2019-07-15 15:34:28 -07:00

131 lines
4.3 KiB
Rust

use crate::fdentry::Descriptor;
use crate::host;
use crate::sys::errno_from_host;
use std::io;
use std::os::unix::prelude::{AsRawFd, FileTypeExt, FromRawFd, RawFd};
impl AsRawFd for Descriptor {
fn as_raw_fd(&self) -> RawFd {
match self {
Descriptor::File(f) => f.as_raw_fd(),
Descriptor::Stdin => io::stdin().as_raw_fd(),
Descriptor::Stdout => io::stdout().as_raw_fd(),
Descriptor::Stderr => io::stderr().as_raw_fd(),
}
}
}
pub(crate) fn determine_type_and_access_rights<Fd: AsRawFd>(
fd: &Fd,
) -> Result<
(
host::__wasi_filetype_t,
host::__wasi_rights_t,
host::__wasi_rights_t,
),
host::__wasi_errno_t,
> {
let (file_type, mut rights_base, rights_inheriting) = determine_type_rights(fd)?;
use nix::fcntl::{fcntl, OFlag, F_GETFL};
let flags_bits = fcntl(fd.as_raw_fd(), F_GETFL).map_err(|err| {
err.as_errno()
.map_or(host::__WASI_EIO, |e| errno_from_host(e as i32))
})?;
let flags = OFlag::from_bits_truncate(flags_bits);
let accmode = flags & OFlag::O_ACCMODE;
if accmode == OFlag::O_RDONLY {
rights_base &= !host::__WASI_RIGHT_FD_WRITE;
} else if accmode == OFlag::O_WRONLY {
rights_base &= !host::__WASI_RIGHT_FD_READ;
}
Ok((file_type, rights_base, rights_inheriting))
}
pub(crate) fn determine_type_rights<Fd: AsRawFd>(
fd: &Fd,
) -> Result<
(
host::__wasi_filetype_t,
host::__wasi_rights_t,
host::__wasi_rights_t,
),
host::__wasi_errno_t,
> {
let (file_type, rights_base, rights_inheriting) = {
// we just make a `File` here for convenience; we don't want it to close when it drops
let file =
std::mem::ManuallyDrop::new(unsafe { std::fs::File::from_raw_fd(fd.as_raw_fd()) });
let ft = file
.metadata()
.map_err(|err| err.raw_os_error().map_or(host::__WASI_EIO, errno_from_host))?
.file_type();
if ft.is_block_device() {
(
host::__WASI_FILETYPE_BLOCK_DEVICE,
host::RIGHTS_BLOCK_DEVICE_BASE,
host::RIGHTS_BLOCK_DEVICE_INHERITING,
)
} else if ft.is_char_device() {
if nix::unistd::isatty(fd.as_raw_fd()).map_err(|err| {
err.as_errno()
.map_or(host::__WASI_EIO, |e| errno_from_host(e as i32))
})? {
(
host::__WASI_FILETYPE_CHARACTER_DEVICE,
host::RIGHTS_TTY_BASE,
host::RIGHTS_TTY_BASE,
)
} else {
(
host::__WASI_FILETYPE_CHARACTER_DEVICE,
host::RIGHTS_CHARACTER_DEVICE_BASE,
host::RIGHTS_CHARACTER_DEVICE_INHERITING,
)
}
} else if ft.is_dir() {
(
host::__WASI_FILETYPE_DIRECTORY,
host::RIGHTS_DIRECTORY_BASE,
host::RIGHTS_DIRECTORY_INHERITING,
)
} else if ft.is_file() {
(
host::__WASI_FILETYPE_REGULAR_FILE,
host::RIGHTS_REGULAR_FILE_BASE,
host::RIGHTS_REGULAR_FILE_INHERITING,
)
} else if ft.is_socket() {
use nix::sys::socket;
match socket::getsockopt(fd.as_raw_fd(), socket::sockopt::SockType).map_err(|err| {
err.as_errno()
.map_or(host::__WASI_EIO, |e| errno_from_host(e as i32))
})? {
socket::SockType::Datagram => (
host::__WASI_FILETYPE_SOCKET_DGRAM,
host::RIGHTS_SOCKET_BASE,
host::RIGHTS_SOCKET_INHERITING,
),
socket::SockType::Stream => (
host::__WASI_FILETYPE_SOCKET_STREAM,
host::RIGHTS_SOCKET_BASE,
host::RIGHTS_SOCKET_INHERITING,
),
_ => return Err(host::__WASI_EINVAL),
}
} else if ft.is_fifo() {
(
host::__WASI_FILETYPE_SOCKET_STREAM,
host::RIGHTS_SOCKET_BASE,
host::RIGHTS_SOCKET_INHERITING,
)
} else {
return Err(host::__WASI_EINVAL);
}
};
Ok((file_type, rights_base, rights_inheriting))
}