mirror of
https://github.com/fluencelabs/wasmer
synced 2024-12-13 22:25:40 +00:00
Merge pull request #650 from wasmerio/feature/wasi-path-rename
implement wasi::path_rename
This commit is contained in:
commit
f909f7ed1f
@ -8,6 +8,7 @@ Blocks of changes will separated by version increments.
|
||||
|
||||
Special thanks to @YaronWittenstein @penberg for their contributions.
|
||||
|
||||
- [#650](https://github.com/wasmerio/wasmer/issues/650) Implement `wasi::path_rename`, improve WASI FS public api, and allow open files to exist even when the underlying file is deleted
|
||||
- [#643](https://github.com/wasmerio/wasmer/issues/643) Implement `wasi::path_symlink` and improve WASI FS public api IO error reporting
|
||||
- [#608](https://github.com/wasmerio/wasmer/issues/608) Implement wasi syscalls `fd_allocate`, `fd_sync`, `fd_pread`, `path_link`, `path_filestat_set_times`; update WASI fs API in a WIP way; reduce coupling of WASI code to host filesystem; make debug messages from WASI more readable; improve rights-checking when calling syscalls; implement reference counting on inodes; misc bug fixes and improvements
|
||||
- [#616](https://github.com/wasmerio/wasmer/issues/616) Create the import object separately from instance instantiation in `runtime-c-api`
|
||||
|
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -1516,6 +1516,7 @@ dependencies = [
|
||||
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wabt 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasmer-runtime-core 0.6.0",
|
||||
"wasmparser 0.35.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
2
Makefile
2
Makefile
@ -7,7 +7,7 @@ generate-spectests:
|
||||
generate-emtests:
|
||||
WASM_EMSCRIPTEN_GENERATE_EMTESTS=1 cargo build -p wasmer-emscripten-tests --release
|
||||
|
||||
generate-wasitests:
|
||||
generate-wasitests: wasitests-setup
|
||||
WASM_WASI_GENERATE_WASITESTS=1 cargo build -p wasmer-wasi-tests --release -vv \
|
||||
&& echo "formatting" \
|
||||
&& cargo fmt
|
||||
|
@ -16,6 +16,7 @@ mod fseek;
|
||||
mod hello;
|
||||
mod mapdir;
|
||||
mod path_link;
|
||||
mod path_rename;
|
||||
mod path_symlink;
|
||||
mod quine;
|
||||
mod readlink;
|
||||
|
14
lib/wasi-tests/tests/wasitests/path_rename.rs
Normal file
14
lib/wasi-tests/tests/wasitests/path_rename.rs
Normal file
@ -0,0 +1,14 @@
|
||||
#[test]
|
||||
fn test_path_rename() {
|
||||
assert_wasi_output!(
|
||||
"../../wasitests/path_rename.wasm",
|
||||
"path_rename",
|
||||
vec![],
|
||||
vec![(
|
||||
"temp".to_string(),
|
||||
::std::path::PathBuf::from("wasitests/test_fs/temp")
|
||||
),],
|
||||
vec![],
|
||||
"../../wasitests/path_rename.out"
|
||||
);
|
||||
}
|
2
lib/wasi-tests/wasitests/path_rename.out
Normal file
2
lib/wasi-tests/wasitests/path_rename.out
Normal file
@ -0,0 +1,2 @@
|
||||
The original file does not still exist!
|
||||
柴犬
|
56
lib/wasi-tests/wasitests/path_rename.rs
Normal file
56
lib/wasi-tests/wasitests/path_rename.rs
Normal file
@ -0,0 +1,56 @@
|
||||
// Args:
|
||||
// mapdir: temp:wasitests/test_fs/temp
|
||||
|
||||
use std::fs;
|
||||
use std::io::{Read, Write};
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn main() {
|
||||
#[cfg(not(target_os = "wasi"))]
|
||||
let mut base = PathBuf::from("wasitests/test_fs");
|
||||
#[cfg(target_os = "wasi")]
|
||||
let mut base = PathBuf::from("/");
|
||||
|
||||
let file_to_create = base.join("temp/path_rename_file.txt");
|
||||
let file_to_rename_to = base.join("temp/path_renamed_file.txt");
|
||||
|
||||
{
|
||||
let mut f = std::fs::OpenOptions::new()
|
||||
.create_new(true)
|
||||
.write(true)
|
||||
.open(&file_to_create)
|
||||
.unwrap();
|
||||
|
||||
// text from https://ja.wikipedia.org/wiki/柴犬
|
||||
let shiba_string = "「柴犬」という名前は中央高地で使われていたもので、文献上では、昭和初期の日本犬保存会の会誌「日本犬」で用いられている。一般的には、「柴」は小ぶりな雑木を指す。
|
||||
由来には諸説があり、
|
||||
|
||||
柴藪を巧みにくぐり抜けて猟を助けることから
|
||||
赤褐色の毛色が枯れ柴に似ている(柴赤)ことから
|
||||
小さなものを表す古語の「柴」から
|
||||
|
||||
の3つの説が代表的。";
|
||||
let shiba_bytes: Vec<u8> = shiba_string.bytes().collect();
|
||||
f.write_all(&shiba_bytes[..]).unwrap();
|
||||
}
|
||||
|
||||
std::fs::rename(&file_to_create, &file_to_rename_to).unwrap();
|
||||
let mut file = fs::File::open(&file_to_rename_to).expect("Could not open file");
|
||||
if file_to_create.exists() {
|
||||
println!("The original file still exists!");
|
||||
return;
|
||||
} else {
|
||||
println!("The original file does not still exist!");
|
||||
}
|
||||
|
||||
let mut out_str = String::new();
|
||||
file.read_to_string(&mut out_str).unwrap();
|
||||
let mut test_str = String::new();
|
||||
let mut out_chars = out_str.chars();
|
||||
out_chars.next().unwrap();
|
||||
test_str.push(out_chars.next().unwrap());
|
||||
test_str.push(out_chars.next().unwrap());
|
||||
|
||||
println!("{}", test_str);
|
||||
std::fs::remove_file(file_to_rename_to).unwrap();
|
||||
}
|
BIN
lib/wasi-tests/wasitests/path_rename.wasm
Executable file
BIN
lib/wasi-tests/wasitests/path_rename.wasm
Executable file
Binary file not shown.
@ -17,3 +17,9 @@ macro_rules! wasi_try {
|
||||
wasi_try!(opt.ok_or($e))
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! get_input_str {
|
||||
($memory:expr, $data:expr, $len:expr) => {{
|
||||
wasi_try!($data.get_utf8_string($memory, $len), __WASI_EINVAL)
|
||||
}};
|
||||
}
|
||||
|
@ -106,7 +106,7 @@ pub enum Kind {
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Debug)]
|
||||
pub struct Fd {
|
||||
pub rights: __wasi_rights_t,
|
||||
pub rights_inheriting: __wasi_rights_t,
|
||||
@ -126,6 +126,8 @@ pub struct WasiFs {
|
||||
pub fd_map: HashMap<u32, Fd>,
|
||||
pub next_fd: Cell<u32>,
|
||||
inode_counter: Cell<u64>,
|
||||
/// for fds still open after the file has been deleted
|
||||
pub orphan_fds: HashMap<Inode, InodeVal>,
|
||||
|
||||
pub stdout: Box<dyn WasiFile>,
|
||||
pub stderr: Box<dyn WasiFile>,
|
||||
@ -146,6 +148,7 @@ impl WasiFs {
|
||||
fd_map: HashMap::new(),
|
||||
next_fd: Cell::new(3),
|
||||
inode_counter: Cell::new(1024),
|
||||
orphan_fds: HashMap::new(),
|
||||
|
||||
stdin: Box::new(Stdin(io::stdin())),
|
||||
stdout: Box::new(Stdout(io::stdout())),
|
||||
@ -683,6 +686,16 @@ impl WasiFs {
|
||||
self.fd_map.get(&fd).ok_or(__WASI_EBADF)
|
||||
}
|
||||
|
||||
/// gets either a normal inode or an orphaned inode
|
||||
pub fn get_inodeval_mut(&mut self, fd: __wasi_fd_t) -> Result<&mut InodeVal, __wasi_errno_t> {
|
||||
let inode = self.get_fd(fd)?.inode;
|
||||
if let Some(iv) = self.inodes.get_mut(inode) {
|
||||
Ok(iv)
|
||||
} else {
|
||||
self.orphan_fds.get_mut(&inode).ok_or(__WASI_EBADF)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn filestat_fd(&self, fd: __wasi_fd_t) -> Result<__wasi_filestat_t, __wasi_errno_t> {
|
||||
let fd = self.get_fd(fd)?;
|
||||
|
||||
@ -818,8 +831,8 @@ impl WasiFs {
|
||||
/// all refences to the given inode have been removed from the filesystem
|
||||
///
|
||||
/// returns true if the inode existed and was removed
|
||||
pub unsafe fn remove_inode(&mut self, inode: Inode) -> bool {
|
||||
self.inodes.remove(inode).is_some()
|
||||
pub unsafe fn remove_inode(&mut self, inode: Inode) -> Option<InodeVal> {
|
||||
self.inodes.remove(inode)
|
||||
}
|
||||
|
||||
fn create_virtual_root(&mut self) -> Inode {
|
||||
|
@ -158,6 +158,13 @@ pub trait WasiFile: std::fmt::Debug + Write + Read + Seek {
|
||||
fn sync_to_disk(&self) -> Result<(), WasiFsError> {
|
||||
panic!("Default implementation for compatibilty in the 0.6.X releases; this will be removed in 0.7.0. Please implement WasiFile::sync_to_disk for your type before then");
|
||||
}
|
||||
|
||||
/// Moves the file to a new location
|
||||
/// NOTE: the signature of this function will change before stabilization
|
||||
// TODO: stablizie this in 0.7.0 or 0.8.0 by removing default impl
|
||||
fn rename_file(&self, _new_name: &std::path::Path) -> Result<(), WasiFsError> {
|
||||
panic!("Default implementation for compatibilty in the 0.6.X releases; this will be removed in 0.7.0 or 0.8.0. Please implement WasiFile::rename_file for your type before then");
|
||||
}
|
||||
}
|
||||
|
||||
pub trait WasiPath {}
|
||||
@ -271,6 +278,10 @@ impl WasiFile for HostFile {
|
||||
fn sync_to_disk(&self) -> Result<(), WasiFsError> {
|
||||
self.inner.sync_all().map_err(Into::into)
|
||||
}
|
||||
|
||||
fn rename_file(&self, new_name: &std::path::Path) -> Result<(), WasiFsError> {
|
||||
std::fs::rename(&self.host_path, new_name).map_err(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<io::Error> for WasiFsError {
|
||||
|
@ -364,15 +364,14 @@ pub fn fd_allocate(
|
||||
/// - `__WASI_EISDIR`
|
||||
/// If `fd` is a directory
|
||||
/// - `__WASI_EBADF`
|
||||
/// If `fd` is invalid or not open (TODO: consider __WASI_EINVAL)
|
||||
/// If `fd` is invalid or not open
|
||||
pub fn fd_close(ctx: &mut Ctx, fd: __wasi_fd_t) -> __wasi_errno_t {
|
||||
debug!("wasi::fd_close");
|
||||
|
||||
let memory = ctx.memory(0);
|
||||
let state = get_wasi_state(ctx);
|
||||
let fd_entry = wasi_try!(state.fs.get_fd(fd)).clone();
|
||||
let inode_val = wasi_try!(state.fs.get_inodeval_mut(fd));
|
||||
|
||||
let inode_val = &mut state.fs.inodes[fd_entry.inode];
|
||||
if inode_val.is_preopened {
|
||||
return __WASI_EACCES;
|
||||
}
|
||||
@ -1303,7 +1302,7 @@ pub fn path_create_directory(
|
||||
if !has_rights(working_dir.rights, __WASI_RIGHT_PATH_CREATE_DIRECTORY) {
|
||||
return __WASI_EACCES;
|
||||
}
|
||||
let path_string = wasi_try!(path.get_utf8_string(memory, path_len), __WASI_EINVAL);
|
||||
let path_string = get_input_str!(memory, path, path_len);
|
||||
debug!("=> fd: {}, path: {}", fd, &path_string);
|
||||
|
||||
let path = std::path::PathBuf::from(path_string);
|
||||
@ -1407,8 +1406,7 @@ pub fn path_filestat_get(
|
||||
if !has_rights(root_dir.rights, __WASI_RIGHT_PATH_FILESTAT_GET) {
|
||||
return __WASI_EACCES;
|
||||
}
|
||||
|
||||
let path_string = wasi_try!(path.get_utf8_string(memory, path_len).ok_or(__WASI_EINVAL));
|
||||
let path_string = get_input_str!(memory, path, path_len);
|
||||
|
||||
debug!("=> base_fd: {}, path: {}", fd, &path_string);
|
||||
|
||||
@ -1459,6 +1457,7 @@ pub fn path_filestat_set_times(
|
||||
let memory = ctx.memory(0);
|
||||
let state = get_wasi_state(ctx);
|
||||
let fd_entry = wasi_try!(state.fs.get_fd(fd)).clone();
|
||||
let fd_inode = fd_entry.inode;
|
||||
if !has_rights(fd_entry.rights, __WASI_RIGHT_PATH_FILESTAT_SET_TIMES) {
|
||||
return __WASI_EACCES;
|
||||
}
|
||||
@ -1469,7 +1468,7 @@ pub fn path_filestat_set_times(
|
||||
return __WASI_EINVAL;
|
||||
}
|
||||
|
||||
let path_string = wasi_try!(path.get_utf8_string(memory, path_len).ok_or(__WASI_EINVAL));
|
||||
let path_string = get_input_str!(memory, path, path_len);
|
||||
debug!("=> base_fd: {}, path: {}", fd, &path_string);
|
||||
|
||||
let file_inode = wasi_try!(state.fs.get_inode_at_path(
|
||||
@ -1482,7 +1481,7 @@ pub fn path_filestat_set_times(
|
||||
.get_stat_for_kind(&state.fs.inodes[file_inode].kind)
|
||||
.ok_or(__WASI_EIO));
|
||||
|
||||
let inode = &mut state.fs.inodes[fd_entry.inode];
|
||||
let inode = &mut state.fs.inodes[fd_inode];
|
||||
|
||||
if fst_flags & __WASI_FILESTAT_SET_ATIM != 0 || fst_flags & __WASI_FILESTAT_SET_ATIM_NOW != 0 {
|
||||
let time_to_set = if fst_flags & __WASI_FILESTAT_SET_ATIM != 0 {
|
||||
@ -1555,15 +1554,8 @@ pub fn path_link(
|
||||
}
|
||||
let memory = ctx.memory(0);
|
||||
let state = get_wasi_state(ctx);
|
||||
let old_path_str = wasi_try!(
|
||||
old_path.get_utf8_string(memory, old_path_len),
|
||||
__WASI_EINVAL
|
||||
);
|
||||
let new_path_str = wasi_try!(
|
||||
new_path.get_utf8_string(memory, new_path_len),
|
||||
__WASI_EINVAL
|
||||
);
|
||||
|
||||
let old_path_str = get_input_str!(memory, old_path, old_path_len);
|
||||
let new_path_str = get_input_str!(memory, new_path, new_path_len);
|
||||
let source_fd = wasi_try!(state.fs.get_fd(old_fd));
|
||||
let target_fd = wasi_try!(state.fs.get_fd(new_fd));
|
||||
debug!(
|
||||
@ -1661,14 +1653,14 @@ pub fn path_open(
|
||||
// - __WASI_O_EXCL (fail if file exists)
|
||||
// - __WASI_O_TRUNC (truncate size to 0)
|
||||
|
||||
let working_dir = wasi_try!(state.fs.get_fd(dirfd)).clone();
|
||||
let working_dir = wasi_try!(state.fs.get_fd(dirfd));
|
||||
let working_dir_rights_inheriting = working_dir.rights_inheriting;
|
||||
|
||||
// ASSUMPTION: open rights apply recursively
|
||||
if !has_rights(working_dir.rights, __WASI_RIGHT_PATH_OPEN) {
|
||||
return __WASI_EACCES;
|
||||
}
|
||||
|
||||
let path_string = wasi_try!(path.get_utf8_string(memory, path_len).ok_or(__WASI_EINVAL));
|
||||
let path_string = get_input_str!(memory, path, path_len);
|
||||
|
||||
debug!("=> fd: {}, path: {}", dirfd, &path_string);
|
||||
|
||||
@ -1680,13 +1672,13 @@ pub fn path_open(
|
||||
);
|
||||
|
||||
if let Ok(m) = maybe_inode {
|
||||
dbg!(&state.fs.inodes[m]);
|
||||
&state.fs.inodes[m];
|
||||
}
|
||||
|
||||
// TODO: traverse rights of dirs properly
|
||||
// COMMENTED OUT: WASI isn't giving appropriate rights here when opening
|
||||
// TODO: look into this; file a bug report if this is a bug
|
||||
let adjusted_rights = /*fs_rights_base &*/ working_dir.rights_inheriting;
|
||||
let adjusted_rights = /*fs_rights_base &*/ working_dir_rights_inheriting;
|
||||
let inode = if let Ok(inode) = maybe_inode {
|
||||
// Happy path, we found the file we're trying to open
|
||||
match &mut state.fs.inodes[inode].kind {
|
||||
@ -1817,6 +1809,22 @@ pub fn path_open(
|
||||
__WASI_ESUCCESS
|
||||
}
|
||||
|
||||
/// ### `path_readlink()`
|
||||
/// Read the value of a symlink
|
||||
/// Inputs:
|
||||
/// - `__wasi_fd_t dir_fd`
|
||||
/// The base directory from which `path` is understood
|
||||
/// - `const char *path`
|
||||
/// Pointer to UTF-8 bytes that make up the path to the symlink
|
||||
/// - `u32 path_len`
|
||||
/// The number of bytes to read from `path`
|
||||
/// - `u32 buf_len`
|
||||
/// Space available pointed to by `buf`
|
||||
/// Outputs:
|
||||
/// - `char *buf`
|
||||
/// Pointer to characters containing the path that the symlink points to
|
||||
/// - `u32 buf_used`
|
||||
/// The number of bytes written to `buf`
|
||||
pub fn path_readlink(
|
||||
ctx: &mut Ctx,
|
||||
dir_fd: __wasi_fd_t,
|
||||
@ -1834,7 +1842,7 @@ pub fn path_readlink(
|
||||
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 = get_input_str!(memory, path, path_len);
|
||||
let inode = wasi_try!(state.fs.get_inode_at_path(dir_fd, path_str, false));
|
||||
|
||||
if let Kind::Symlink { relative_path, .. } = &state.fs.inodes[inode].kind {
|
||||
@ -1875,7 +1883,7 @@ pub fn path_remove_directory(
|
||||
let memory = ctx.memory(0);
|
||||
|
||||
let base_dir = wasi_try!(state.fs.fd_map.get(&fd), __WASI_EBADF);
|
||||
let path_str = wasi_try!(path.get_utf8_string(memory, path_len), __WASI_EINVAL);
|
||||
let path_str = get_input_str!(memory, path, path_len);
|
||||
|
||||
let inode = wasi_try!(state.fs.get_inode_at_path(fd, path_str, false));
|
||||
let (parent_inode, childs_name) =
|
||||
@ -1927,6 +1935,21 @@ pub fn path_remove_directory(
|
||||
__WASI_ESUCCESS
|
||||
}
|
||||
|
||||
/// ### `path_rename()`
|
||||
/// Rename a file or directory
|
||||
/// Inputs:
|
||||
/// - `__wasi_fd_t old_fd`
|
||||
/// The base directory for `old_path`
|
||||
/// - `const char* old_path`
|
||||
/// Pointer to UTF8 bytes, the file to be renamed
|
||||
/// - `u32 old_path_len`
|
||||
/// The number of bytes to read from `old_path`
|
||||
/// - `__wasi_fd_t new_fd`
|
||||
/// The base directory for `new_path`
|
||||
/// - `const char* new_path`
|
||||
/// Pointer to UTF8 bytes, the new file name
|
||||
/// - `u32 new_path_len`
|
||||
/// The number of bytes to read from `new_path`
|
||||
pub fn path_rename(
|
||||
ctx: &mut Ctx,
|
||||
old_fd: __wasi_fd_t,
|
||||
@ -1937,7 +1960,90 @@ pub fn path_rename(
|
||||
new_path_len: u32,
|
||||
) -> __wasi_errno_t {
|
||||
debug!("wasi::path_rename");
|
||||
unimplemented!("wasi::path_rename")
|
||||
let memory = ctx.memory(0);
|
||||
let state = get_wasi_state(ctx);
|
||||
let source_str = get_input_str!(memory, old_path, old_path_len);
|
||||
let source_path = std::path::Path::new(source_str);
|
||||
let target_str = get_input_str!(memory, new_path, new_path_len);
|
||||
let target_path = std::path::Path::new(target_str);
|
||||
|
||||
{
|
||||
let source_fd = wasi_try!(state.fs.get_fd(old_fd));
|
||||
if !has_rights(source_fd.rights, __WASI_RIGHT_PATH_RENAME_SOURCE) {
|
||||
return __WASI_EACCES;
|
||||
}
|
||||
let target_fd = wasi_try!(state.fs.get_fd(new_fd));
|
||||
if !has_rights(target_fd.rights, __WASI_RIGHT_PATH_RENAME_TARGET) {
|
||||
return __WASI_EACCES;
|
||||
}
|
||||
}
|
||||
|
||||
let (source_parent_inode, source_entry_name) =
|
||||
wasi_try!(state.fs.get_parent_inode_at_path(old_fd, source_path, true));
|
||||
let (target_parent_inode, target_entry_name) =
|
||||
wasi_try!(state.fs.get_parent_inode_at_path(new_fd, target_path, true));
|
||||
|
||||
let host_adjusted_target_path = match &state.fs.inodes[target_parent_inode].kind {
|
||||
Kind::Dir { entries, path, .. } => {
|
||||
if entries.contains_key(&target_entry_name) {
|
||||
return __WASI_EEXIST;
|
||||
}
|
||||
let mut out_path = path.clone();
|
||||
// remove fd's own name which will be double counted
|
||||
out_path.pop();
|
||||
out_path.push(target_path);
|
||||
out_path
|
||||
}
|
||||
Kind::Root { .. } => return __WASI_ENOTCAPABLE,
|
||||
Kind::Symlink { .. } | Kind::File { .. } | Kind::Buffer { .. } => {
|
||||
unreachable!("Fatal internal logic error: parent of inode is not a directory")
|
||||
}
|
||||
};
|
||||
let source_entry = match &mut state.fs.inodes[source_parent_inode].kind {
|
||||
Kind::Dir { entries, .. } => wasi_try!(entries.remove(&source_entry_name), __WASI_EINVAL),
|
||||
Kind::Root { .. } => return __WASI_ENOTCAPABLE,
|
||||
Kind::Symlink { .. } | Kind::File { .. } | Kind::Buffer { .. } => {
|
||||
unreachable!("Fatal internal logic error: parent of inode is not a directory")
|
||||
}
|
||||
};
|
||||
|
||||
match &mut state.fs.inodes[source_entry].kind {
|
||||
Kind::File {
|
||||
handle,
|
||||
ref mut path,
|
||||
} => {
|
||||
let result = if let Some(h) = handle {
|
||||
h.rename_file(&host_adjusted_target_path)
|
||||
.map_err(|e| e.into_wasi_err())
|
||||
} else {
|
||||
let out =
|
||||
std::fs::rename(&path, &host_adjusted_target_path).map_err(|_| __WASI_EIO);
|
||||
*path = host_adjusted_target_path;
|
||||
out
|
||||
};
|
||||
// if the above operation failed we have to revert the previous change and then fail
|
||||
if let Err(e) = result {
|
||||
if let Kind::Dir { entries, .. } = &mut state.fs.inodes[source_parent_inode].kind {
|
||||
entries.insert(source_entry_name, source_entry);
|
||||
return e;
|
||||
}
|
||||
}
|
||||
}
|
||||
Kind::Dir { path, .. } => unimplemented!("wasi::path_rename on Directories"),
|
||||
Kind::Buffer { .. } => {}
|
||||
Kind::Symlink { .. } => {}
|
||||
Kind::Root { .. } => unreachable!("The root can not be moved"),
|
||||
}
|
||||
|
||||
if let Kind::Dir { entries, .. } = &mut state.fs.inodes[target_parent_inode].kind {
|
||||
let result = entries.insert(target_entry_name, source_entry);
|
||||
assert!(
|
||||
result.is_none(),
|
||||
"Fatal error: race condition on filesystem detected or internal logic error"
|
||||
);
|
||||
}
|
||||
|
||||
__WASI_ESUCCESS
|
||||
}
|
||||
|
||||
/// ### `path_symlink()`
|
||||
@ -1964,14 +2070,8 @@ pub fn path_symlink(
|
||||
debug!("wasi::path_symlink");
|
||||
let state = get_wasi_state(ctx);
|
||||
let memory = ctx.memory(0);
|
||||
let old_path_str = wasi_try!(
|
||||
old_path.get_utf8_string(memory, old_path_len),
|
||||
__WASI_EINVAL
|
||||
);
|
||||
let new_path_str = wasi_try!(
|
||||
new_path.get_utf8_string(memory, new_path_len),
|
||||
__WASI_EINVAL
|
||||
);
|
||||
let old_path_str = get_input_str!(memory, old_path, old_path_len);
|
||||
let new_path_str = get_input_str!(memory, new_path, new_path_len);
|
||||
let base_fd = wasi_try!(state.fs.get_fd(fd));
|
||||
if !has_rights(base_fd.rights, __WASI_RIGHT_PATH_SYMLINK) {
|
||||
return __WASI_EACCES;
|
||||
@ -2053,7 +2153,7 @@ pub fn path_unlink_file(
|
||||
if !has_rights(base_dir.rights, __WASI_RIGHT_PATH_UNLINK_FILE) {
|
||||
return __WASI_EACCES;
|
||||
}
|
||||
let path_str = wasi_try!(path.get_utf8_string(memory, path_len).ok_or(__WASI_EINVAL));
|
||||
let path_str = get_input_str!(memory, path, path_len);
|
||||
debug!("Requested file: {}", path_str);
|
||||
|
||||
let inode = wasi_try!(state.fs.get_inode_at_path(fd, path_str, false));
|
||||
@ -2097,16 +2197,43 @@ pub fn path_unlink_file(
|
||||
}
|
||||
_ => unimplemented!("wasi::path_unlink_file for Buffer"),
|
||||
}
|
||||
let inode_was_removed = unsafe { state.fs.remove_inode(removed_inode) };
|
||||
// TODO: test this on Windows and actually make it portable
|
||||
// make the file an orphan fd if the fd is still open
|
||||
let fd_is_orphaned = if let Kind::File { handle, .. } = &state.fs.inodes[removed_inode].kind
|
||||
{
|
||||
handle.is_some()
|
||||
} else {
|
||||
false
|
||||
};
|
||||
let removed_inode_val = unsafe { state.fs.remove_inode(removed_inode) };
|
||||
assert!(
|
||||
inode_was_removed,
|
||||
removed_inode_val.is_some(),
|
||||
"Inode could not be removed because it doesn't exist"
|
||||
);
|
||||
|
||||
if fd_is_orphaned {
|
||||
state
|
||||
.fs
|
||||
.orphan_fds
|
||||
.insert(removed_inode, removed_inode_val.unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
__WASI_ESUCCESS
|
||||
}
|
||||
|
||||
/// ### `poll_oneoff()`
|
||||
/// Concurrently poll for a set of events
|
||||
/// Inputs:
|
||||
/// - `const __wasi_subscription_t *in`
|
||||
/// The events to subscribe to
|
||||
/// - `__wasi_event_t *out`
|
||||
/// The events that have occured
|
||||
/// - `u32 nsubscriptions`
|
||||
/// The number of subscriptions and the number of events
|
||||
/// Output:
|
||||
/// - `u32 nevents`
|
||||
/// The number of events seen
|
||||
pub fn poll_oneoff(
|
||||
ctx: &mut Ctx,
|
||||
in_: WasmPtr<__wasi_subscription_t, Array>,
|
||||
@ -2117,6 +2244,7 @@ pub fn poll_oneoff(
|
||||
debug!("wasi::poll_oneoff");
|
||||
unimplemented!("wasi::poll_oneoff")
|
||||
}
|
||||
|
||||
pub fn proc_exit(ctx: &mut Ctx, code: __wasi_exitcode_t) -> Result<Infallible, ExitCode> {
|
||||
debug!("wasi::proc_exit, {}", code);
|
||||
Err(ExitCode { code })
|
||||
|
Loading…
Reference in New Issue
Block a user