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
This commit is contained in:
130
src/sys/unix/fdentry_impl.rs
Normal file
130
src/sys/unix/fdentry_impl.rs
Normal file
@@ -0,0 +1,130 @@
|
||||
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))
|
||||
}
|
||||
Reference in New Issue
Block a user