mirror of
https://github.com/fluencelabs/wasmer
synced 2024-12-13 06:15:33 +00:00
Merge branch 'master' into feature/tar-install-with-wapm
This commit is contained in:
commit
684720ab3a
@ -5,6 +5,9 @@ All PRs to the Wasmer repository must add to this file.
|
||||
Blocks of changes will separated by version increments.
|
||||
|
||||
## **[Unreleased]**
|
||||
- [#368](https://github.com/wasmerio/wasmer/pull/368) Fix issue with write buffering
|
||||
- [#343](https://github.com/wasmerio/wasmer/pull/343) Implement preopened files for WASI and fix aligment issue when accessing WASI memory
|
||||
- [#367](https://github.com/wasmerio/wasmer/pull/367) Add caching support to the LLVM backend.
|
||||
- [#366](https://github.com/wasmerio/wasmer/pull/366) Remove `UserTrapper` trait to fix [#365](https://github.com/wasmerio/wasmer/issues/365).
|
||||
- [#348](https://github.com/wasmerio/wasmer/pull/348) Refactor internal runtime ↔️ backend abstraction.
|
||||
- [#355](https://github.com/wasmerio/wasmer/pull/355) Misc changes to `Cargo.toml`s for publishing
|
||||
|
@ -27,18 +27,12 @@ impl CacheGenerator {
|
||||
}
|
||||
|
||||
impl CacheGen for CacheGenerator {
|
||||
fn generate_cache(
|
||||
&self,
|
||||
module: &ModuleInner,
|
||||
) -> Result<(Box<ModuleInfo>, Box<[u8]>, Memory), Error> {
|
||||
let info = Box::new(module.info.clone());
|
||||
|
||||
fn generate_cache(&self) -> Result<(Box<[u8]>, Memory), Error> {
|
||||
// Clone the memory to a new location. This could take a long time,
|
||||
// depending on the throughput of your memcpy implementation.
|
||||
let compiled_code = (*self.memory).clone();
|
||||
|
||||
Ok((
|
||||
info,
|
||||
self.backend_cache.into_backend_data()?.into_boxed_slice(),
|
||||
compiled_code,
|
||||
))
|
||||
|
@ -175,21 +175,26 @@ WasmModule::WasmModule(
|
||||
callbacks_t callbacks
|
||||
) : memory_manager(std::unique_ptr<MemoryManager>(new MemoryManager(callbacks)))
|
||||
{
|
||||
object_file = llvm::cantFail(llvm::object::ObjectFile::createObjectFile(llvm::MemoryBufferRef(
|
||||
|
||||
|
||||
if (auto created_object_file = llvm::object::ObjectFile::createObjectFile(llvm::MemoryBufferRef(
|
||||
llvm::StringRef((const char *)object_start, object_size), "object"
|
||||
)));
|
||||
))) {
|
||||
object_file = cantFail(std::move(created_object_file));
|
||||
SymbolLookup symbol_resolver(callbacks);
|
||||
runtime_dyld = std::unique_ptr<llvm::RuntimeDyld>(new llvm::RuntimeDyld(*memory_manager, symbol_resolver));
|
||||
|
||||
SymbolLookup symbol_resolver(callbacks);
|
||||
runtime_dyld = std::unique_ptr<llvm::RuntimeDyld>(new llvm::RuntimeDyld(*memory_manager, symbol_resolver));
|
||||
runtime_dyld->setProcessAllSections(true);
|
||||
|
||||
runtime_dyld->setProcessAllSections(true);
|
||||
runtime_dyld->loadObject(*object_file);
|
||||
runtime_dyld->finalizeWithMemoryManagerLocking();
|
||||
|
||||
runtime_dyld->loadObject(*object_file);
|
||||
runtime_dyld->finalizeWithMemoryManagerLocking();
|
||||
|
||||
if (runtime_dyld->hasError()) {
|
||||
std::cout << "RuntimeDyld error: " << (std::string)runtime_dyld->getErrorString() << std::endl;
|
||||
abort();
|
||||
if (runtime_dyld->hasError()) {
|
||||
_init_failed = true;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
_init_failed = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -152,6 +152,7 @@ struct WasmModule
|
||||
|
||||
void *get_func(llvm::StringRef name) const;
|
||||
|
||||
bool _init_failed = false;
|
||||
private:
|
||||
std::unique_ptr<llvm::RuntimeDyld::MemoryManager> memory_manager;
|
||||
std::unique_ptr<llvm::object::ObjectFile> object_file;
|
||||
@ -164,6 +165,10 @@ extern "C"
|
||||
{
|
||||
*module_out = new WasmModule(mem_ptr, mem_size, callbacks);
|
||||
|
||||
if ((*module_out)->_init_failed) {
|
||||
return RESULT_OBJECT_LOAD_FAILURE;
|
||||
}
|
||||
|
||||
return RESULT_OK;
|
||||
}
|
||||
|
||||
|
@ -13,12 +13,17 @@ use std::{
|
||||
any::Any,
|
||||
ffi::{c_void, CString},
|
||||
mem,
|
||||
ops::Deref,
|
||||
ptr::{self, NonNull},
|
||||
slice, str,
|
||||
sync::Once,
|
||||
sync::{Arc, Once},
|
||||
};
|
||||
use wasmer_runtime_core::{
|
||||
backend::RunnableModule,
|
||||
backend::{
|
||||
sys::{Memory, Protect},
|
||||
CacheGen, RunnableModule,
|
||||
},
|
||||
cache::Error as CacheError,
|
||||
module::ModuleInfo,
|
||||
structures::TypedIndex,
|
||||
typed_func::{Wasm, WasmTrapInfo},
|
||||
@ -203,17 +208,32 @@ fn get_callbacks() -> Callbacks {
|
||||
}
|
||||
}
|
||||
|
||||
pub enum Buffer {
|
||||
LlvmMemory(MemoryBuffer),
|
||||
Memory(Memory),
|
||||
}
|
||||
|
||||
impl Deref for Buffer {
|
||||
type Target = [u8];
|
||||
fn deref(&self) -> &[u8] {
|
||||
match self {
|
||||
Buffer::LlvmMemory(mem_buffer) => mem_buffer.as_slice(),
|
||||
Buffer::Memory(memory) => unsafe { memory.as_slice() },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for LLVMBackend {}
|
||||
unsafe impl Sync for LLVMBackend {}
|
||||
|
||||
pub struct LLVMBackend {
|
||||
module: *mut LLVMModule,
|
||||
#[allow(dead_code)]
|
||||
memory_buffer: MemoryBuffer,
|
||||
buffer: Arc<Buffer>,
|
||||
}
|
||||
|
||||
impl LLVMBackend {
|
||||
pub fn new(module: Module, _intrinsics: Intrinsics) -> Self {
|
||||
pub fn new(module: Module, _intrinsics: Intrinsics) -> (Self, LLVMCache) {
|
||||
Target::initialize_x86(&InitializationConfig {
|
||||
asm_parser: true,
|
||||
asm_printer: true,
|
||||
@ -262,10 +282,44 @@ impl LLVMBackend {
|
||||
panic!("failed to load object")
|
||||
}
|
||||
|
||||
Self {
|
||||
module,
|
||||
memory_buffer,
|
||||
let buffer = Arc::new(Buffer::LlvmMemory(memory_buffer));
|
||||
|
||||
(
|
||||
Self {
|
||||
module,
|
||||
buffer: Arc::clone(&buffer),
|
||||
},
|
||||
LLVMCache { buffer },
|
||||
)
|
||||
}
|
||||
|
||||
pub unsafe fn from_buffer(memory: Memory) -> Result<(Self, LLVMCache), String> {
|
||||
let callbacks = get_callbacks();
|
||||
let mut module: *mut LLVMModule = ptr::null_mut();
|
||||
|
||||
let slice = unsafe { memory.as_slice() };
|
||||
|
||||
let res = module_load(slice.as_ptr(), slice.len(), callbacks, &mut module);
|
||||
|
||||
if res != LLVMResult::OK {
|
||||
return Err("failed to load object".to_string());
|
||||
}
|
||||
|
||||
static SIGNAL_HANDLER_INSTALLED: Once = Once::new();
|
||||
|
||||
SIGNAL_HANDLER_INSTALLED.call_once(|| unsafe {
|
||||
crate::platform::install_signal_handler();
|
||||
});
|
||||
|
||||
let buffer = Arc::new(Buffer::Memory(memory));
|
||||
|
||||
Ok((
|
||||
Self {
|
||||
module,
|
||||
buffer: Arc::clone(&buffer),
|
||||
},
|
||||
LLVMCache { buffer },
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
@ -322,6 +376,28 @@ impl RunnableModule for LLVMBackend {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for LLVMCache {}
|
||||
unsafe impl Sync for LLVMCache {}
|
||||
|
||||
pub struct LLVMCache {
|
||||
buffer: Arc<Buffer>,
|
||||
}
|
||||
|
||||
impl CacheGen for LLVMCache {
|
||||
fn generate_cache(&self) -> Result<(Box<[u8]>, Memory), CacheError> {
|
||||
let mut memory = Memory::with_size_protect(self.buffer.len(), Protect::ReadWrite)
|
||||
.map_err(CacheError::SerializeError)?;
|
||||
|
||||
let buffer = self.buffer.deref();
|
||||
|
||||
unsafe {
|
||||
memory.as_slice_mut()[..buffer.len()].copy_from_slice(buffer);
|
||||
}
|
||||
|
||||
Ok(([].as_ref().into(), memory))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "disasm")]
|
||||
unsafe fn disass_ptr(ptr: *const u8, size: usize, inst_count: usize) {
|
||||
use capstone::arch::BuildsCapstone;
|
||||
|
@ -38,38 +38,27 @@ impl Compiler for LLVMCompiler {
|
||||
let (info, code_reader) = read_info::read_module(wasm, compiler_config).unwrap();
|
||||
let (module, intrinsics) = code::parse_function_bodies(&info, code_reader).unwrap();
|
||||
|
||||
let backend = backend::LLVMBackend::new(module, intrinsics);
|
||||
|
||||
// Create placeholder values here.
|
||||
let cache_gen = {
|
||||
use wasmer_runtime_core::backend::{sys::Memory, CacheGen};
|
||||
use wasmer_runtime_core::cache::Error as CacheError;
|
||||
use wasmer_runtime_core::module::ModuleInfo;
|
||||
|
||||
struct Placeholder;
|
||||
|
||||
impl CacheGen for Placeholder {
|
||||
fn generate_cache(
|
||||
&self,
|
||||
_module: &ModuleInner,
|
||||
) -> Result<(Box<ModuleInfo>, Box<[u8]>, Memory), CacheError> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
Box::new(Placeholder)
|
||||
};
|
||||
let (backend, cache_gen) = backend::LLVMBackend::new(module, intrinsics);
|
||||
|
||||
Ok(ModuleInner {
|
||||
runnable_module: Box::new(backend),
|
||||
cache_gen,
|
||||
cache_gen: Box::new(cache_gen),
|
||||
|
||||
info,
|
||||
})
|
||||
}
|
||||
|
||||
unsafe fn from_cache(&self, _artifact: Artifact, _: Token) -> Result<ModuleInner, CacheError> {
|
||||
unimplemented!("the llvm backend doesn't support caching yet")
|
||||
unsafe fn from_cache(&self, artifact: Artifact, _: Token) -> Result<ModuleInner, CacheError> {
|
||||
let (info, _, memory) = artifact.consume();
|
||||
let (backend, cache_gen) =
|
||||
backend::LLVMBackend::from_buffer(memory).map_err(CacheError::DeserializeError)?;
|
||||
|
||||
Ok(ModuleInner {
|
||||
runnable_module: Box::new(backend),
|
||||
cache_gen: Box::new(cache_gen),
|
||||
|
||||
info,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -123,7 +112,7 @@ fn test_read_module() {
|
||||
|
||||
let (module, intrinsics) = code::parse_function_bodies(&info, code_reader).unwrap();
|
||||
|
||||
let backend = backend::LLVMBackend::new(module, intrinsics);
|
||||
let (backend, _) = backend::LLVMBackend::new(module, intrinsics);
|
||||
|
||||
let func_ptr = backend.get_func(&info, LocalFuncIndex::new(0)).unwrap();
|
||||
|
||||
|
@ -83,8 +83,5 @@ pub trait RunnableModule: Send + Sync {
|
||||
}
|
||||
|
||||
pub trait CacheGen: Send + Sync {
|
||||
fn generate_cache(
|
||||
&self,
|
||||
module: &ModuleInner,
|
||||
) -> Result<(Box<ModuleInfo>, Box<[u8]>, Memory), CacheError>;
|
||||
fn generate_cache(&self) -> Result<(Box<[u8]>, Memory), CacheError>;
|
||||
}
|
||||
|
@ -121,8 +121,12 @@ impl Module {
|
||||
}
|
||||
|
||||
pub fn cache(&self) -> Result<Artifact, CacheError> {
|
||||
let (info, backend_metadata, code) = self.inner.cache_gen.generate_cache(&self.inner)?;
|
||||
Ok(Artifact::from_parts(info, backend_metadata, code))
|
||||
let (backend_metadata, code) = self.inner.cache_gen.generate_cache()?;
|
||||
Ok(Artifact::from_parts(
|
||||
Box::new(self.inner.info.clone()),
|
||||
backend_metadata,
|
||||
code,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn info(&self) -> &ModuleInfo {
|
||||
|
@ -569,10 +569,7 @@ mod vm_ctx_tests {
|
||||
}
|
||||
}
|
||||
impl CacheGen for Placeholder {
|
||||
fn generate_cache(
|
||||
&self,
|
||||
module: &ModuleInner,
|
||||
) -> Result<(Box<ModuleInfo>, Box<[u8]>, Memory), CacheError> {
|
||||
fn generate_cache(&self) -> Result<(Box<[u8]>, Memory), CacheError> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
@ -7,8 +7,6 @@ static WAT: &'static str = r#"
|
||||
(type (;0;) (func (result i32)))
|
||||
(import "env" "do_panic" (func $do_panic (type 0)))
|
||||
(func $dbz (result i32)
|
||||
call $do_panic
|
||||
drop
|
||||
i32.const 42
|
||||
i32.const 0
|
||||
i32.div_u
|
||||
|
@ -36,10 +36,7 @@ use wasmer_runtime_core::{
|
||||
|
||||
struct Placeholder;
|
||||
impl CacheGen for Placeholder {
|
||||
fn generate_cache(
|
||||
&self,
|
||||
_module: &ModuleInner,
|
||||
) -> Result<(Box<ModuleInfo>, Box<[u8]>, Memory), CacheError> {
|
||||
fn generate_cache(&self) -> Result<(Box<[u8]>, Memory), CacheError> {
|
||||
Err(CacheError::Unknown(
|
||||
"the singlepass backend doesn't support caching yet".to_string(),
|
||||
))
|
||||
|
@ -17,7 +17,11 @@ pub use self::utils::is_wasi_module;
|
||||
|
||||
use wasmer_runtime_core::{func, import::ImportObject, imports};
|
||||
|
||||
pub fn generate_import_object(args: Vec<Vec<u8>>, envs: Vec<Vec<u8>>) -> ImportObject {
|
||||
pub fn generate_import_object(
|
||||
args: Vec<Vec<u8>>,
|
||||
envs: Vec<Vec<u8>>,
|
||||
preopened_files: Vec<String>,
|
||||
) -> ImportObject {
|
||||
let state_gen = move || {
|
||||
fn state_destructor(data: *mut c_void) {
|
||||
unsafe {
|
||||
@ -26,7 +30,7 @@ pub fn generate_import_object(args: Vec<Vec<u8>>, envs: Vec<Vec<u8>>) -> ImportO
|
||||
}
|
||||
|
||||
let state = Box::new(WasiState {
|
||||
fs: WasiFs::new().unwrap(),
|
||||
fs: WasiFs::new(&preopened_files).unwrap(),
|
||||
args: &args[..],
|
||||
envs: &envs[..],
|
||||
});
|
||||
|
@ -36,10 +36,12 @@ impl<T: Copy + ValueType> WasmPtr<T, Item> {
|
||||
return Err(__WASI_EFAULT);
|
||||
}
|
||||
unsafe {
|
||||
let cell_ptr = memory
|
||||
.view::<T>()
|
||||
.get_unchecked((self.offset() as usize) / mem::size_of::<T>())
|
||||
as *const _;
|
||||
// clears bits below aligment amount (assumes power of 2) to align pointer
|
||||
let aligner = |ptr: usize, align: usize| ptr & !(align - 1);
|
||||
let cell_ptr = aligner(
|
||||
memory.view::<u8>().as_ptr().add(self.offset as usize) as usize,
|
||||
mem::align_of::<T>(),
|
||||
) as *const Cell<T>;
|
||||
Ok(&*cell_ptr)
|
||||
}
|
||||
}
|
||||
|
@ -7,14 +7,92 @@ use generational_arena::{Arena, Index as Inode};
|
||||
use hashbrown::hash_map::{Entry, HashMap};
|
||||
use std::{
|
||||
cell::Cell,
|
||||
io::{self, Write},
|
||||
fs,
|
||||
io::{self, Read, Seek, Write},
|
||||
time::SystemTime,
|
||||
};
|
||||
use wasmer_runtime_core::debug;
|
||||
use zbox::{init_env as zbox_init_env, File, FileType, OpenOptions, Repo, RepoOpener};
|
||||
use zbox::init_env as zbox_init_env;
|
||||
|
||||
pub const MAX_SYMLINKS: usize = 100;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum WasiFile {
|
||||
#[allow(dead_code)]
|
||||
ZboxFile(zbox::File),
|
||||
HostFile(fs::File),
|
||||
}
|
||||
|
||||
impl Write for WasiFile {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
match self {
|
||||
WasiFile::ZboxFile(zbf) => zbf.write(buf),
|
||||
WasiFile::HostFile(hf) => hf.write(buf),
|
||||
}
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
match self {
|
||||
WasiFile::ZboxFile(zbf) => zbf.flush(),
|
||||
WasiFile::HostFile(hf) => hf.flush(),
|
||||
}
|
||||
}
|
||||
|
||||
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
|
||||
match self {
|
||||
WasiFile::ZboxFile(zbf) => zbf.write_all(buf),
|
||||
WasiFile::HostFile(hf) => hf.write_all(buf),
|
||||
}
|
||||
}
|
||||
|
||||
fn write_fmt(&mut self, fmt: ::std::fmt::Arguments) -> io::Result<()> {
|
||||
match self {
|
||||
WasiFile::ZboxFile(zbf) => zbf.write_fmt(fmt),
|
||||
WasiFile::HostFile(hf) => hf.write_fmt(fmt),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Read for WasiFile {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
match self {
|
||||
WasiFile::ZboxFile(zbf) => zbf.read(buf),
|
||||
WasiFile::HostFile(hf) => hf.read(buf),
|
||||
}
|
||||
}
|
||||
|
||||
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
|
||||
match self {
|
||||
WasiFile::ZboxFile(zbf) => zbf.read_to_end(buf),
|
||||
WasiFile::HostFile(hf) => hf.read_to_end(buf),
|
||||
}
|
||||
}
|
||||
|
||||
fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
|
||||
match self {
|
||||
WasiFile::ZboxFile(zbf) => zbf.read_to_string(buf),
|
||||
WasiFile::HostFile(hf) => hf.read_to_string(buf),
|
||||
}
|
||||
}
|
||||
|
||||
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
|
||||
match self {
|
||||
WasiFile::ZboxFile(zbf) => zbf.read_exact(buf),
|
||||
WasiFile::HostFile(hf) => hf.read_exact(buf),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Seek for WasiFile {
|
||||
fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
|
||||
match self {
|
||||
WasiFile::ZboxFile(zbf) => zbf.seek(pos),
|
||||
WasiFile::HostFile(hf) => hf.seek(pos),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct InodeVal {
|
||||
pub stat: __wasi_filestat_t,
|
||||
pub is_preopened: bool,
|
||||
@ -22,13 +100,57 @@ pub struct InodeVal {
|
||||
pub kind: Kind,
|
||||
}
|
||||
|
||||
impl InodeVal {
|
||||
// TODO: clean this up
|
||||
pub fn from_file_metadata(
|
||||
metadata: &std::fs::Metadata,
|
||||
name: String,
|
||||
is_preopened: bool,
|
||||
kind: Kind,
|
||||
) -> Self {
|
||||
InodeVal {
|
||||
stat: __wasi_filestat_t {
|
||||
st_filetype: if metadata.is_dir() {
|
||||
__WASI_FILETYPE_DIRECTORY
|
||||
} else {
|
||||
__WASI_FILETYPE_REGULAR_FILE
|
||||
},
|
||||
st_size: metadata.len(),
|
||||
st_atim: metadata
|
||||
.accessed()
|
||||
.ok()
|
||||
.and_then(|sys_time| sys_time.duration_since(SystemTime::UNIX_EPOCH).ok())
|
||||
.map(|duration| duration.as_nanos() as u64)
|
||||
.unwrap_or(0),
|
||||
st_ctim: metadata
|
||||
.created()
|
||||
.ok()
|
||||
.and_then(|sys_time| sys_time.duration_since(SystemTime::UNIX_EPOCH).ok())
|
||||
.map(|duration| duration.as_nanos() as u64)
|
||||
.unwrap_or(0),
|
||||
st_mtim: metadata
|
||||
.modified()
|
||||
.ok()
|
||||
.and_then(|sys_time| sys_time.duration_since(SystemTime::UNIX_EPOCH).ok())
|
||||
.map(|duration| duration.as_nanos() as u64)
|
||||
.unwrap_or(0),
|
||||
..__wasi_filestat_t::default()
|
||||
},
|
||||
is_preopened,
|
||||
name,
|
||||
kind,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
pub enum Kind {
|
||||
File {
|
||||
handle: File,
|
||||
handle: WasiFile,
|
||||
},
|
||||
Dir {
|
||||
handle: File,
|
||||
handle: WasiFile,
|
||||
/// The entries of a directory are lazily filled.
|
||||
entries: HashMap<String, Inode>,
|
||||
},
|
||||
@ -40,7 +162,7 @@ pub enum Kind {
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Fd {
|
||||
pub rights: __wasi_rights_t,
|
||||
pub rights_inheriting: __wasi_rights_t,
|
||||
@ -50,7 +172,7 @@ pub struct Fd {
|
||||
}
|
||||
|
||||
pub struct WasiFs {
|
||||
// pub repo: Repo,
|
||||
//pub repo: Repo,
|
||||
pub name_map: HashMap<String, Inode>,
|
||||
pub inodes: Arena<InodeVal>,
|
||||
pub fd_map: HashMap<u32, Fd>,
|
||||
@ -59,33 +181,63 @@ pub struct WasiFs {
|
||||
}
|
||||
|
||||
impl WasiFs {
|
||||
pub fn new() -> Result<Self, String> {
|
||||
pub fn new(preopened_files: &[String]) -> Result<Self, String> {
|
||||
debug!("wasi::fs::init");
|
||||
zbox_init_env();
|
||||
debug!("wasi::fs::repo");
|
||||
// let repo = RepoOpener::new()
|
||||
// .create(true)
|
||||
// .open("mem://wasmer-test-fs", "")
|
||||
// .map_err(|e| e.to_string())?;
|
||||
/*let repo = RepoOpener::new()
|
||||
.create(true)
|
||||
.open("mem://wasmer-test-fs", "")
|
||||
.map_err(|e| e.to_string())?;*/
|
||||
debug!("wasi::fs::inodes");
|
||||
let inodes = Arena::new();
|
||||
let res = Ok(Self {
|
||||
// repo: repo,
|
||||
let mut wasi_fs = Self {
|
||||
//repo: repo,
|
||||
name_map: HashMap::new(),
|
||||
inodes: inodes,
|
||||
fd_map: HashMap::new(),
|
||||
next_fd: Cell::new(3),
|
||||
inode_counter: Cell::new(1000),
|
||||
});
|
||||
};
|
||||
for file in preopened_files {
|
||||
debug!("Attempting to preopen {}", &file);
|
||||
// TODO: think about this
|
||||
let default_rights = 0x1FFFFFFF; // all rights
|
||||
let cur_file: fs::File = fs::OpenOptions::new()
|
||||
.read(true)
|
||||
.open(file)
|
||||
.expect("Could not find file");
|
||||
let cur_file_metadata = cur_file.metadata().unwrap();
|
||||
let kind = if cur_file_metadata.is_dir() {
|
||||
Kind::Dir {
|
||||
handle: WasiFile::HostFile(cur_file),
|
||||
entries: Default::default(),
|
||||
}
|
||||
} else {
|
||||
return Err(format!(
|
||||
"WASI only supports pre-opened directories right now; found \"{}\"",
|
||||
file
|
||||
));
|
||||
};
|
||||
// TODO: handle nested pats in `file`
|
||||
let inode_val =
|
||||
InodeVal::from_file_metadata(&cur_file_metadata, file.clone(), true, kind);
|
||||
|
||||
let inode = wasi_fs.inodes.insert(inode_val);
|
||||
wasi_fs.inodes[inode].stat.st_ino = wasi_fs.inode_counter.get();
|
||||
wasi_fs
|
||||
.create_fd(default_rights, default_rights, 0, inode)
|
||||
.expect("Could not open fd");
|
||||
}
|
||||
debug!("wasi::fs::end");
|
||||
res
|
||||
Ok(wasi_fs)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn get_inode(&mut self, path: &str) -> Option<Inode> {
|
||||
Some(match self.name_map.entry(path.to_string()) {
|
||||
Entry::Occupied(o) => *o.get(),
|
||||
Entry::Vacant(v) => {
|
||||
Entry::Vacant(_v) => {
|
||||
return None;
|
||||
// let file = if let Ok(file) = OpenOptions::new()
|
||||
// .read(true)
|
||||
@ -195,6 +347,8 @@ impl WasiFs {
|
||||
pub fn fdstat(&self, fd: __wasi_fd_t) -> Result<__wasi_fdstat_t, __wasi_errno_t> {
|
||||
let fd = self.fd_map.get(&fd).ok_or(__WASI_EBADF)?;
|
||||
|
||||
debug!("fdstat: {:?}", fd);
|
||||
|
||||
Ok(__wasi_fdstat_t {
|
||||
fs_filetype: match self.inodes[fd.inode].kind {
|
||||
Kind::File { .. } => __WASI_FILETYPE_REGULAR_FILE,
|
||||
@ -204,20 +358,22 @@ impl WasiFs {
|
||||
},
|
||||
fs_flags: fd.flags,
|
||||
fs_rights_base: fd.rights,
|
||||
fs_rights_inheriting: fd.rights, // TODO(lachlan): Is this right?
|
||||
fs_rights_inheriting: fd.rights_inheriting, // TODO(lachlan): Is this right?
|
||||
})
|
||||
}
|
||||
|
||||
pub fn prestat_fd(&self, fd: __wasi_fd_t) -> Result<__wasi_prestat_t, __wasi_errno_t> {
|
||||
let fd = self.fd_map.get(&fd).ok_or(__WASI_EBADF)?;
|
||||
|
||||
debug!("in prestat_fd {:?}", fd);
|
||||
let inode_val = &self.inodes[fd.inode];
|
||||
|
||||
if inode_val.is_preopened {
|
||||
Ok(__wasi_prestat_t {
|
||||
pr_type: __WASI_PREOPENTYPE_DIR,
|
||||
u: PrestatEnum::Dir {
|
||||
pr_name_len: inode_val.name.len() as u32,
|
||||
// REVIEW:
|
||||
pr_name_len: inode_val.name.len() as u32 + 1,
|
||||
}
|
||||
.untagged(),
|
||||
})
|
||||
|
@ -8,11 +8,11 @@ pub mod windows;
|
||||
use self::types::*;
|
||||
use crate::{
|
||||
ptr::{Array, WasmPtr},
|
||||
state::{Fd, Kind, WasiState, MAX_SYMLINKS},
|
||||
state::{Fd, InodeVal, Kind, WasiFile, WasiState, MAX_SYMLINKS},
|
||||
};
|
||||
use rand::{thread_rng, Rng};
|
||||
use std::cell::Cell;
|
||||
use std::io::{self, Read, Write};
|
||||
use std::io::{self, Read, Seek, Write};
|
||||
use wasmer_runtime_core::{debug, memory::Memory, vm::Ctx};
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
@ -37,11 +37,15 @@ fn write_bytes<T: Write>(
|
||||
let bytes = iov_inner.buf.deref(memory, 0, iov_inner.buf_len)?;
|
||||
write_loc
|
||||
.write(&bytes.iter().map(|b_cell| b_cell.get()).collect::<Vec<u8>>())
|
||||
.map_err(|_| __WASI_EIO)?;
|
||||
.map_err(|_| {
|
||||
write_loc.flush();
|
||||
__WASI_EIO
|
||||
})?;
|
||||
|
||||
// TODO: handle failure more accurately
|
||||
bytes_written += iov_inner.buf_len;
|
||||
}
|
||||
write_loc.flush();
|
||||
Ok(bytes_written)
|
||||
}
|
||||
|
||||
@ -324,18 +328,21 @@ pub fn fd_datasync(ctx: &mut Ctx, fd: __wasi_fd_t) -> __wasi_errno_t {
|
||||
pub fn fd_fdstat_get(
|
||||
ctx: &mut Ctx,
|
||||
fd: __wasi_fd_t,
|
||||
buf: WasmPtr<__wasi_fdstat_t>,
|
||||
buf_ptr: WasmPtr<__wasi_fdstat_t>,
|
||||
) -> __wasi_errno_t {
|
||||
debug!("wasi::fd_fdstat_get: fd={}", fd);
|
||||
debug!(
|
||||
"wasi::fd_fdstat_get: fd={}, buf_ptr={}",
|
||||
fd,
|
||||
buf_ptr.offset()
|
||||
);
|
||||
let mut state = get_wasi_state(ctx);
|
||||
let memory = ctx.memory(0);
|
||||
|
||||
let stat = wasi_try!(state.fs.fdstat(fd));
|
||||
let buf = wasi_try!(buf_ptr.deref(memory));
|
||||
|
||||
let buf = wasi_try!(buf.deref(memory));
|
||||
buf.set(stat);
|
||||
|
||||
__WASI_EFAULT
|
||||
__WASI_ESUCCESS
|
||||
}
|
||||
|
||||
/// ### `fd_fdstat_set_flags()`
|
||||
@ -532,27 +539,36 @@ pub fn fd_prestat_dir_name(
|
||||
fd, path_len
|
||||
);
|
||||
let memory = ctx.memory(0);
|
||||
let path_chars = wasi_try!(path.deref(memory, 0, path_len));
|
||||
|
||||
let state = get_wasi_state(ctx);
|
||||
let real_fd = wasi_try!(state.fs.fd_map.get(&fd).ok_or(__WASI_EBADF));
|
||||
let inode_val = &state.fs.inodes[real_fd.inode];
|
||||
|
||||
// check inode-val.is_preopened?
|
||||
|
||||
if let Kind::Dir { .. } = inode_val.kind {
|
||||
// TODO: verify this: null termination, etc
|
||||
if inode_val.name.len() <= path_len as usize {
|
||||
let mut i = 0;
|
||||
for c in inode_val.name.bytes() {
|
||||
path_chars[i].set(c);
|
||||
i += 1
|
||||
}
|
||||
path_chars[i].set(0);
|
||||
|
||||
debug!(
|
||||
"=> result: \"{}\"",
|
||||
::std::str::from_utf8(unsafe { &*(&path_chars[..] as *const [_] as *const [u8]) })
|
||||
.unwrap()
|
||||
);
|
||||
|
||||
if let Ok(path_chars) = path.deref(memory, 0, path_len) {
|
||||
debug!(
|
||||
"=> path: {}",
|
||||
path_chars
|
||||
.iter()
|
||||
.map(|c| c.get() as char)
|
||||
.collect::<String>()
|
||||
);
|
||||
if true
|
||||
/* check if dir */
|
||||
{
|
||||
// get name
|
||||
// write name
|
||||
// if overflow __WASI_EOVERFLOW
|
||||
__WASI_ESUCCESS
|
||||
} else {
|
||||
__WASI_ENOTDIR
|
||||
__WASI_EOVERFLOW
|
||||
}
|
||||
} else {
|
||||
__WASI_EFAULT
|
||||
__WASI_ENOTDIR
|
||||
}
|
||||
}
|
||||
|
||||
@ -612,7 +628,7 @@ pub fn fd_pwrite(
|
||||
|
||||
let bytes_written = match &mut inode.kind {
|
||||
Kind::File { handle } => {
|
||||
// TODO: adjust by offset
|
||||
handle.seek(::std::io::SeekFrom::Start(offset as u64));
|
||||
wasi_try!(write_bytes(handle, memory, iovs_arr_cell))
|
||||
}
|
||||
Kind::Dir { .. } => {
|
||||
@ -699,7 +715,10 @@ pub fn fd_read(
|
||||
let inode = &mut state.fs.inodes[fd_entry.inode];
|
||||
|
||||
let bytes_read = match &mut inode.kind {
|
||||
Kind::File { handle } => wasi_try!(read_bytes(handle, memory, iovs_arr_cell)),
|
||||
Kind::File { handle } => {
|
||||
handle.seek(::std::io::SeekFrom::Start(offset as u64));
|
||||
wasi_try!(read_bytes(handle, memory, iovs_arr_cell))
|
||||
}
|
||||
Kind::Dir { .. } => {
|
||||
// TODO: verify
|
||||
return __WASI_EISDIR;
|
||||
@ -798,7 +817,7 @@ pub fn fd_seek(
|
||||
whence: __wasi_whence_t,
|
||||
newoffset: WasmPtr<__wasi_filesize_t>,
|
||||
) -> __wasi_errno_t {
|
||||
debug!("wasi::fd_seek: fd={}", fd);
|
||||
debug!("wasi::fd_seek: fd={}, offset={}", fd, offset);
|
||||
let memory = ctx.memory(0);
|
||||
let state = get_wasi_state(ctx);
|
||||
let new_offset_cell = wasi_try!(newoffset.deref(memory));
|
||||
@ -830,7 +849,7 @@ pub fn fd_seek(
|
||||
/// Errors:
|
||||
/// TODO: figure out which errors this should return
|
||||
/// - `__WASI_EPERM`
|
||||
/// - `__WAIS_ENOTCAPABLE`
|
||||
/// - `__WASI_ENOTCAPABLE`
|
||||
pub fn fd_sync(ctx: &mut Ctx, fd: __wasi_fd_t) -> __wasi_errno_t {
|
||||
debug!("wasi::fd_sync");
|
||||
// TODO: check __WASI_RIGHT_FD_SYNC
|
||||
@ -920,7 +939,11 @@ pub fn fd_write(
|
||||
let inode = &mut state.fs.inodes[fd_entry.inode];
|
||||
|
||||
let bytes_written = match &mut inode.kind {
|
||||
Kind::File { handle } => wasi_try!(write_bytes(handle, memory, iovs_arr_cell)),
|
||||
Kind::File { handle } => {
|
||||
handle.seek(::std::io::SeekFrom::Start(offset as u64));
|
||||
|
||||
wasi_try!(write_bytes(handle, memory, iovs_arr_cell))
|
||||
}
|
||||
Kind::Dir { .. } => {
|
||||
// TODO: verify
|
||||
return __WASI_EISDIR;
|
||||
@ -1030,7 +1053,9 @@ pub fn path_filestat_get(
|
||||
return __WASI_ELOOP;
|
||||
}
|
||||
}
|
||||
_ => return __WASI_ENOTDIR,
|
||||
_ => {
|
||||
return __WASI_ENOTDIR;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1142,13 +1167,11 @@ pub fn path_open(
|
||||
) -> __wasi_errno_t {
|
||||
debug!("wasi::path_open");
|
||||
let memory = ctx.memory(0);
|
||||
if path_len > 1024
|
||||
/* TODO: find actual upper bound on name size (also this is a path, not a name :think-fish:) */
|
||||
{
|
||||
if path_len > 1024 * 1024 {
|
||||
return __WASI_ENAMETOOLONG;
|
||||
}
|
||||
|
||||
// check for __WASI_RIGHT_PATH_OPEN somewhere, probably via dirfd
|
||||
let fd_cell = wasi_try!(fd.deref(memory));
|
||||
let path_cells = wasi_try!(path.deref(memory, 0, path_len));
|
||||
let state = get_wasi_state(ctx);
|
||||
@ -1161,85 +1184,182 @@ pub fn path_open(
|
||||
|
||||
let working_dir = wasi_try!(state.fs.fd_map.get(&dirfd).ok_or(__WASI_EBADF));
|
||||
|
||||
// ASSUMPTION: open rights cascade down
|
||||
// ASSUMPTION: open rights apply recursively
|
||||
if !has_rights(working_dir.rights, __WASI_RIGHT_PATH_OPEN) {
|
||||
return __WASI_EACCES;
|
||||
}
|
||||
|
||||
let path_vec =
|
||||
let path_string =
|
||||
wasi_try!(
|
||||
::std::str::from_utf8(unsafe { &*(path_cells as *const [_] as *const [u8]) })
|
||||
std::str::from_utf8(unsafe { &*(path_cells as *const [_] as *const [u8]) })
|
||||
.map_err(|_| __WASI_EINVAL)
|
||||
)
|
||||
.split('/')
|
||||
.map(|str| str.to_string())
|
||||
.collect::<Vec<String>>();
|
||||
);
|
||||
let path = std::path::PathBuf::from(path_string);
|
||||
let path_vec = wasi_try!(path
|
||||
.components()
|
||||
.map(|comp| {
|
||||
comp.as_os_str()
|
||||
.to_str()
|
||||
.map(|inner_str| inner_str.to_string())
|
||||
.ok_or(__WASI_EINVAL)
|
||||
})
|
||||
.collect::<Result<Vec<String>, __wasi_errno_t>>());
|
||||
debug!("Path vec: {:#?}", path_vec);
|
||||
|
||||
if path_vec.is_empty() {
|
||||
return __WASI_EINVAL;
|
||||
}
|
||||
|
||||
let working_dir_inode = &mut state.fs.inodes[working_dir.inode];
|
||||
let mut cur_dir_inode = working_dir.inode;
|
||||
let mut cumulative_path = std::path::PathBuf::from(".");
|
||||
|
||||
let mut cur_dir = working_dir;
|
||||
|
||||
// TODO: refactor single path segment logic out and do traversing before
|
||||
// as necessary
|
||||
let out_fd = if path_vec.len() == 1 {
|
||||
// just the file or dir
|
||||
if let Kind::Dir { entries, .. } = &mut working_dir_inode.kind {
|
||||
if let Some(child) = entries.get(&path_vec[0]).cloned() {
|
||||
let child_inode_val = &state.fs.inodes[child];
|
||||
// early return based on flags
|
||||
if o_flags & __WASI_O_EXCL != 0 {
|
||||
return __WASI_EEXIST;
|
||||
}
|
||||
if o_flags & __WASI_O_DIRECTORY != 0 {
|
||||
match &child_inode_val.kind {
|
||||
Kind::Dir { .. } => (),
|
||||
Kind::Symlink { .. } => unimplemented!(),
|
||||
_ => return __WASI_ENOTDIR,
|
||||
}
|
||||
}
|
||||
// do logic on child
|
||||
wasi_try!(state
|
||||
.fs
|
||||
.create_fd(fs_rights_base, fs_rights_inheriting, fs_flags, child))
|
||||
} else {
|
||||
// entry does not exist in parent directory
|
||||
// check to see if we should create it
|
||||
if o_flags & __WASI_O_CREAT != 0 {
|
||||
// insert in to directory and set values
|
||||
//entries.insert(path_segment[0], )
|
||||
unimplemented!()
|
||||
} else {
|
||||
// no entry and can't create it
|
||||
return __WASI_ENOENT;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// working_dir is not a directory
|
||||
return __WASI_ENOTDIR;
|
||||
}
|
||||
} else {
|
||||
// traverse the pieces of the path
|
||||
// TODO: lots of testing on this
|
||||
// traverse path
|
||||
if path_vec.len() > 1 {
|
||||
for path_segment in &path_vec[..(path_vec.len() - 1)] {
|
||||
match &working_dir_inode.kind {
|
||||
match &state.fs.inodes[cur_dir_inode].kind {
|
||||
Kind::Dir { entries, .. } => {
|
||||
if let Some(child) = entries.get(path_segment) {
|
||||
unimplemented!();
|
||||
let inode_val = *child;
|
||||
cur_dir_inode = inode_val;
|
||||
} else {
|
||||
// Is __WASI_O_FLAG_CREAT recursive?
|
||||
// ASSUMPTION: it's not
|
||||
return __WASI_EINVAL;
|
||||
// attempt to lazily load or create
|
||||
if path_segment == ".." {
|
||||
unimplemented!(
|
||||
"\"..\" in paths in `path_open` has not been implemented yet"
|
||||
);
|
||||
}
|
||||
// lazily load
|
||||
cumulative_path.push(path_segment);
|
||||
let mut open_options = std::fs::OpenOptions::new();
|
||||
let open_options = open_options.read(true);
|
||||
// ASSUMPTION: __WASI_O_CREAT applies recursively
|
||||
let open_options = if o_flags & __WASI_O_CREAT != 0 {
|
||||
open_options.create(true)
|
||||
} else {
|
||||
open_options
|
||||
};
|
||||
// TODO: handle __WASI_O_TRUNC on directories
|
||||
|
||||
let cur_dir = wasi_try!(open_options
|
||||
.open(&cumulative_path)
|
||||
.map_err(|_| __WASI_EINVAL));
|
||||
|
||||
// TODO: refactor and reuse
|
||||
let cur_file_metadata = cur_dir.metadata().unwrap();
|
||||
let kind = if cur_file_metadata.is_dir() {
|
||||
Kind::Dir {
|
||||
handle: WasiFile::HostFile(cur_dir),
|
||||
entries: Default::default(),
|
||||
}
|
||||
} else {
|
||||
return __WASI_ENOTDIR;
|
||||
};
|
||||
let inode_val = InodeVal::from_file_metadata(
|
||||
&cur_file_metadata,
|
||||
path_segment.clone(),
|
||||
false,
|
||||
kind,
|
||||
);
|
||||
|
||||
let new_inode = state.fs.inodes.insert(inode_val);
|
||||
let inode_idx = state.fs.inode_counter.get();
|
||||
state.fs.inode_counter.replace(inode_idx + 1);
|
||||
// reborrow to insert entry
|
||||
if let Kind::Dir { entries, .. } = &mut state.fs.inodes[cur_dir_inode].kind
|
||||
{
|
||||
assert!(entries.insert(path_segment.clone(), new_inode).is_none());
|
||||
state.fs.inodes[new_inode].stat.st_ino = state.fs.inode_counter.get();
|
||||
cur_dir_inode = new_inode;
|
||||
}
|
||||
}
|
||||
}
|
||||
Kind::Symlink { .. } => unimplemented!(),
|
||||
Kind::Symlink { .. } => unimplemented!("Symlinks not yet supported in `path_open`"),
|
||||
_ => return __WASI_ENOTDIR,
|
||||
}
|
||||
}
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
let file_name = path_vec.last().unwrap();
|
||||
|
||||
debug!(
|
||||
"Looking for file {} in directory {:#?}",
|
||||
file_name, cumulative_path
|
||||
);
|
||||
cumulative_path.push(file_name);
|
||||
let file_path = cumulative_path;
|
||||
|
||||
let out_fd = if let Kind::Dir { entries, .. } = &mut state.fs.inodes[cur_dir_inode].kind {
|
||||
if let Some(child) = entries.get(file_name).cloned() {
|
||||
let child_inode_val = &state.fs.inodes[child];
|
||||
// early return based on flags
|
||||
if o_flags & __WASI_O_EXCL != 0 {
|
||||
return __WASI_EEXIST;
|
||||
}
|
||||
if o_flags & __WASI_O_DIRECTORY != 0 {
|
||||
match &child_inode_val.kind {
|
||||
Kind::Dir { .. } => (),
|
||||
Kind::Symlink { .. } => {
|
||||
unimplemented!("Symlinks not yet supported in path_open")
|
||||
}
|
||||
_ => return __WASI_ENOTDIR,
|
||||
}
|
||||
}
|
||||
// do logic on child
|
||||
wasi_try!(state
|
||||
.fs
|
||||
.create_fd(fs_rights_base, fs_rights_inheriting, fs_flags, child))
|
||||
} else {
|
||||
// if entry does not exist in parent directory, try to lazily
|
||||
// load it; possibly creating or truncating it if flags set
|
||||
let real_opened_file = {
|
||||
let mut open_options = std::fs::OpenOptions::new();
|
||||
let open_options = open_options.read(true).write(true);
|
||||
let open_options = if o_flags & __WASI_O_CREAT != 0 {
|
||||
debug!(
|
||||
"File {} may be created when opened if it does not exist",
|
||||
&path_string
|
||||
);
|
||||
open_options.create(true)
|
||||
} else {
|
||||
open_options
|
||||
};
|
||||
let open_options = if o_flags & __WASI_O_TRUNC != 0 {
|
||||
debug!("File {} will be truncated when opened", &path_string);
|
||||
open_options.truncate(true)
|
||||
} else {
|
||||
open_options
|
||||
};
|
||||
let real_open_file =
|
||||
wasi_try!(open_options.open(&file_path).map_err(|_| __WASI_EIO));
|
||||
debug!("Opening host file {}", &path_string);
|
||||
|
||||
real_open_file
|
||||
};
|
||||
// record lazily loaded or newly created fd
|
||||
let new_inode = state.fs.inodes.insert(InodeVal {
|
||||
stat: __wasi_filestat_t::default(),
|
||||
is_preopened: false,
|
||||
name: file_name.clone(),
|
||||
kind: Kind::File {
|
||||
handle: WasiFile::HostFile(real_opened_file),
|
||||
},
|
||||
});
|
||||
// reborrow to insert entry
|
||||
if let Kind::Dir { entries, .. } = &mut state.fs.inodes[working_dir.inode].kind {
|
||||
entries.insert(file_name.clone(), new_inode);
|
||||
}
|
||||
let new_fd = wasi_try!(state.fs.create_fd(
|
||||
fs_rights_base,
|
||||
fs_rights_inheriting,
|
||||
fs_flags,
|
||||
new_inode,
|
||||
));
|
||||
|
||||
new_fd
|
||||
}
|
||||
} else {
|
||||
// working_dir did not match on Kind::Dir
|
||||
return __WASI_ENOTDIR;
|
||||
};
|
||||
|
||||
fd_cell.set(out_fd);
|
||||
|
@ -42,84 +42,84 @@ pub struct __wasi_dirent_t {
|
||||
pub d_type: __wasi_filetype_t,
|
||||
}
|
||||
|
||||
pub type __wasi_errno_t = u16;
|
||||
pub const __WASI_ESUCCESS: u16 = 0;
|
||||
pub const __WASI_E2BIG: u16 = 1;
|
||||
pub const __WASI_EACCES: u16 = 2;
|
||||
pub const __WASI_EADDRINUSE: u16 = 3;
|
||||
pub const __WASI_EADDRNOTAVAIL: u16 = 4;
|
||||
pub const __WASI_EAFNOSUPPORT: u16 = 5;
|
||||
pub const __WASI_EAGAIN: u16 = 6;
|
||||
pub const __WASI_EALREADY: u16 = 7;
|
||||
pub const __WASI_EBADF: u16 = 8;
|
||||
pub const __WASI_EBADMSG: u16 = 9;
|
||||
pub const __WASI_EBUSY: u16 = 10;
|
||||
pub const __WASI_ECANCELED: u16 = 11;
|
||||
pub const __WASI_ECHILD: u16 = 12;
|
||||
pub const __WASI_ECONNABORTED: u16 = 13;
|
||||
pub const __WASI_ECONNREFUSED: u16 = 14;
|
||||
pub const __WASI_ECONNRESET: u16 = 15;
|
||||
pub const __WASI_EDEADLK: u16 = 16;
|
||||
pub const __WASI_EDESTADDRREQ: u16 = 17;
|
||||
pub const __WASI_EDOM: u16 = 18;
|
||||
pub const __WASI_EDQUOT: u16 = 19;
|
||||
pub const __WASI_EEXIST: u16 = 20;
|
||||
pub const __WASI_EFAULT: u16 = 21;
|
||||
pub const __WASI_EFBIG: u16 = 22;
|
||||
pub const __WASI_EHOSTUNREACH: u16 = 23;
|
||||
pub const __WASI_EIDRM: u16 = 24;
|
||||
pub const __WASI_EILSEQ: u16 = 25;
|
||||
pub const __WASI_EINPROGRESS: u16 = 26;
|
||||
pub const __WASI_EINTR: u16 = 27;
|
||||
pub const __WASI_EINVAL: u16 = 28;
|
||||
pub const __WASI_EIO: u16 = 29;
|
||||
pub const __WASI_EISCONN: u16 = 30;
|
||||
pub const __WASI_EISDIR: u16 = 31;
|
||||
pub const __WASI_ELOOP: u16 = 32;
|
||||
pub const __WASI_EMFILE: u16 = 33;
|
||||
pub const __WASI_EMLINK: u16 = 34;
|
||||
pub const __WASI_EMSGSIZE: u16 = 35;
|
||||
pub const __WASI_EMULTIHOP: u16 = 36;
|
||||
pub const __WASI_ENAMETOOLONG: u16 = 37;
|
||||
pub const __WASI_ENETDOWN: u16 = 38;
|
||||
pub const __WASI_ENETRESET: u16 = 39;
|
||||
pub const __WASI_ENETUNREACH: u16 = 40;
|
||||
pub const __WASI_ENFILE: u16 = 41;
|
||||
pub const __WASI_ENOBUFS: u16 = 42;
|
||||
pub const __WASI_ENODEV: u16 = 43;
|
||||
pub const __WASI_ENOENT: u16 = 44;
|
||||
pub const __WASI_ENOEXEC: u16 = 45;
|
||||
pub const __WASI_ENOLCK: u16 = 46;
|
||||
pub const __WASI_ENOLINK: u16 = 47;
|
||||
pub const __WASI_ENOMEM: u16 = 48;
|
||||
pub const __WASI_ENOMSG: u16 = 49;
|
||||
pub const __WASI_ENOPROTOOPT: u16 = 50;
|
||||
pub const __WASI_ENOSPC: u16 = 51;
|
||||
pub const __WASI_ENOSYS: u16 = 52;
|
||||
pub const __WASI_ENOTCONN: u16 = 53;
|
||||
pub const __WASI_ENOTDIR: u16 = 54;
|
||||
pub const __WASI_ENOTEMPTY: u16 = 55;
|
||||
pub const __WASI_ENOTRECOVERABLE: u16 = 56;
|
||||
pub const __WASI_ENOTSOCK: u16 = 57;
|
||||
pub const __WASI_ENOTSUP: u16 = 58;
|
||||
pub const __WASI_ENOTTY: u16 = 59;
|
||||
pub const __WASI_ENXIO: u16 = 60;
|
||||
pub const __WASI_EOVERFLOW: u16 = 61;
|
||||
pub const __WASI_EOWNERDEAD: u16 = 62;
|
||||
pub const __WASI_EPERM: u16 = 63;
|
||||
pub const __WASI_EPIPE: u16 = 64;
|
||||
pub const __WASI_EPROTO: u16 = 65;
|
||||
pub const __WASI_EPROTONOSUPPORT: u16 = 66;
|
||||
pub const __WASI_EPROTOTYPE: u16 = 67;
|
||||
pub const __WASI_ERANGE: u16 = 68;
|
||||
pub const __WASI_EROFS: u16 = 69;
|
||||
pub const __WASI_ESPIPE: u16 = 70;
|
||||
pub const __WASI_ESRCH: u16 = 71;
|
||||
pub const __WASI_ESTALE: u16 = 72;
|
||||
pub const __WASI_ETIMEDOUT: u16 = 73;
|
||||
pub const __WASI_ETXTBSY: u16 = 74;
|
||||
pub const __WASI_EXDEV: u16 = 75;
|
||||
pub const __WASI_ENOTCAPABLE: u16 = 76;
|
||||
pub type __wasi_errno_t = u32;
|
||||
pub const __WASI_ESUCCESS: u32 = 0;
|
||||
pub const __WASI_E2BIG: u32 = 1;
|
||||
pub const __WASI_EACCES: u32 = 2;
|
||||
pub const __WASI_EADDRINUSE: u32 = 3;
|
||||
pub const __WASI_EADDRNOTAVAIL: u32 = 4;
|
||||
pub const __WASI_EAFNOSUPPORT: u32 = 5;
|
||||
pub const __WASI_EAGAIN: u32 = 6;
|
||||
pub const __WASI_EALREADY: u32 = 7;
|
||||
pub const __WASI_EBADF: u32 = 8;
|
||||
pub const __WASI_EBADMSG: u32 = 9;
|
||||
pub const __WASI_EBUSY: u32 = 10;
|
||||
pub const __WASI_ECANCELED: u32 = 11;
|
||||
pub const __WASI_ECHILD: u32 = 12;
|
||||
pub const __WASI_ECONNABORTED: u32 = 13;
|
||||
pub const __WASI_ECONNREFUSED: u32 = 14;
|
||||
pub const __WASI_ECONNRESET: u32 = 15;
|
||||
pub const __WASI_EDEADLK: u32 = 16;
|
||||
pub const __WASI_EDESTADDRREQ: u32 = 17;
|
||||
pub const __WASI_EDOM: u32 = 18;
|
||||
pub const __WASI_EDQUOT: u32 = 19;
|
||||
pub const __WASI_EEXIST: u32 = 20;
|
||||
pub const __WASI_EFAULT: u32 = 21;
|
||||
pub const __WASI_EFBIG: u32 = 22;
|
||||
pub const __WASI_EHOSTUNREACH: u32 = 23;
|
||||
pub const __WASI_EIDRM: u32 = 24;
|
||||
pub const __WASI_EILSEQ: u32 = 25;
|
||||
pub const __WASI_EINPROGRESS: u32 = 26;
|
||||
pub const __WASI_EINTR: u32 = 27;
|
||||
pub const __WASI_EINVAL: u32 = 28;
|
||||
pub const __WASI_EIO: u32 = 29;
|
||||
pub const __WASI_EISCONN: u32 = 30;
|
||||
pub const __WASI_EISDIR: u32 = 31;
|
||||
pub const __WASI_ELOOP: u32 = 32;
|
||||
pub const __WASI_EMFILE: u32 = 33;
|
||||
pub const __WASI_EMLINK: u32 = 34;
|
||||
pub const __WASI_EMSGSIZE: u32 = 35;
|
||||
pub const __WASI_EMULTIHOP: u32 = 36;
|
||||
pub const __WASI_ENAMETOOLONG: u32 = 37;
|
||||
pub const __WASI_ENETDOWN: u32 = 38;
|
||||
pub const __WASI_ENETRESET: u32 = 39;
|
||||
pub const __WASI_ENETUNREACH: u32 = 40;
|
||||
pub const __WASI_ENFILE: u32 = 41;
|
||||
pub const __WASI_ENOBUFS: u32 = 42;
|
||||
pub const __WASI_ENODEV: u32 = 43;
|
||||
pub const __WASI_ENOENT: u32 = 44;
|
||||
pub const __WASI_ENOEXEC: u32 = 45;
|
||||
pub const __WASI_ENOLCK: u32 = 46;
|
||||
pub const __WASI_ENOLINK: u32 = 47;
|
||||
pub const __WASI_ENOMEM: u32 = 48;
|
||||
pub const __WASI_ENOMSG: u32 = 49;
|
||||
pub const __WASI_ENOPROTOOPT: u32 = 50;
|
||||
pub const __WASI_ENOSPC: u32 = 51;
|
||||
pub const __WASI_ENOSYS: u32 = 52;
|
||||
pub const __WASI_ENOTCONN: u32 = 53;
|
||||
pub const __WASI_ENOTDIR: u32 = 54;
|
||||
pub const __WASI_ENOTEMPTY: u32 = 55;
|
||||
pub const __WASI_ENOTRECOVERABLE: u32 = 56;
|
||||
pub const __WASI_ENOTSOCK: u32 = 57;
|
||||
pub const __WASI_ENOTSUP: u32 = 58;
|
||||
pub const __WASI_ENOTTY: u32 = 59;
|
||||
pub const __WASI_ENXIO: u32 = 60;
|
||||
pub const __WASI_EOVERFLOW: u32 = 61;
|
||||
pub const __WASI_EOWNERDEAD: u32 = 62;
|
||||
pub const __WASI_EPERM: u32 = 63;
|
||||
pub const __WASI_EPIPE: u32 = 64;
|
||||
pub const __WASI_EPROTO: u32 = 65;
|
||||
pub const __WASI_EPROTONOSUPPORT: u32 = 66;
|
||||
pub const __WASI_EPROTOTYPE: u32 = 67;
|
||||
pub const __WASI_ERANGE: u32 = 68;
|
||||
pub const __WASI_EROFS: u32 = 69;
|
||||
pub const __WASI_ESPIPE: u32 = 70;
|
||||
pub const __WASI_ESRCH: u32 = 71;
|
||||
pub const __WASI_ESTALE: u32 = 72;
|
||||
pub const __WASI_ETIMEDOUT: u32 = 73;
|
||||
pub const __WASI_ETXTBSY: u32 = 74;
|
||||
pub const __WASI_EXDEV: u32 = 75;
|
||||
pub const __WASI_ENOTCAPABLE: u32 = 76;
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
#[repr(C)]
|
||||
@ -173,8 +173,8 @@ impl __wasi_event_t {
|
||||
}
|
||||
}
|
||||
|
||||
pub type __wasi_eventrwflags_t = u16;
|
||||
pub const __WASI_EVENT_FD_READWRITE_HANGUP: u16 = 1 << 0;
|
||||
pub type __wasi_eventrwflags_t = u32;
|
||||
pub const __WASI_EVENT_FD_READWRITE_HANGUP: u32 = 1 << 0;
|
||||
|
||||
pub type __wasi_eventtype_t = u8;
|
||||
pub const __WASI_EVENTTYPE_CLOCK: u8 = 0;
|
||||
@ -188,12 +188,12 @@ pub const __WASI_STDIN_FILENO: u32 = 0;
|
||||
pub const __WASI_STDOUT_FILENO: u32 = 1;
|
||||
pub const __WASI_STDERR_FILENO: u32 = 2;
|
||||
|
||||
pub type __wasi_fdflags_t = u16;
|
||||
pub const __WASI_FDFLAG_APPEND: u16 = 1 << 0;
|
||||
pub const __WASI_FDFLAG_DSYNC: u16 = 1 << 1;
|
||||
pub const __WASI_FDFLAG_NONBLOCK: u16 = 1 << 2;
|
||||
pub const __WASI_FDFLAG_RSYNC: u16 = 1 << 3;
|
||||
pub const __WASI_FDFLAG_SYNC: u16 = 1 << 4;
|
||||
pub type __wasi_fdflags_t = u32;
|
||||
pub const __WASI_FDFLAG_APPEND: u32 = 1 << 0;
|
||||
pub const __WASI_FDFLAG_DSYNC: u32 = 1 << 1;
|
||||
pub const __WASI_FDFLAG_NONBLOCK: u32 = 1 << 2;
|
||||
pub const __WASI_FDFLAG_RSYNC: u32 = 1 << 3;
|
||||
pub const __WASI_FDFLAG_SYNC: u32 = 1 << 4;
|
||||
|
||||
pub type __wasi_preopentype_t = u8;
|
||||
pub const __WASI_PREOPENTYPE_DIR: u8 = 0;
|
||||
@ -264,7 +264,7 @@ pub type __wasi_filedelta_t = i64;
|
||||
|
||||
pub type __wasi_filesize_t = u64;
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
|
||||
#[repr(C)]
|
||||
pub struct __wasi_filestat_t {
|
||||
pub st_dev: __wasi_device_t,
|
||||
@ -289,11 +289,11 @@ pub const __WASI_FILETYPE_SOCKET_DGRAM: u8 = 5;
|
||||
pub const __WASI_FILETYPE_SOCKET_STREAM: u8 = 6;
|
||||
pub const __WASI_FILETYPE_SYMBOLIC_LINK: u8 = 7;
|
||||
|
||||
pub type __wasi_fstflags_t = u16;
|
||||
pub const __WASI_FILESTAT_SET_ATIM: u16 = 1 << 0;
|
||||
pub const __WASI_FILESTAT_SET_ATIM_NOW: u16 = 1 << 1;
|
||||
pub const __WASI_FILESTAT_SET_MTIM: u16 = 1 << 2;
|
||||
pub const __WASI_FILESTAT_SET_MTIM_NOW: u16 = 1 << 3;
|
||||
pub type __wasi_fstflags_t = u32;
|
||||
pub const __WASI_FILESTAT_SET_ATIM: u32 = 1 << 0;
|
||||
pub const __WASI_FILESTAT_SET_ATIM_NOW: u32 = 1 << 1;
|
||||
pub const __WASI_FILESTAT_SET_MTIM: u32 = 1 << 2;
|
||||
pub const __WASI_FILESTAT_SET_MTIM_NOW: u32 = 1 << 3;
|
||||
|
||||
pub type __wasi_inode_t = u64;
|
||||
|
||||
@ -311,15 +311,15 @@ pub type __wasi_linkcount_t = u32;
|
||||
pub type __wasi_lookupflags_t = u32;
|
||||
pub const __WASI_LOOKUP_SYMLINK_FOLLOW: u32 = 1 << 0;
|
||||
|
||||
pub type __wasi_oflags_t = u16;
|
||||
pub const __WASI_O_CREAT: u16 = 1 << 0;
|
||||
pub const __WASI_O_DIRECTORY: u16 = 1 << 1;
|
||||
pub const __WASI_O_EXCL: u16 = 1 << 2;
|
||||
pub const __WASI_O_TRUNC: u16 = 1 << 3;
|
||||
pub type __wasi_oflags_t = u32;
|
||||
pub const __WASI_O_CREAT: u32 = 1 << 0;
|
||||
pub const __WASI_O_DIRECTORY: u32 = 1 << 1;
|
||||
pub const __WASI_O_EXCL: u32 = 1 << 2;
|
||||
pub const __WASI_O_TRUNC: u32 = 1 << 3;
|
||||
|
||||
pub type __wasi_riflags_t = u16;
|
||||
pub const __WASI_SOCK_RECV_PEEK: u16 = 1 << 0;
|
||||
pub const __WASI_SOCK_RECV_WAITALL: u16 = 1 << 1;
|
||||
pub type __wasi_riflags_t = u32;
|
||||
pub const __WASI_SOCK_RECV_PEEK: u32 = 1 << 0;
|
||||
pub const __WASI_SOCK_RECV_WAITALL: u32 = 1 << 1;
|
||||
|
||||
pub type __wasi_rights_t = u64;
|
||||
pub const __WASI_RIGHT_FD_DATASYNC: u64 = 1 << 0;
|
||||
@ -352,14 +352,14 @@ pub const __WASI_RIGHT_PATH_REMOVE_DIRECTORY: u64 = 1 << 26;
|
||||
pub const __WASI_RIGHT_POLL_FD_READWRITE: u64 = 1 << 27;
|
||||
pub const __WASI_RIGHT_SOCK_SHUTDOWN: u64 = 1 << 28;
|
||||
|
||||
pub type __wasi_roflags_t = u16;
|
||||
pub const __WASI_SOCK_RECV_DATA_TRUNCATED: u16 = 1 << 0;
|
||||
pub type __wasi_roflags_t = u32;
|
||||
pub const __WASI_SOCK_RECV_DATA_TRUNCATED: u32 = 1 << 0;
|
||||
|
||||
pub type __wasi_sdflags_t = u8;
|
||||
pub const __WASI_SHUT_RD: u8 = 1 << 0;
|
||||
pub const __WASI_SHUT_WR: u8 = 1 << 1;
|
||||
|
||||
pub type __wasi_siflags_t = u16;
|
||||
pub type __wasi_siflags_t = u32;
|
||||
|
||||
pub type __wasi_signal_t = u8;
|
||||
pub const __WASI_SIGABRT: u8 = 0;
|
||||
@ -389,8 +389,8 @@ pub const __WASI_SIGVTALRM: u8 = 23;
|
||||
pub const __WASI_SIGXCPU: u8 = 24;
|
||||
pub const __WASI_SIGXFSZ: u8 = 25;
|
||||
|
||||
pub type __wasi_subclockflags_t = u16;
|
||||
pub const __WASI_SUBSCRIPTION_CLOCK_ABSTIME: u16 = 1 << 0;
|
||||
pub type __wasi_subclockflags_t = u32;
|
||||
pub const __WASI_SUBSCRIPTION_CLOCK_ABSTIME: u32 = 1 << 0;
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
#[repr(C)]
|
||||
|
@ -80,9 +80,13 @@ struct Run {
|
||||
backend: Backend,
|
||||
|
||||
/// Emscripten symbol map
|
||||
#[structopt(long = "em-symbol-map", parse(from_os_str))]
|
||||
#[structopt(long = "em-symbol-map", parse(from_os_str), group = "emscripten")]
|
||||
em_symbol_map: Option<PathBuf>,
|
||||
|
||||
/// WASI pre-opened directory
|
||||
#[structopt(long = "dir", multiple = true, group = "wasi")]
|
||||
pre_opened_directories: Vec<String>,
|
||||
|
||||
#[structopt(long = "command-name", hidden = true)]
|
||||
command_name: Option<String>,
|
||||
|
||||
@ -316,6 +320,7 @@ fn execute_wasm(options: &Run) -> Result<(), String> {
|
||||
env::vars()
|
||||
.map(|(k, v)| format!("{}={}", k, v).into_bytes())
|
||||
.collect(),
|
||||
options.pre_opened_directories.clone(),
|
||||
),
|
||||
None,
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user