Skip to content

Commit

Permalink
fix wasi-fyi tests (#4740)
Browse files Browse the repository at this point in the history
  • Loading branch information
maminrayej authored May 31, 2024
2 parents b05b3c0 + 60643bf commit ca63dd7
Show file tree
Hide file tree
Showing 8 changed files with 167 additions and 44 deletions.
8 changes: 7 additions & 1 deletion lib/wasix/src/syscalls/wasi/path_create_directory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ pub(crate) fn path_create_directory_internal(
}

let mut cur_dir_inode = working_dir.inode;
let mut created_directory = false;
for comp in &path_vec {
let processing_cur_dir_inode = cur_dir_inode.clone();
let mut guard = processing_cur_dir_inode.write();
Expand Down Expand Up @@ -125,6 +126,7 @@ pub(crate) fn path_create_directory_internal(
return Err(Errno::Notdir);
}
} else {
created_directory = true;
state.fs_create_dir(&adjusted_path)?;
}
let kind = Kind::Dir {
Expand Down Expand Up @@ -160,5 +162,9 @@ pub(crate) fn path_create_directory_internal(
}
}

Ok(())
if created_directory {
Ok(())
} else {
Err(Errno::Exist)
}
}
149 changes: 108 additions & 41 deletions lib/wasix/src/syscalls/wasi/path_remove_directory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,58 +47,125 @@ pub(crate) fn path_remove_directory_internal(
path: &str,
) -> Result<(), Errno> {
let env = ctx.data();
let (memory, mut state, inodes) = unsafe { env.get_memory_and_wasi_state_and_inodes(&ctx, 0) };
let (memory, state, inodes) = unsafe { env.get_memory_and_wasi_state_and_inodes(&ctx, 0) };
let working_dir = state.fs.get_fd(fd)?;

let inode = state.fs.get_inode_at_path(inodes, fd, path, false)?;
let (parent_inode, childs_name) =
state
.fs
.get_parent_inode_at_path(inodes, fd, std::path::Path::new(&path), false)?;

let host_path_to_remove = {
let guard = inode.read();
match guard.deref() {
Kind::Dir { entries, path, .. } => {
if !entries.is_empty() || state.fs_read_dir(path)?.count() != 0 {
return Err(Errno::Notempty);
}
path.clone()
}
Kind::Root { .. } => return Err(Errno::Access),
_ => return Err(Errno::Notdir),
}
};
let path = std::path::PathBuf::from(path);
let path_vec = path
.components()
.map(|comp| {
comp.as_os_str()
.to_str()
.map(|inner_str| inner_str.to_string())
.ok_or(Errno::Inval)
})
.collect::<Result<Vec<String>, Errno>>()?;
if path_vec.is_empty() {
trace!("path vector is invalid (its empty)");
return Err(Errno::Inval);
}

{
let mut guard = parent_inode.write();
let (child, parent) = path_vec.split_last().unwrap();

// if path only contains one component (the root), operation is not permitted
if child.is_empty() {
return Err(Errno::Access);
}

let mut cur_dir_inode = working_dir.inode;
for comp in path_vec.iter() {
let processing_cur_dir_inode = cur_dir_inode.clone();
let mut guard = processing_cur_dir_inode.write();
match guard.deref_mut() {
Kind::Dir {
ref mut entries, ..
ref mut entries,
path,
parent,
} => {
let removed_inode = entries.remove(&childs_name).ok_or(Errno::Inval)?;
match comp.borrow() {
".." => {
if let Some(p) = parent.upgrade() {
cur_dir_inode = p;
continue;
}
}
"." => continue,
_ => (),
}
if let Some(child) = entries.get(comp) {
cur_dir_inode = child.clone();
} else {
let parent_path = path.clone();
let mut adjusted_path = path.clone();
drop(guard);

// TODO: double check this doesn't risk breaking the sandbox
adjusted_path.push(comp);
if let Ok(adjusted_path_stat) = path_filestat_get_internal(
&memory,
state,
inodes,
fd,
0,
&adjusted_path.to_string_lossy(),
) {
if adjusted_path_stat.st_filetype != Filetype::Directory {
trace!("path is not a directory");
return Err(Errno::Notdir);
}
} else {
return Err(Errno::Noent);
}
let kind = Kind::Dir {
parent: cur_dir_inode.downgrade(),
path: adjusted_path,
entries: Default::default(),
};
let new_inode = state
.fs
.create_inode(inodes, kind, false, comp.to_string())?;

// TODO: make this a debug assert in the future
assert!(inode.ino() == removed_inode.ino());
// reborrow to insert
{
let mut guard = cur_dir_inode.write();
if let Kind::Dir {
ref mut entries, ..
} = guard.deref_mut()
{
entries.insert(comp.to_string(), new_inode.clone());
}
}
cur_dir_inode = new_inode;
}
}
Kind::Root { .. } => {
trace!("the root node can no create a directory");
return Err(Errno::Access);
}
_ => {
trace!("path is not a directory");
return Err(Errno::Notdir);
}
Kind::Root { .. } => return Err(Errno::Access),
_ => unreachable!(
"Internal logic error in wasi::path_remove_directory, parent is not a directory"
),
}
}

let env = ctx.data();
let (memory, mut state, inodes) = unsafe { env.get_memory_and_wasi_state_and_inodes(&ctx, 0) };
if let Err(err) = state.fs_remove_dir(host_path_to_remove) {
// reinsert to prevent FS from being in bad state
let mut guard = parent_inode.write();
if let Kind::Dir {
ref mut entries, ..
} = guard.deref_mut()
{
entries.insert(childs_name, inode);
if let Kind::Dir {
parent,
path: child_path,
entries,
} = cur_dir_inode.write().deref_mut()
{
let parent = parent.upgrade().ok_or(Errno::Noent)?;

if let Kind::Dir { entries, .. } = parent.write().deref_mut() {
let child_inode = entries.remove(child).ok_or(Errno::Noent)?;

if let Err(e) = state.fs_remove_dir(&child_path) {
tracing::warn!(path = ?child_path, error = ?e, "failed to remove directory");
}
}
return Err(err);

drop(parent)
}

Ok(())
Expand Down
Binary file added tests/integration/cli/resources/php/db/.ht.sqlite
Binary file not shown.
16 changes: 16 additions & 0 deletions tests/integration/cli/resources/php/test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php
for ($i = 0; $i < 5; $i++) {
$sqlite = new SQLite3('/db/.ht.sqlite');

$result = @$sqlite->query("SELECT name FROM sqlite_master WHERE type='table'");

if ($result) {
$sqlite->close();
} else {
echo "1";
exit(1);
};
}

echo "0"
?>
10 changes: 10 additions & 0 deletions tests/integration/cli/src/fixtures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@ use std::path::{Path, PathBuf};

use crate::{asset_path, c_asset_path};

pub fn php() -> (PathBuf, PathBuf, PathBuf) {
let root = Path::new(env!("CARGO_MANIFEST_DIR"));
let resources = root.join("resources").join("php");
(
root.join("tests").join("wasm").join("php.wasm"),
resources.clone(),
resources.join("db"),
)
}

/// A WEBC file containing the Python interpreter, compiled to WASI.
pub fn python() -> PathBuf {
c_asset_path().join("python-0.1.0.wasmer")
Expand Down
26 changes: 25 additions & 1 deletion tests/integration/cli/tests/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@ use predicates::str::contains;
use rand::Rng;
use reqwest::{blocking::Client, IntoUrl};
use tempfile::TempDir;
use wasmer_integration_tests_cli::{asset_path, fixtures, get_wasmer_path};
use wasmer_integration_tests_cli::{
asset_path,
fixtures::{self, php},
get_wasmer_path,
};

const HTTP_GET_TIMEOUT: Duration = Duration::from_secs(5);

Expand Down Expand Up @@ -43,6 +47,26 @@ static CACHE_RUST_LOG: Lazy<String> = Lazy::new(|| {
.join(",")
});

#[test]
fn run_php_with_sqlite() {
let (php_wasm, app_dir, db) = php();

let output = Command::new(get_wasmer_path())
.arg("-q")
.arg("run")
.arg(php_wasm)
.arg("--mapdir")
.arg(format!("/db:{}", db.display()))
.arg("--mapdir")
.arg(format!("/app:{}", app_dir.display()))
.arg("--")
.arg("/app/test.php")
.output()
.unwrap();

assert_eq!(output.stdout, "0".as_bytes().to_vec());
}

/// Ignored on Windows because running vendored packages does not work
/// since Windows does not allow `::` characters in filenames (every other OS does)
///
Expand Down
Binary file added tests/integration/cli/tests/wasm/php.wasm
Binary file not shown.
2 changes: 1 addition & 1 deletion tests/wasi-fyi/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ bash build.sh
status=0

# Define skip list as an array
SKIP_LIST=("fs_create_dir-existing-directory.wasm")
SKIP_LIST=()

# List and process .foo files
for file in *.wasm; do
Expand Down

0 comments on commit ca63dd7

Please sign in to comment.