Skip to content

Commit 88fc562

Browse files
bors[bot]Mark McCaskey
and
Mark McCaskey
committed
Merge #343
343: add preopened fd and fix/improve fs syscalls; fix wasi memory access r=MarkMcCaskey a=MarkMcCaskey resolves #356 Co-authored-by: Mark McCaskey <mark@wasmer.io>
2 parents ed65105 + b141d7f commit 88fc562

File tree

6 files changed

+397
-115
lines changed

6 files changed

+397
-115
lines changed

lib/wasi/src/lib.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,11 @@ pub use self::utils::is_wasi_module;
1717

1818
use wasmer_runtime_core::{func, import::ImportObject, imports};
1919

20-
pub fn generate_import_object(args: Vec<Vec<u8>>, envs: Vec<Vec<u8>>) -> ImportObject {
20+
pub fn generate_import_object(
21+
args: Vec<Vec<u8>>,
22+
envs: Vec<Vec<u8>>,
23+
preopened_files: Vec<String>,
24+
) -> ImportObject {
2125
let state_gen = move || {
2226
fn state_destructor(data: *mut c_void) {
2327
unsafe {
@@ -26,7 +30,7 @@ pub fn generate_import_object(args: Vec<Vec<u8>>, envs: Vec<Vec<u8>>) -> ImportO
2630
}
2731

2832
let state = Box::new(WasiState {
29-
fs: WasiFs::new().unwrap(),
33+
fs: WasiFs::new(&preopened_files).unwrap(),
3034
args: &args[..],
3135
envs: &envs[..],
3236
});

lib/wasi/src/ptr.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,12 @@ impl<T: Copy + ValueType> WasmPtr<T, Item> {
3636
return Err(__WASI_EFAULT);
3737
}
3838
unsafe {
39-
let cell_ptr = memory
40-
.view::<T>()
41-
.get_unchecked((self.offset() as usize) / mem::size_of::<T>())
42-
as *const _;
39+
// clears bits below aligment amount (assumes power of 2) to align pointer
40+
let aligner = |ptr: usize, align: usize| ptr & !(align - 1);
41+
let cell_ptr = aligner(
42+
memory.view::<u8>().as_ptr().add(self.offset as usize) as usize,
43+
mem::align_of::<T>(),
44+
) as *const Cell<T>;
4345
Ok(&*cell_ptr)
4446
}
4547
}

lib/wasi/src/state.rs

+172-17
Original file line numberDiff line numberDiff line change
@@ -7,28 +7,149 @@ use generational_arena::{Arena, Index as Inode};
77
use hashbrown::hash_map::{Entry, HashMap};
88
use std::{
99
cell::Cell,
10-
io::{self, Write},
10+
fs,
11+
io::{self, Read, Seek, Write},
1112
time::SystemTime,
1213
};
1314
use wasmer_runtime_core::debug;
14-
use zbox::{init_env as zbox_init_env, File, FileType, OpenOptions, Repo, RepoOpener};
15+
use zbox::{init_env as zbox_init_env, FileType, OpenOptions, Repo, RepoOpener};
1516

1617
pub const MAX_SYMLINKS: usize = 100;
1718

19+
#[derive(Debug)]
20+
pub enum WasiFile {
21+
ZboxFile(zbox::File),
22+
HostFile(fs::File),
23+
}
24+
25+
impl Write for WasiFile {
26+
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
27+
match self {
28+
WasiFile::ZboxFile(zbf) => zbf.write(buf),
29+
WasiFile::HostFile(hf) => hf.write(buf),
30+
}
31+
}
32+
33+
fn flush(&mut self) -> io::Result<()> {
34+
match self {
35+
WasiFile::ZboxFile(zbf) => zbf.flush(),
36+
WasiFile::HostFile(hf) => hf.flush(),
37+
}
38+
}
39+
40+
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
41+
match self {
42+
WasiFile::ZboxFile(zbf) => zbf.write_all(buf),
43+
WasiFile::HostFile(hf) => hf.write_all(buf),
44+
}
45+
}
46+
47+
fn write_fmt(&mut self, fmt: ::std::fmt::Arguments) -> io::Result<()> {
48+
match self {
49+
WasiFile::ZboxFile(zbf) => zbf.write_fmt(fmt),
50+
WasiFile::HostFile(hf) => hf.write_fmt(fmt),
51+
}
52+
}
53+
}
54+
55+
impl Read for WasiFile {
56+
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
57+
match self {
58+
WasiFile::ZboxFile(zbf) => zbf.read(buf),
59+
WasiFile::HostFile(hf) => hf.read(buf),
60+
}
61+
}
62+
63+
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
64+
match self {
65+
WasiFile::ZboxFile(zbf) => zbf.read_to_end(buf),
66+
WasiFile::HostFile(hf) => hf.read_to_end(buf),
67+
}
68+
}
69+
70+
fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
71+
match self {
72+
WasiFile::ZboxFile(zbf) => zbf.read_to_string(buf),
73+
WasiFile::HostFile(hf) => hf.read_to_string(buf),
74+
}
75+
}
76+
77+
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
78+
match self {
79+
WasiFile::ZboxFile(zbf) => zbf.read_exact(buf),
80+
WasiFile::HostFile(hf) => hf.read_exact(buf),
81+
}
82+
}
83+
}
84+
85+
impl Seek for WasiFile {
86+
fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
87+
match self {
88+
WasiFile::ZboxFile(zbf) => zbf.seek(pos),
89+
WasiFile::HostFile(hf) => hf.seek(pos),
90+
}
91+
}
92+
}
93+
94+
#[derive(Debug)]
1895
pub struct InodeVal {
1996
pub stat: __wasi_filestat_t,
2097
pub is_preopened: bool,
2198
pub name: String,
2299
pub kind: Kind,
23100
}
24101

102+
impl InodeVal {
103+
// TODO: clean this up
104+
pub fn from_file_metadata(
105+
metadata: &std::fs::Metadata,
106+
name: String,
107+
is_preopened: bool,
108+
kind: Kind,
109+
) -> Self {
110+
InodeVal {
111+
stat: __wasi_filestat_t {
112+
st_filetype: if metadata.is_dir() {
113+
__WASI_FILETYPE_DIRECTORY
114+
} else {
115+
__WASI_FILETYPE_REGULAR_FILE
116+
},
117+
st_size: metadata.len(),
118+
st_atim: metadata
119+
.accessed()
120+
.ok()
121+
.and_then(|sys_time| sys_time.duration_since(SystemTime::UNIX_EPOCH).ok())
122+
.map(|duration| duration.as_nanos() as u64)
123+
.unwrap_or(0),
124+
st_ctim: metadata
125+
.created()
126+
.ok()
127+
.and_then(|sys_time| sys_time.duration_since(SystemTime::UNIX_EPOCH).ok())
128+
.map(|duration| duration.as_nanos() as u64)
129+
.unwrap_or(0),
130+
st_mtim: metadata
131+
.modified()
132+
.ok()
133+
.and_then(|sys_time| sys_time.duration_since(SystemTime::UNIX_EPOCH).ok())
134+
.map(|duration| duration.as_nanos() as u64)
135+
.unwrap_or(0),
136+
..__wasi_filestat_t::default()
137+
},
138+
is_preopened,
139+
name,
140+
kind,
141+
}
142+
}
143+
}
144+
25145
#[allow(dead_code)]
146+
#[derive(Debug)]
26147
pub enum Kind {
27148
File {
28-
handle: File,
149+
handle: WasiFile,
29150
},
30151
Dir {
31-
handle: File,
152+
handle: WasiFile,
32153
/// The entries of a directory are lazily filled.
33154
entries: HashMap<String, Inode>,
34155
},
@@ -40,7 +161,7 @@ pub enum Kind {
40161
},
41162
}
42163

43-
#[derive(Clone)]
164+
#[derive(Clone, Debug)]
44165
pub struct Fd {
45166
pub rights: __wasi_rights_t,
46167
pub rights_inheriting: __wasi_rights_t,
@@ -50,7 +171,7 @@ pub struct Fd {
50171
}
51172

52173
pub struct WasiFs {
53-
// pub repo: Repo,
174+
//pub repo: Repo,
54175
pub name_map: HashMap<String, Inode>,
55176
pub inodes: Arena<InodeVal>,
56177
pub fd_map: HashMap<u32, Fd>,
@@ -59,26 +180,56 @@ pub struct WasiFs {
59180
}
60181

61182
impl WasiFs {
62-
pub fn new() -> Result<Self, String> {
183+
pub fn new(preopened_files: &[String]) -> Result<Self, String> {
63184
debug!("wasi::fs::init");
64185
zbox_init_env();
65186
debug!("wasi::fs::repo");
66-
// let repo = RepoOpener::new()
67-
// .create(true)
68-
// .open("mem://wasmer-test-fs", "")
69-
// .map_err(|e| e.to_string())?;
187+
/*let repo = RepoOpener::new()
188+
.create(true)
189+
.open("mem://wasmer-test-fs", "")
190+
.map_err(|e| e.to_string())?;*/
70191
debug!("wasi::fs::inodes");
71192
let inodes = Arena::new();
72-
let res = Ok(Self {
73-
// repo: repo,
193+
let mut wasi_fs = Self {
194+
//repo: repo,
74195
name_map: HashMap::new(),
75196
inodes: inodes,
76197
fd_map: HashMap::new(),
77198
next_fd: Cell::new(3),
78199
inode_counter: Cell::new(1000),
79-
});
200+
};
201+
for file in preopened_files {
202+
debug!("Attempting to preopen {}", &file);
203+
// TODO: think about this
204+
let default_rights = 0x1FFFFFFF; // all rights
205+
let cur_file: fs::File = fs::OpenOptions::new()
206+
.read(true)
207+
.open(file)
208+
.expect("Could not find file");
209+
let cur_file_metadata = cur_file.metadata().unwrap();
210+
let kind = if cur_file_metadata.is_dir() {
211+
Kind::Dir {
212+
handle: WasiFile::HostFile(cur_file),
213+
entries: Default::default(),
214+
}
215+
} else {
216+
return Err(format!(
217+
"WASI only supports pre-opened directories right now; found \"{}\"",
218+
file
219+
));
220+
};
221+
// TODO: handle nested pats in `file`
222+
let inode_val =
223+
InodeVal::from_file_metadata(&cur_file_metadata, file.clone(), true, kind);
224+
225+
let inode = wasi_fs.inodes.insert(inode_val);
226+
wasi_fs.inodes[inode].stat.st_ino = wasi_fs.inode_counter.get();
227+
wasi_fs
228+
.create_fd(default_rights, default_rights, 0, inode)
229+
.expect("Could not open fd");
230+
}
80231
debug!("wasi::fs::end");
81-
res
232+
Ok(wasi_fs)
82233
}
83234

84235
#[allow(dead_code)]
@@ -195,6 +346,8 @@ impl WasiFs {
195346
pub fn fdstat(&self, fd: __wasi_fd_t) -> Result<__wasi_fdstat_t, __wasi_errno_t> {
196347
let fd = self.fd_map.get(&fd).ok_or(__WASI_EBADF)?;
197348

349+
debug!("fdstat: {:?}", fd);
350+
198351
Ok(__wasi_fdstat_t {
199352
fs_filetype: match self.inodes[fd.inode].kind {
200353
Kind::File { .. } => __WASI_FILETYPE_REGULAR_FILE,
@@ -204,20 +357,22 @@ impl WasiFs {
204357
},
205358
fs_flags: fd.flags,
206359
fs_rights_base: fd.rights,
207-
fs_rights_inheriting: fd.rights, // TODO(lachlan): Is this right?
360+
fs_rights_inheriting: fd.rights_inheriting, // TODO(lachlan): Is this right?
208361
})
209362
}
210363

211364
pub fn prestat_fd(&self, fd: __wasi_fd_t) -> Result<__wasi_prestat_t, __wasi_errno_t> {
212365
let fd = self.fd_map.get(&fd).ok_or(__WASI_EBADF)?;
213366

367+
debug!("in prestat_fd {:?}", fd);
214368
let inode_val = &self.inodes[fd.inode];
215369

216370
if inode_val.is_preopened {
217371
Ok(__wasi_prestat_t {
218372
pr_type: __WASI_PREOPENTYPE_DIR,
219373
u: PrestatEnum::Dir {
220-
pr_name_len: inode_val.name.len() as u32,
374+
// REVIEW:
375+
pr_name_len: inode_val.name.len() as u32 + 1,
221376
}
222377
.untagged(),
223378
})

0 commit comments

Comments
 (0)