* Add support for wasi_snapshot_preview1. This adds support for the new ABI, while preserving compatibility support for the old ABI. * Fix compilation on platforms where nlink_t isn't 64-bit. * rustfmt * Fix Windows build errors.
136 lines
4.8 KiB
Rust
136 lines
4.8 KiB
Rust
use crate::fdentry::Descriptor;
|
|
use crate::{wasi, Error, Result};
|
|
use std::io;
|
|
use std::os::unix::prelude::{AsRawFd, FileTypeExt, FromRawFd, RawFd};
|
|
|
|
cfg_if::cfg_if! {
|
|
if #[cfg(target_os = "linux")] {
|
|
pub(crate) use super::linux::osfile::*;
|
|
pub(crate) use super::linux::fdentry_impl::*;
|
|
} else if #[cfg(any(
|
|
target_os = "macos",
|
|
target_os = "netbsd",
|
|
target_os = "freebsd",
|
|
target_os = "openbsd",
|
|
target_os = "ios",
|
|
target_os = "dragonfly"
|
|
))] {
|
|
pub(crate) use super::bsd::osfile::*;
|
|
pub(crate) use super::bsd::fdentry_impl::*;
|
|
}
|
|
}
|
|
|
|
impl AsRawFd for Descriptor {
|
|
fn as_raw_fd(&self) -> RawFd {
|
|
match self {
|
|
Self::OsFile(file) => file.as_raw_fd(),
|
|
Self::Stdin => io::stdin().as_raw_fd(),
|
|
Self::Stdout => io::stdout().as_raw_fd(),
|
|
Self::Stderr => io::stderr().as_raw_fd(),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// This function is unsafe because it operates on a raw file descriptor.
|
|
pub(crate) unsafe fn determine_type_and_access_rights<Fd: AsRawFd>(
|
|
fd: &Fd,
|
|
) -> Result<(
|
|
wasi::__wasi_filetype_t,
|
|
wasi::__wasi_rights_t,
|
|
wasi::__wasi_rights_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)?;
|
|
let flags = OFlag::from_bits_truncate(flags_bits);
|
|
let accmode = flags & OFlag::O_ACCMODE;
|
|
if accmode == OFlag::O_RDONLY {
|
|
rights_base &= !wasi::__WASI_RIGHTS_FD_WRITE;
|
|
} else if accmode == OFlag::O_WRONLY {
|
|
rights_base &= !wasi::__WASI_RIGHTS_FD_READ;
|
|
}
|
|
|
|
Ok((file_type, rights_base, rights_inheriting))
|
|
}
|
|
|
|
/// This function is unsafe because it operates on a raw file descriptor.
|
|
pub(crate) unsafe fn determine_type_rights<Fd: AsRawFd>(
|
|
fd: &Fd,
|
|
) -> Result<(
|
|
wasi::__wasi_filetype_t,
|
|
wasi::__wasi_rights_t,
|
|
wasi::__wasi_rights_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(std::fs::File::from_raw_fd(fd.as_raw_fd()));
|
|
let ft = file.metadata()?.file_type();
|
|
if ft.is_block_device() {
|
|
log::debug!("Host fd {:?} is a block device", fd.as_raw_fd());
|
|
(
|
|
wasi::__WASI_FILETYPE_BLOCK_DEVICE,
|
|
wasi::RIGHTS_BLOCK_DEVICE_BASE,
|
|
wasi::RIGHTS_BLOCK_DEVICE_INHERITING,
|
|
)
|
|
} else if ft.is_char_device() {
|
|
log::debug!("Host fd {:?} is a char device", fd.as_raw_fd());
|
|
if isatty(fd)? {
|
|
(
|
|
wasi::__WASI_FILETYPE_CHARACTER_DEVICE,
|
|
wasi::RIGHTS_TTY_BASE,
|
|
wasi::RIGHTS_TTY_BASE,
|
|
)
|
|
} else {
|
|
(
|
|
wasi::__WASI_FILETYPE_CHARACTER_DEVICE,
|
|
wasi::RIGHTS_CHARACTER_DEVICE_BASE,
|
|
wasi::RIGHTS_CHARACTER_DEVICE_INHERITING,
|
|
)
|
|
}
|
|
} else if ft.is_dir() {
|
|
log::debug!("Host fd {:?} is a directory", fd.as_raw_fd());
|
|
(
|
|
wasi::__WASI_FILETYPE_DIRECTORY,
|
|
wasi::RIGHTS_DIRECTORY_BASE,
|
|
wasi::RIGHTS_DIRECTORY_INHERITING,
|
|
)
|
|
} else if ft.is_file() {
|
|
log::debug!("Host fd {:?} is a file", fd.as_raw_fd());
|
|
(
|
|
wasi::__WASI_FILETYPE_REGULAR_FILE,
|
|
wasi::RIGHTS_REGULAR_FILE_BASE,
|
|
wasi::RIGHTS_REGULAR_FILE_INHERITING,
|
|
)
|
|
} else if ft.is_socket() {
|
|
log::debug!("Host fd {:?} is a socket", fd.as_raw_fd());
|
|
use nix::sys::socket;
|
|
match socket::getsockopt(fd.as_raw_fd(), socket::sockopt::SockType)? {
|
|
socket::SockType::Datagram => (
|
|
wasi::__WASI_FILETYPE_SOCKET_DGRAM,
|
|
wasi::RIGHTS_SOCKET_BASE,
|
|
wasi::RIGHTS_SOCKET_INHERITING,
|
|
),
|
|
socket::SockType::Stream => (
|
|
wasi::__WASI_FILETYPE_SOCKET_STREAM,
|
|
wasi::RIGHTS_SOCKET_BASE,
|
|
wasi::RIGHTS_SOCKET_INHERITING,
|
|
),
|
|
_ => return Err(Error::EINVAL),
|
|
}
|
|
} else if ft.is_fifo() {
|
|
log::debug!("Host fd {:?} is a fifo", fd.as_raw_fd());
|
|
(
|
|
wasi::__WASI_FILETYPE_UNKNOWN,
|
|
wasi::RIGHTS_REGULAR_FILE_BASE,
|
|
wasi::RIGHTS_REGULAR_FILE_INHERITING,
|
|
)
|
|
} else {
|
|
log::debug!("Host fd {:?} is unknown", fd.as_raw_fd());
|
|
return Err(Error::EINVAL);
|
|
}
|
|
};
|
|
|
|
Ok((file_type, rights_base, rights_inheriting))
|
|
}
|