From 3609a82dc910976197c8424bd13bc6b6493df86a Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Mon, 26 Aug 2019 14:40:59 +0200 Subject: [PATCH] Fix incorrect fd_readdir behaviour * when executed twice in a row, need to manually reset the stream by calling seekdir with __WASI_DIRCOOKIE_START, if __WASI_DIRCOOKIE_START was specified * fix mapping between d_type and __wasi_filetype_t * include minor refactor - removes use of wasm32 module on the host's side --- src/sys/unix/host_impl.rs | 39 +++++++++++++++++++++++++------ src/sys/unix/hostcalls_impl/fs.rs | 34 ++++++++++++++++----------- 2 files changed, 53 insertions(+), 20 deletions(-) diff --git a/src/sys/unix/host_impl.rs b/src/sys/unix/host_impl.rs index 8d736af533..eeecba5bb2 100644 --- a/src/sys/unix/host_impl.rs +++ b/src/sys/unix/host_impl.rs @@ -2,7 +2,7 @@ #![allow(non_camel_case_types)] #![allow(non_snake_case)] #![allow(dead_code)] -use crate::{host, memory, wasm32, Result}; +use crate::{host, memory, Result}; use std::ffi::OsStr; use std::os::unix::prelude::OsStrExt; @@ -228,29 +228,54 @@ pub(crate) fn filestat_from_nix( }) } +pub(crate) fn dirent_filetype_from_host( + host_entry: &nix::libc::dirent, +) -> Result { + match host_entry.d_type { + libc::DT_FIFO => Ok(host::__WASI_FILETYPE_UNKNOWN), + libc::DT_CHR => Ok(host::__WASI_FILETYPE_CHARACTER_DEVICE), + libc::DT_DIR => Ok(host::__WASI_FILETYPE_DIRECTORY), + libc::DT_BLK => Ok(host::__WASI_FILETYPE_BLOCK_DEVICE), + libc::DT_REG => Ok(host::__WASI_FILETYPE_REGULAR_FILE), + libc::DT_LNK => Ok(host::__WASI_FILETYPE_SYMBOLIC_LINK), + libc::DT_SOCK => { + // 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? + Ok(host::__WASI_FILETYPE_UNKNOWN) + } + libc::DT_UNKNOWN => Ok(host::__WASI_FILETYPE_UNKNOWN), + _ => Err(host::__WASI_EINVAL), + } +} + #[cfg(target_os = "linux")] -pub(crate) fn dirent_from_host(host_entry: &nix::libc::dirent) -> Result { - let mut entry = unsafe { std::mem::zeroed::() }; +pub(crate) fn dirent_from_host(host_entry: &nix::libc::dirent) -> Result { + let mut entry = unsafe { std::mem::zeroed::() }; let d_namlen = unsafe { std::ffi::CStr::from_ptr(host_entry.d_name.as_ptr()) } .to_bytes() .len(); if d_namlen > u32::max_value() as usize { return Err(host::__WASI_EIO); } + let d_type = dirent_filetype_from_host(host_entry)?; entry.d_ino = memory::enc_inode(host_entry.d_ino); entry.d_next = memory::enc_dircookie(host_entry.d_off as u64); entry.d_namlen = memory::enc_u32(d_namlen as u32); - entry.d_type = memory::enc_filetype(host_entry.d_type); + entry.d_type = memory::enc_filetype(d_type); Ok(entry) } #[cfg(not(target_os = "linux"))] -pub(crate) fn dirent_from_host(host_entry: &nix::libc::dirent) -> Result { - let mut entry = unsafe { std::mem::zeroed::() }; +pub(crate) fn dirent_from_host(host_entry: &nix::libc::dirent) -> Result { + let mut entry = unsafe { std::mem::zeroed::() }; + let d_type = dirent_filetype_from_host(host_entry)?; entry.d_ino = memory::enc_inode(host_entry.d_ino); entry.d_next = memory::enc_dircookie(host_entry.d_seekoff); entry.d_namlen = memory::enc_u32(u32::from(host_entry.d_namlen)); - entry.d_type = memory::enc_filetype(host_entry.d_type); + entry.d_type = memory::enc_filetype(d_type); Ok(entry) } diff --git a/src/sys/unix/hostcalls_impl/fs.rs b/src/sys/unix/hostcalls_impl/fs.rs index dc9a87e7af..90ce9c217f 100644 --- a/src/sys/unix/hostcalls_impl/fs.rs +++ b/src/sys/unix/hostcalls_impl/fs.rs @@ -5,7 +5,7 @@ use crate::helpers::systemtime_to_timestamp; use crate::hostcalls_impl::PathGet; use crate::sys::errno_from_ioerror; use crate::sys::host_impl; -use crate::{host, wasm32, Result}; +use crate::{host, Result}; use nix::libc::{self, c_long, c_void}; use std::convert::TryInto; use std::ffi::CString; @@ -213,7 +213,7 @@ pub(crate) fn fd_readdir( host_buf: &mut [u8], cookie: host::__wasi_dircookie_t, ) -> Result { - use libc::{dirent, fdopendir, memcpy, readdir_r, seekdir}; + use libc::{dirent, fdopendir, memcpy, readdir_r, rewinddir, seekdir}; let host_buf_ptr = host_buf.as_mut_ptr(); let host_buf_len = host_buf.len(); @@ -221,9 +221,15 @@ pub(crate) fn fd_readdir( if dir.is_null() { return Err(host_impl::errno_from_nix(nix::errno::Errno::last())); } - if cookie != wasm32::__WASI_DIRCOOKIE_START { + + if cookie != host::__WASI_DIRCOOKIE_START { unsafe { seekdir(dir, cookie as c_long) }; + } else { + // If cookie set to __WASI_DIRCOOKIE_START, rewind the dir ptr + // to the start of the stream. + unsafe { rewinddir(dir) }; } + let mut entry_buf = unsafe { std::mem::uninitialized::() }; let mut left = host_buf_len; let mut host_buf_offset: usize = 0; @@ -236,7 +242,7 @@ pub(crate) fn fd_readdir( if host_entry.is_null() { break; } - let entry: wasm32::__wasi_dirent_t = host_impl::dirent_from_host(&unsafe { *host_entry })?; + let entry: host::__wasi_dirent_t = host_impl::dirent_from_host(&unsafe { *host_entry })?; let name_len = entry.d_namlen as usize; let required_space = std::mem::size_of_val(&entry) + name_len; if required_space > left { @@ -244,7 +250,7 @@ pub(crate) fn fd_readdir( } unsafe { let ptr = host_buf_ptr.offset(host_buf_offset as isize) as *mut c_void - as *mut wasm32::__wasi_dirent_t; + as *mut host::__wasi_dirent_t; *ptr = entry; } host_buf_offset += std::mem::size_of_val(&entry); @@ -344,8 +350,8 @@ pub(crate) fn fd_filestat_get_impl(file: &std::fs::File) -> Result Result { - use std::os::unix::fs::FileTypeExt; use nix::sys::socket::{self, SockType}; + use std::os::unix::fs::FileTypeExt; let ftype = metadata.file_type(); if ftype.is_file() { Ok(host::__WASI_FILETYPE_REGULAR_FILE) @@ -360,12 +366,14 @@ fn filetype(file: &File, metadata: &Metadata) -> Result } else if ftype.is_fifo() { Ok(host::__WASI_FILETYPE_SOCKET_STREAM) } else if ftype.is_socket() { - match socket::getsockopt(file.as_raw_fd(), socket::sockopt::SockType).map_err(|err| - err.as_errno().unwrap()).map_err(host_impl::errno_from_nix)? { - SockType::Datagram => Ok(host::__WASI_FILETYPE_SOCKET_DGRAM), - SockType::Stream => Ok(host::__WASI_FILETYPE_SOCKET_STREAM), - _ => Ok(host::__WASI_FILETYPE_UNKNOWN), - } + match socket::getsockopt(file.as_raw_fd(), socket::sockopt::SockType) + .map_err(|err| err.as_errno().unwrap()) + .map_err(host_impl::errno_from_nix)? + { + SockType::Datagram => Ok(host::__WASI_FILETYPE_SOCKET_DGRAM), + SockType::Stream => Ok(host::__WASI_FILETYPE_SOCKET_STREAM), + _ => Ok(host::__WASI_FILETYPE_UNKNOWN), + } } else { Ok(host::__WASI_FILETYPE_UNKNOWN) } @@ -425,7 +433,7 @@ pub(crate) fn path_filestat_set_times( } let atflags = match dirflags { - wasm32::__WASI_LOOKUP_SYMLINK_FOLLOW => UtimensatFlags::FollowSymlink, + host::__WASI_LOOKUP_SYMLINK_FOLLOW => UtimensatFlags::FollowSymlink, _ => UtimensatFlags::NoFollowSymlink, };