mirror of
https://github.com/fluencelabs/wasmer
synced 2024-12-13 06:15:33 +00:00
wip fs improvements
This commit is contained in:
parent
122963909f
commit
dd1ddea37b
@ -1,7 +1,5 @@
|
|||||||
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
|
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate log;
|
|
||||||
#[cfg(target = "windows")]
|
#[cfg(target = "windows")]
|
||||||
extern crate winapi;
|
extern crate winapi;
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ use std::{
|
|||||||
cell::Cell,
|
cell::Cell,
|
||||||
fs,
|
fs,
|
||||||
io::{self, Read, Seek, Write},
|
io::{self, Read, Seek, Write},
|
||||||
path::PathBuf,
|
path::{Path, PathBuf},
|
||||||
time::SystemTime,
|
time::SystemTime,
|
||||||
};
|
};
|
||||||
use wasmer_runtime_core::debug;
|
use wasmer_runtime_core::debug;
|
||||||
@ -81,6 +81,7 @@ impl Seek for WasiFile {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A file that Wasi knows about that may or may not be open
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct InodeVal {
|
pub struct InodeVal {
|
||||||
pub stat: __wasi_filestat_t,
|
pub stat: __wasi_filestat_t,
|
||||||
@ -136,7 +137,10 @@ impl InodeVal {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Kind {
|
pub enum Kind {
|
||||||
File {
|
File {
|
||||||
handle: WasiFile,
|
/// the open file, if it's open
|
||||||
|
handle: Option<WasiFile>,
|
||||||
|
/// the path to the file
|
||||||
|
path: PathBuf,
|
||||||
},
|
},
|
||||||
Dir {
|
Dir {
|
||||||
/// Parent directory
|
/// Parent directory
|
||||||
@ -148,7 +152,9 @@ pub enum Kind {
|
|||||||
entries: HashMap<String, Inode>,
|
entries: HashMap<String, Inode>,
|
||||||
},
|
},
|
||||||
Symlink {
|
Symlink {
|
||||||
forwarded: Inode,
|
forwarded: Option<Inode>,
|
||||||
|
/// This is required because, at the very least, symlinks can be deleted and we'll need to check that
|
||||||
|
path: PathBuf,
|
||||||
},
|
},
|
||||||
Buffer {
|
Buffer {
|
||||||
buffer: Vec<u8>,
|
buffer: Vec<u8>,
|
||||||
@ -311,6 +317,7 @@ impl WasiFs {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
fn filestat_inode(
|
fn filestat_inode(
|
||||||
&self,
|
&self,
|
||||||
@ -318,8 +325,13 @@ impl WasiFs {
|
|||||||
flags: __wasi_lookupflags_t,
|
flags: __wasi_lookupflags_t,
|
||||||
) -> Result<__wasi_filestat_t, __wasi_errno_t> {
|
) -> Result<__wasi_filestat_t, __wasi_errno_t> {
|
||||||
let inode_val = &self.inodes[inode];
|
let inode_val = &self.inodes[inode];
|
||||||
if let (true, Kind::Symlink { mut forwarded }) =
|
if let (
|
||||||
(flags & __WASI_LOOKUP_SYMLINK_FOLLOW != 0, &inode_val.kind)
|
true,
|
||||||
|
Kind::Symlink {
|
||||||
|
mut forwarded,
|
||||||
|
path,
|
||||||
|
},
|
||||||
|
) = (flags & __WASI_LOOKUP_SYMLINK_FOLLOW != 0, &inode_val.kind)
|
||||||
{
|
{
|
||||||
// Time to follow the symlink.
|
// Time to follow the symlink.
|
||||||
let mut counter = 0;
|
let mut counter = 0;
|
||||||
@ -355,6 +367,118 @@ impl WasiFs {
|
|||||||
|
|
||||||
self.filestat_inode(inode, flags)
|
self.filestat_inode(inode, flags)
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// gets a host file from a base directory and a path
|
||||||
|
/// this function ensures the fs remains sandboxed
|
||||||
|
pub fn get_inode_at_path(
|
||||||
|
&mut self,
|
||||||
|
base: __wasi_fd_t,
|
||||||
|
path: &str,
|
||||||
|
) -> Result<Inode, __wasi_errno_t> {
|
||||||
|
let base_dir = self.get_fd(base)?;
|
||||||
|
let path: &Path = Path::new(path);
|
||||||
|
|
||||||
|
let mut symlinks_followed = 0;
|
||||||
|
let mut cur_inode = base_dir.inode;
|
||||||
|
// TODO: rights checks
|
||||||
|
'path_iter: for component in path.components() {
|
||||||
|
// for each component traverse file structure
|
||||||
|
// loading inodes as necessary
|
||||||
|
'symlink_resolution: loop {
|
||||||
|
match &mut self.inodes[cur_inode].kind {
|
||||||
|
Kind::Buffer { .. } => unimplemented!("state::get_inode_at_path for buffers"),
|
||||||
|
Kind::Dir {
|
||||||
|
ref mut entries,
|
||||||
|
ref path,
|
||||||
|
ref parent,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
if component.as_os_str().to_string_lossy() == ".." {
|
||||||
|
if let Some(p) = parent {
|
||||||
|
cur_inode = *p;
|
||||||
|
continue 'path_iter;
|
||||||
|
} else {
|
||||||
|
// TODO: be smart here with multiple preopened directories
|
||||||
|
return Err(__WASI_EACCES);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(entry) =
|
||||||
|
entries.get(component.as_os_str().to_string_lossy().as_ref())
|
||||||
|
{
|
||||||
|
cur_inode = *entry;
|
||||||
|
} else {
|
||||||
|
let file = {
|
||||||
|
let mut cd = path.clone();
|
||||||
|
cd.push(component);
|
||||||
|
cd
|
||||||
|
};
|
||||||
|
// TODO: verify this returns successfully when given a non-symlink
|
||||||
|
let metadata = file.symlink_metadata().ok().ok_or(__WASI_EEXIST)?;
|
||||||
|
let file_type = metadata.file_type();
|
||||||
|
|
||||||
|
let kind = if file_type.is_dir() {
|
||||||
|
// load DIR
|
||||||
|
Kind::Dir {
|
||||||
|
parent: Some(cur_inode),
|
||||||
|
path: file.clone(),
|
||||||
|
entries: Default::default(),
|
||||||
|
}
|
||||||
|
} else if file_type.is_file() {
|
||||||
|
// load file
|
||||||
|
Kind::File {
|
||||||
|
handle: None,
|
||||||
|
path: file.clone(),
|
||||||
|
}
|
||||||
|
} else if file_type.is_symlink() {
|
||||||
|
// use a stack and load symlinks?
|
||||||
|
// load symlink
|
||||||
|
Kind::Symlink {
|
||||||
|
forwarded: None,
|
||||||
|
path: file.clone(),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
unimplemented!("state::get_inode_at_path unknown file type: not file, directory, or symlink");
|
||||||
|
};
|
||||||
|
|
||||||
|
let new_inode = self.inodes.insert(InodeVal {
|
||||||
|
stat: get_stat_for_kind(&kind).ok_or(__WASI_EIO)?,
|
||||||
|
is_preopened: false,
|
||||||
|
name: file.to_string_lossy().to_string(),
|
||||||
|
kind,
|
||||||
|
});
|
||||||
|
*self.inode_counter.get_mut() += 1;
|
||||||
|
|
||||||
|
cur_inode = new_inode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Kind::File { .. } => {
|
||||||
|
return Err(__WASI_ENOTDIR);
|
||||||
|
}
|
||||||
|
Kind::Symlink { forwarded, path } => {
|
||||||
|
if symlinks_followed > MAX_SYMLINKS {
|
||||||
|
return Err(__WASI_EMLINK);
|
||||||
|
}
|
||||||
|
if let Some(fwd) = forwarded {
|
||||||
|
cur_inode = *fwd;
|
||||||
|
} else {
|
||||||
|
// load the symlink
|
||||||
|
let _link = path.read_link().ok().ok_or(__WASI_EIO)?;
|
||||||
|
}
|
||||||
|
symlinks_followed += 1;
|
||||||
|
continue 'symlink_resolution;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break 'symlink_resolution;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(cur_inode)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_fd(&self, fd: __wasi_fd_t) -> Result<&Fd, __wasi_errno_t> {
|
||||||
|
self.fd_map.get(&fd).ok_or(__WASI_EBADF)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn filestat_fd(&self, fd: __wasi_fd_t) -> Result<__wasi_filestat_t, __wasi_errno_t> {
|
pub fn filestat_fd(&self, fd: __wasi_fd_t) -> Result<__wasi_filestat_t, __wasi_errno_t> {
|
||||||
let fd = self.fd_map.get(&fd).ok_or(__WASI_EBADF)?;
|
let fd = self.fd_map.get(&fd).ok_or(__WASI_EBADF)?;
|
||||||
@ -414,11 +538,15 @@ impl WasiFs {
|
|||||||
let inode = &mut self.inodes[fd.inode];
|
let inode = &mut self.inodes[fd.inode];
|
||||||
|
|
||||||
match &mut inode.kind {
|
match &mut inode.kind {
|
||||||
Kind::File { handle } => handle.flush().map_err(|_| __WASI_EIO)?,
|
Kind::File {
|
||||||
|
handle: Some(handle),
|
||||||
|
..
|
||||||
|
} => handle.flush().map_err(|_| __WASI_EIO)?,
|
||||||
// TODO: verify this behavior
|
// TODO: verify this behavior
|
||||||
Kind::Dir { .. } => return Err(__WASI_EISDIR),
|
Kind::Dir { .. } => return Err(__WASI_EISDIR),
|
||||||
Kind::Symlink { .. } => unimplemented!(),
|
Kind::Symlink { .. } => unimplemented!(),
|
||||||
Kind::Buffer { .. } => (),
|
Kind::Buffer { .. } => (),
|
||||||
|
_ => return Err(__WASI_EIO),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -477,35 +605,36 @@ pub fn host_file_type_to_wasi_file_type(file_type: fs::FileType) -> __wasi_filet
|
|||||||
|
|
||||||
pub fn get_stat_for_kind(kind: &Kind) -> Option<__wasi_filestat_t> {
|
pub fn get_stat_for_kind(kind: &Kind) -> Option<__wasi_filestat_t> {
|
||||||
match kind {
|
match kind {
|
||||||
Kind::File { handle } => match handle {
|
Kind::File { handle, path } => {
|
||||||
WasiFile::HostFile(hf) => {
|
let md = match handle {
|
||||||
let md = hf.metadata().ok()?;
|
Some(WasiFile::HostFile(hf)) => hf.metadata().ok()?,
|
||||||
|
None => path.metadata().ok()?,
|
||||||
|
};
|
||||||
|
|
||||||
Some(__wasi_filestat_t {
|
Some(__wasi_filestat_t {
|
||||||
st_filetype: host_file_type_to_wasi_file_type(md.file_type()),
|
st_filetype: host_file_type_to_wasi_file_type(md.file_type()),
|
||||||
st_size: md.len(),
|
st_size: md.len(),
|
||||||
st_atim: md
|
st_atim: md
|
||||||
.accessed()
|
.accessed()
|
||||||
.ok()?
|
.ok()?
|
||||||
.duration_since(SystemTime::UNIX_EPOCH)
|
.duration_since(SystemTime::UNIX_EPOCH)
|
||||||
.ok()?
|
.ok()?
|
||||||
.as_nanos() as u64,
|
.as_nanos() as u64,
|
||||||
st_mtim: md
|
st_mtim: md
|
||||||
.modified()
|
.modified()
|
||||||
.ok()?
|
.ok()?
|
||||||
.duration_since(SystemTime::UNIX_EPOCH)
|
.duration_since(SystemTime::UNIX_EPOCH)
|
||||||
.ok()?
|
.ok()?
|
||||||
.as_nanos() as u64,
|
.as_nanos() as u64,
|
||||||
st_ctim: md
|
st_ctim: md
|
||||||
.created()
|
.created()
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|ct| ct.duration_since(SystemTime::UNIX_EPOCH).ok())
|
.and_then(|ct| ct.duration_since(SystemTime::UNIX_EPOCH).ok())
|
||||||
.map(|ct| ct.as_nanos() as u64)
|
.map(|ct| ct.as_nanos() as u64)
|
||||||
.unwrap_or(0),
|
.unwrap_or(0),
|
||||||
..__wasi_filestat_t::default()
|
..__wasi_filestat_t::default()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
|
||||||
Kind::Dir { path, .. } => {
|
Kind::Dir { path, .. } => {
|
||||||
let md = path.metadata().ok()?;
|
let md = path.metadata().ok()?;
|
||||||
Some(__wasi_filestat_t {
|
Some(__wasi_filestat_t {
|
||||||
|
@ -648,9 +648,13 @@ pub fn fd_pwrite(
|
|||||||
let inode = &mut state.fs.inodes[fd_entry.inode];
|
let inode = &mut state.fs.inodes[fd_entry.inode];
|
||||||
|
|
||||||
let bytes_written = match &mut inode.kind {
|
let bytes_written = match &mut inode.kind {
|
||||||
Kind::File { handle } => {
|
Kind::File { handle, .. } => {
|
||||||
handle.seek(::std::io::SeekFrom::Start(offset as u64));
|
if let Some(handle) = handle {
|
||||||
wasi_try!(write_bytes(handle, memory, iovs_arr_cell))
|
handle.seek(::std::io::SeekFrom::Start(offset as u64));
|
||||||
|
wasi_try!(write_bytes(handle, memory, iovs_arr_cell))
|
||||||
|
} else {
|
||||||
|
return __WASI_EINVAL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Kind::Dir { .. } => {
|
Kind::Dir { .. } => {
|
||||||
// TODO: verify
|
// TODO: verify
|
||||||
@ -736,9 +740,13 @@ pub fn fd_read(
|
|||||||
let inode = &mut state.fs.inodes[fd_entry.inode];
|
let inode = &mut state.fs.inodes[fd_entry.inode];
|
||||||
|
|
||||||
let bytes_read = match &mut inode.kind {
|
let bytes_read = match &mut inode.kind {
|
||||||
Kind::File { handle } => {
|
Kind::File { handle, .. } => {
|
||||||
handle.seek(::std::io::SeekFrom::Start(offset as u64));
|
if let Some(handle) = handle {
|
||||||
wasi_try!(read_bytes(handle, memory, iovs_arr_cell))
|
handle.seek(::std::io::SeekFrom::Start(offset as u64));
|
||||||
|
wasi_try!(read_bytes(handle, memory, iovs_arr_cell))
|
||||||
|
} else {
|
||||||
|
return __WASI_EINVAL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Kind::Dir { .. } => {
|
Kind::Dir { .. } => {
|
||||||
// TODO: verify
|
// TODO: verify
|
||||||
@ -1011,10 +1019,13 @@ pub fn fd_write(
|
|||||||
let inode = &mut state.fs.inodes[fd_entry.inode];
|
let inode = &mut state.fs.inodes[fd_entry.inode];
|
||||||
|
|
||||||
let bytes_written = match &mut inode.kind {
|
let bytes_written = match &mut inode.kind {
|
||||||
Kind::File { handle } => {
|
Kind::File { handle, .. } => {
|
||||||
handle.seek(::std::io::SeekFrom::Start(offset as u64));
|
if let Some(handle) = handle {
|
||||||
|
handle.seek(::std::io::SeekFrom::Start(offset as u64));
|
||||||
wasi_try!(write_bytes(handle, memory, iovs_arr_cell))
|
wasi_try!(write_bytes(handle, memory, iovs_arr_cell))
|
||||||
|
} else {
|
||||||
|
return __WASI_EINVAL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Kind::Dir { .. } => {
|
Kind::Dir { .. } => {
|
||||||
// TODO: verify
|
// TODO: verify
|
||||||
@ -1152,105 +1163,11 @@ pub fn path_filestat_get(
|
|||||||
})
|
})
|
||||||
.map_err(|_| __WASI_EINVAL));
|
.map_err(|_| __WASI_EINVAL));
|
||||||
debug!("=> path: {}", &path_string);
|
debug!("=> path: {}", &path_string);
|
||||||
let path = std::path::PathBuf::from(path_string);
|
|
||||||
let path_vec = path
|
let file_inode = wasi_try!(state.fs.get_inode_at_path(fd, path_string));
|
||||||
.components()
|
let stat = wasi_try!(get_stat_for_kind(&state.fs.inodes[file_inode].kind).ok_or(__WASI_EIO));
|
||||||
.map(|comp| comp.as_os_str().to_string_lossy().to_string())
|
|
||||||
.collect::<Vec<String>>();
|
|
||||||
let buf_cell = wasi_try!(buf.deref(memory));
|
let buf_cell = wasi_try!(buf.deref(memory));
|
||||||
|
|
||||||
if path_vec.is_empty() {
|
|
||||||
return __WASI_EINVAL;
|
|
||||||
}
|
|
||||||
let mut cumulative_path = std::path::PathBuf::from(wasi_try!(state
|
|
||||||
.fs
|
|
||||||
.get_base_path_for_directory(root_dir.inode)
|
|
||||||
.ok_or(__WASI_EIO)));
|
|
||||||
|
|
||||||
debug!("=> Path vec: {:?}:", &path_vec);
|
|
||||||
// find the inode by traversing the path
|
|
||||||
let mut inode = root_dir.inode;
|
|
||||||
'outer: for segment in &path_vec[..(path_vec.len() - 1)] {
|
|
||||||
// loop to traverse symlinks
|
|
||||||
// TODO: proper cycle detection
|
|
||||||
let mut sym_count = 0;
|
|
||||||
loop {
|
|
||||||
match &state.fs.inodes[inode].kind {
|
|
||||||
Kind::Dir { entries, .. } => {
|
|
||||||
cumulative_path.push(&segment);
|
|
||||||
if let Some(entry) = entries.get(segment) {
|
|
||||||
debug!("Entry {:?} found", &segment);
|
|
||||||
inode = entry.clone();
|
|
||||||
} else {
|
|
||||||
// lazily load
|
|
||||||
debug!("Lazily loading entry {:?}", &segment);
|
|
||||||
let path_metadata =
|
|
||||||
wasi_try!(cumulative_path.metadata().map_err(|_| __WASI_ENOENT));
|
|
||||||
if !path_metadata.is_dir() {
|
|
||||||
// TODO: should this just return invalid arg?
|
|
||||||
return __WASI_ENOTDIR;
|
|
||||||
}
|
|
||||||
let kind = Kind::Dir {
|
|
||||||
parent: Some(inode),
|
|
||||||
path: std::path::PathBuf::from(&segment),
|
|
||||||
entries: Default::default(),
|
|
||||||
};
|
|
||||||
let inode_val = InodeVal::from_file_metadata(
|
|
||||||
&path_metadata,
|
|
||||||
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);
|
|
||||||
if let Kind::Dir { entries, .. } = &mut state.fs.inodes[inode].kind {
|
|
||||||
// check that we're not displacing any entries
|
|
||||||
assert!(entries.insert(segment.clone(), new_inode).is_none());
|
|
||||||
state.fs.inodes[new_inode].stat.st_ino = state.fs.inode_counter.get();
|
|
||||||
inode = new_inode;
|
|
||||||
}
|
|
||||||
debug!("Directory {:#?} lazily loaded", &cumulative_path);
|
|
||||||
}
|
|
||||||
continue 'outer;
|
|
||||||
}
|
|
||||||
Kind::Symlink { forwarded } => {
|
|
||||||
// TODO: updated cumulative path
|
|
||||||
sym_count += 1;
|
|
||||||
inode = forwarded.clone();
|
|
||||||
if sym_count > MAX_SYMLINKS {
|
|
||||||
return __WASI_ELOOP;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
return __WASI_ENOTDIR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let stat = match &state.fs.inodes[inode].kind {
|
|
||||||
Kind::Dir { path, entries, .. } => {
|
|
||||||
// read it from internal data structures if we can
|
|
||||||
let last_segment = path_vec.last().unwrap();
|
|
||||||
cumulative_path.push(last_segment);
|
|
||||||
|
|
||||||
if entries.contains_key(last_segment) {
|
|
||||||
state.fs.inodes[entries[last_segment]].stat
|
|
||||||
} else {
|
|
||||||
// otherwise read it from the host FS
|
|
||||||
if !cumulative_path.exists() {
|
|
||||||
return __WASI_ENOENT;
|
|
||||||
}
|
|
||||||
let final_path_metadata =
|
|
||||||
wasi_try!(cumulative_path.metadata().map_err(|_| __WASI_EIO));
|
|
||||||
wasi_try!(get_stat_for_kind(&state.fs.inodes[inode].kind).ok_or(__WASI_EIO))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
return __WASI_ENOTDIR;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
buf_cell.set(stat);
|
buf_cell.set(stat);
|
||||||
|
|
||||||
__WASI_ESUCCESS
|
__WASI_ESUCCESS
|
||||||
@ -1562,7 +1479,8 @@ pub fn path_open(
|
|||||||
real_open_file
|
real_open_file
|
||||||
};
|
};
|
||||||
Kind::File {
|
Kind::File {
|
||||||
handle: WasiFile::HostFile(real_opened_file),
|
handle: Some(WasiFile::HostFile(real_opened_file)),
|
||||||
|
path: file_path,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1612,24 +1530,37 @@ pub fn path_readlink(
|
|||||||
let memory = ctx.memory(0);
|
let memory = ctx.memory(0);
|
||||||
|
|
||||||
let base_dir = wasi_try!(state.fs.fd_map.get(&dir_fd).ok_or(__WASI_EBADF));
|
let base_dir = wasi_try!(state.fs.fd_map.get(&dir_fd).ok_or(__WASI_EBADF));
|
||||||
|
if !has_rights(base_dir.rights, __WASI_RIGHT_PATH_READLINK) {
|
||||||
|
return __WASI_EACCES;
|
||||||
|
}
|
||||||
let path_str = wasi_try!(path.get_utf8_string(memory, path_len).ok_or(__WASI_EINVAL));
|
let path_str = wasi_try!(path.get_utf8_string(memory, path_len).ok_or(__WASI_EINVAL));
|
||||||
let result = wasi_try!(std::fs::read_link(path_str).ok().ok_or(__WASI_EIO));
|
let inode = wasi_try!(state.fs.get_inode_at_path(dir_fd, path_str));
|
||||||
let result_path_as_str = result.to_string_lossy();
|
|
||||||
let bytes = result_path_as_str.bytes();
|
|
||||||
if bytes.len() < buf_len as usize {
|
|
||||||
return __WASI_EOVERFLOW;
|
|
||||||
}
|
|
||||||
|
|
||||||
let out = wasi_try!(buf.deref(memory, 0, buf_len));
|
if let Kind::Symlink { forwarded, .. } = &state.fs.inodes[inode].kind {
|
||||||
let mut bytes_written = 0;
|
if let Some(fwd) = forwarded {
|
||||||
for b in bytes {
|
let resolved_name = &state.fs.inodes[*fwd].name;
|
||||||
out[bytes_written].set(b);
|
let bytes = resolved_name.bytes();
|
||||||
bytes_written += 1;
|
if bytes.len() < buf_len as usize {
|
||||||
}
|
return __WASI_EOVERFLOW;
|
||||||
// should we null terminate this?
|
}
|
||||||
|
|
||||||
let bytes_out = wasi_try!(buf_used.deref(memory));
|
let out = wasi_try!(buf.deref(memory, 0, buf_len));
|
||||||
bytes_out.set(bytes_written as u32);
|
let mut bytes_written = 0;
|
||||||
|
for b in bytes {
|
||||||
|
out[bytes_written].set(b);
|
||||||
|
bytes_written += 1;
|
||||||
|
}
|
||||||
|
// should we null terminate this?
|
||||||
|
|
||||||
|
let bytes_out = wasi_try!(buf_used.deref(memory));
|
||||||
|
bytes_out.set(bytes_written as u32);
|
||||||
|
} else {
|
||||||
|
panic!("do this before shipping");
|
||||||
|
return __WASI_EINVAL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return __WASI_EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
__WASI_ESUCCESS
|
__WASI_ESUCCESS
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user