wasi-common 0.21.0

WASI implementation in Rust
Documentation
//! WASI host types specific to *nix host.
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(dead_code)]
use crate::old::snapshot_0::host::FileType;
use crate::old::snapshot_0::wasi::{self, WasiError, WasiResult};
use crate::old::snapshot_0::{helpers, sys::unix::sys_impl};
use std::ffi::OsStr;
use std::io;
use std::os::unix::prelude::OsStrExt;
use yanix::file::OFlags;

pub(crate) use sys_impl::host_impl::*;

impl From<io::Error> for WasiError {
    fn from(err: io::Error) -> Self {
        match err.raw_os_error() {
            Some(code) => match code {
                libc::EPERM => Self::EPERM,
                libc::ENOENT => Self::ENOENT,
                libc::ESRCH => Self::ESRCH,
                libc::EINTR => Self::EINTR,
                libc::EIO => Self::EIO,
                libc::ENXIO => Self::ENXIO,
                libc::E2BIG => Self::E2BIG,
                libc::ENOEXEC => Self::ENOEXEC,
                libc::EBADF => Self::EBADF,
                libc::ECHILD => Self::ECHILD,
                libc::EAGAIN => Self::EAGAIN,
                libc::ENOMEM => Self::ENOMEM,
                libc::EACCES => Self::EACCES,
                libc::EFAULT => Self::EFAULT,
                libc::EBUSY => Self::EBUSY,
                libc::EEXIST => Self::EEXIST,
                libc::EXDEV => Self::EXDEV,
                libc::ENODEV => Self::ENODEV,
                libc::ENOTDIR => Self::ENOTDIR,
                libc::EISDIR => Self::EISDIR,
                libc::EINVAL => Self::EINVAL,
                libc::ENFILE => Self::ENFILE,
                libc::EMFILE => Self::EMFILE,
                libc::ENOTTY => Self::ENOTTY,
                libc::ETXTBSY => Self::ETXTBSY,
                libc::EFBIG => Self::EFBIG,
                libc::ENOSPC => Self::ENOSPC,
                libc::ESPIPE => Self::ESPIPE,
                libc::EROFS => Self::EROFS,
                libc::EMLINK => Self::EMLINK,
                libc::EPIPE => Self::EPIPE,
                libc::EDOM => Self::EDOM,
                libc::ERANGE => Self::ERANGE,
                libc::EDEADLK => Self::EDEADLK,
                libc::ENAMETOOLONG => Self::ENAMETOOLONG,
                libc::ENOLCK => Self::ENOLCK,
                libc::ENOSYS => Self::ENOSYS,
                libc::ENOTEMPTY => Self::ENOTEMPTY,
                libc::ELOOP => Self::ELOOP,
                libc::ENOMSG => Self::ENOMSG,
                libc::EIDRM => Self::EIDRM,
                libc::ENOLINK => Self::ENOLINK,
                libc::EPROTO => Self::EPROTO,
                libc::EMULTIHOP => Self::EMULTIHOP,
                libc::EBADMSG => Self::EBADMSG,
                libc::EOVERFLOW => Self::EOVERFLOW,
                libc::EILSEQ => Self::EILSEQ,
                libc::ENOTSOCK => Self::ENOTSOCK,
                libc::EDESTADDRREQ => Self::EDESTADDRREQ,
                libc::EMSGSIZE => Self::EMSGSIZE,
                libc::EPROTOTYPE => Self::EPROTOTYPE,
                libc::ENOPROTOOPT => Self::ENOPROTOOPT,
                libc::EPROTONOSUPPORT => Self::EPROTONOSUPPORT,
                libc::EAFNOSUPPORT => Self::EAFNOSUPPORT,
                libc::EADDRINUSE => Self::EADDRINUSE,
                libc::EADDRNOTAVAIL => Self::EADDRNOTAVAIL,
                libc::ENETDOWN => Self::ENETDOWN,
                libc::ENETUNREACH => Self::ENETUNREACH,
                libc::ENETRESET => Self::ENETRESET,
                libc::ECONNABORTED => Self::ECONNABORTED,
                libc::ECONNRESET => Self::ECONNRESET,
                libc::ENOBUFS => Self::ENOBUFS,
                libc::EISCONN => Self::EISCONN,
                libc::ENOTCONN => Self::ENOTCONN,
                libc::ETIMEDOUT => Self::ETIMEDOUT,
                libc::ECONNREFUSED => Self::ECONNREFUSED,
                libc::EHOSTUNREACH => Self::EHOSTUNREACH,
                libc::EALREADY => Self::EALREADY,
                libc::EINPROGRESS => Self::EINPROGRESS,
                libc::ESTALE => Self::ESTALE,
                libc::EDQUOT => Self::EDQUOT,
                libc::ECANCELED => Self::ECANCELED,
                libc::EOWNERDEAD => Self::EOWNERDEAD,
                libc::ENOTRECOVERABLE => Self::ENOTRECOVERABLE,
                libc::ENOTSUP => Self::ENOTSUP,
                x => {
                    tracing::debug!("Unknown errno value: {}", x);
                    Self::EIO
                }
            },
            None => {
                tracing::debug!("Other I/O error: {}", err);
                Self::EIO
            }
        }
    }
}

pub(crate) fn nix_from_fdflags(fdflags: wasi::__wasi_fdflags_t) -> OFlags {
    let mut nix_flags = OFlags::empty();
    if fdflags & wasi::__WASI_FDFLAGS_APPEND != 0 {
        nix_flags.insert(OFlags::APPEND);
    }
    if fdflags & wasi::__WASI_FDFLAGS_DSYNC != 0 {
        nix_flags.insert(OFlags::DSYNC);
    }
    if fdflags & wasi::__WASI_FDFLAGS_NONBLOCK != 0 {
        nix_flags.insert(OFlags::NONBLOCK);
    }
    if fdflags & wasi::__WASI_FDFLAGS_RSYNC != 0 {
        nix_flags.insert(O_RSYNC);
    }
    if fdflags & wasi::__WASI_FDFLAGS_SYNC != 0 {
        nix_flags.insert(OFlags::SYNC);
    }
    nix_flags
}

pub(crate) fn fdflags_from_nix(oflags: OFlags) -> wasi::__wasi_fdflags_t {
    let mut fdflags = 0;
    if oflags.contains(OFlags::APPEND) {
        fdflags |= wasi::__WASI_FDFLAGS_APPEND;
    }
    if oflags.contains(OFlags::DSYNC) {
        fdflags |= wasi::__WASI_FDFLAGS_DSYNC;
    }
    if oflags.contains(OFlags::NONBLOCK) {
        fdflags |= wasi::__WASI_FDFLAGS_NONBLOCK;
    }
    if oflags.contains(O_RSYNC) {
        fdflags |= wasi::__WASI_FDFLAGS_RSYNC;
    }
    if oflags.contains(OFlags::SYNC) {
        fdflags |= wasi::__WASI_FDFLAGS_SYNC;
    }
    fdflags
}

pub(crate) fn nix_from_oflags(oflags: wasi::__wasi_oflags_t) -> OFlags {
    let mut nix_flags = OFlags::empty();
    if oflags & wasi::__WASI_OFLAGS_CREAT != 0 {
        nix_flags.insert(OFlags::CREAT);
    }
    if oflags & wasi::__WASI_OFLAGS_DIRECTORY != 0 {
        nix_flags.insert(OFlags::DIRECTORY);
    }
    if oflags & wasi::__WASI_OFLAGS_EXCL != 0 {
        nix_flags.insert(OFlags::EXCL);
    }
    if oflags & wasi::__WASI_OFLAGS_TRUNC != 0 {
        nix_flags.insert(OFlags::TRUNC);
    }
    nix_flags
}

pub(crate) fn filestat_from_nix(filestat: libc::stat) -> WasiResult<wasi::__wasi_filestat_t> {
    use std::convert::TryInto;

    fn filestat_to_timestamp(secs: u64, nsecs: u64) -> WasiResult<wasi::__wasi_timestamp_t> {
        secs.checked_mul(1_000_000_000)
            .and_then(|sec_nsec| sec_nsec.checked_add(nsecs))
            .ok_or(WasiError::EOVERFLOW)
    }

    let filetype = yanix::file::FileType::from_stat_st_mode(filestat.st_mode);
    let dev = stdev_from_nix(filestat.st_dev)?;
    let ino = stino_from_nix(filestat.st_ino)?;
    let atim = filestat_to_timestamp(
        filestat.st_atime.try_into()?,
        filestat.st_atime_nsec.try_into()?,
    )?;
    let ctim = filestat_to_timestamp(
        filestat.st_ctime.try_into()?,
        filestat.st_ctime_nsec.try_into()?,
    )?;
    let mtim = filestat_to_timestamp(
        filestat.st_mtime.try_into()?,
        filestat.st_mtime_nsec.try_into()?,
    )?;

    Ok(wasi::__wasi_filestat_t {
        dev,
        ino,
        nlink: stnlink_from_nix(filestat.st_nlink)?,
        size: filestat.st_size as wasi::__wasi_filesize_t,
        atim,
        ctim,
        mtim,
        filetype: FileType::from(filetype).to_wasi(),
    })
}

/// Creates owned WASI path from OS string.
///
/// NB WASI spec requires OS string to be valid UTF-8. Otherwise,
/// `__WASI_ERRNO_ILSEQ` error is returned.
pub(crate) fn path_from_host<S: AsRef<OsStr>>(s: S) -> WasiResult<String> {
    helpers::path_from_slice(s.as_ref().as_bytes()).map(String::from)
}

impl From<yanix::file::FileType> for FileType {
    fn from(ft: yanix::file::FileType) -> Self {
        use yanix::file::FileType::*;
        match ft {
            RegularFile => Self::RegularFile,
            Symlink => Self::Symlink,
            Directory => Self::Directory,
            BlockDevice => Self::BlockDevice,
            CharacterDevice => Self::CharacterDevice,
            /* Unknown | Socket | Fifo */
            _ => Self::Unknown,
            // TODO how to discriminate between STREAM and DGRAM?
            // Perhaps, we should create a more general WASI filetype
            // such as __WASI_FILETYPE_SOCKET, and then it would be
            // up to the client to check whether it's actually
            // STREAM or DGRAM?
        }
    }
}