diff --git a/src/hostcalls/fs.rs b/src/hostcalls/fs.rs
index b99b747..9dc423c 100644
@@ -663,13 +663,17 @@ pub fn path_open(
| host::__WASI_RIGHT_FD_ALLOCATE
| host::__WASI_RIGHT_FD_FILESTAT_SET_SIZE)
!= 0;
+ let open = (fs_rights_base & (host::__WASI_RIGHT_FD_TELL | host::__WASI_RIGHT_FD_ADVISE)) != 0
+ || (oflags & wasm32::__WASI_O_CREAT) != 0;
let mut nix_all_oflags = if read && write {
OFlag::O_RDWR
} else if write {
OFlag::O_WRONLY
- } else {
+ } else if open {
OFlag::O_RDONLY
+ } else {
+ OFlag::O_PATH
};
// on non-Capsicum systems, we always want nofollow
diff --git a/src/hostcalls/fs_helpers.rs b/src/hostcalls/fs_helpers.rs
index 5f5400e..85cae7c 100644
@@ -20,6 +20,7 @@ pub fn path_get<P: AsRef<OsStr>>(
needed_inheriting: host::__wasi_rights_t,
needs_final_component: bool,
) -> Result<(RawFd, OsString), host::__wasi_errno_t> {
+ eprintln!("--------- path_get: nfc={}", needs_final_component);
use nix::errno::Errno;
use nix::fcntl::{openat, readlinkat, OFlag};
use nix::sys::stat::Mode;
@@ -64,9 +65,18 @@ pub fn path_get<P: AsRef<OsStr>>(
// escaping the base directory.
let mut dir_stack = vec![dirfe.fd_object.rawfd];
+ let mut ends_with_slashes = false;
+ let mut path_vec = path.as_ref().to_owned().into_vec();
+ while path_vec.ends_with(b"/") {
+ ends_with_slashes = true;
+ path_vec.pop();
+ }
+ eprintln!("ews={}", ends_with_slashes);
+
// Stack of paths left to process. This is initially the `path` argument to this function, but
// any symlinks we encounter are processed by pushing them on the stack.
- let mut path_stack = vec![path.as_ref().to_owned().into_vec()];
+ eprintln!("path {:?}", path.as_ref());
+ let mut path_stack = vec![path_vec];
// Track the number of symlinks we've expanded, so we can return `ELOOP` after too many.
let mut symlink_expansions = 0;
@@ -78,10 +88,10 @@ pub fn path_get<P: AsRef<OsStr>>(
// trailing slashes. This version does way too much allocation, and is way too fiddly.
loop {
let component = if let Some(cur_path) = path_stack.pop() {
- // eprintln!(
- // "cur_path = {:?}",
- // std::str::from_utf8(cur_path.as_slice()).unwrap()
- // );
+ eprintln!(
+ "cur_path = {:?}",
+ std::str::from_utf8(cur_path.as_slice()).unwrap()
+ );
let mut split = cur_path.splitn(2, |&c| c == '/' as u8);
let head = split.next();
let tail = split.next();
@@ -144,11 +154,10 @@ pub fn path_get<P: AsRef<OsStr>>(
// should the component be a directory? it should if there is more path left to process, or
// if it has a trailing slash and `needs_final_component` is not set
component
- if !path_stack.is_empty()
- || (component.ends_with(b"/") && !needs_final_component) =>
+ if !path_stack.is_empty() || (ends_with_slashes && !needs_final_component) =>
{
match openat(
- *dir_stack.first().expect("dir_stack is never empty"),
+ *dir_stack.last().expect("dir_stack is never empty"),
component,
OFlag::O_RDONLY | OFlag::O_DIRECTORY | OFlag::O_NOFOLLOW,
Mode::empty(),
@@ -181,7 +190,7 @@ pub fn path_get<P: AsRef<OsStr>>(
// append a trailing slash if the component leading to it has one, so
// that we preserve any ENOTDIR that might come from trying to open a
// non-directory
- if component.ends_with(b"/") {
+ if ends_with_slashes {
link_path.push('/' as u8);
}
@@ -189,9 +198,16 @@ pub fn path_get<P: AsRef<OsStr>>(
continue;
}
Err(e) => {
+ // readlink returns EINVAL if the path isn't a symlink. In that case,
+ // it's more informative to return ENOTDIR.
+ let report_errno = if e == nix::Error::Sys(Errno::EINVAL) {
+ nix::Error::Sys(Errno::ENOTDIR)
+ } else {
+ e
+ };
return ret_error(
&mut dir_stack,
- host::errno_from_nix(e.as_errno().unwrap()),
+ host::errno_from_nix(report_errno.as_errno().unwrap()),
);
}
}
@@ -208,8 +224,7 @@ pub fn path_get<P: AsRef<OsStr>>(
component => {
// if there's a trailing slash, or if `LOOKUP_SYMLINK_FOLLOW` is set, attempt
// symlink expansion
- if component.ends_with(b"/") || (dirflags & host::__WASI_LOOKUP_SYMLINK_FOLLOW) != 0
- {
+ if ends_with_slashes || (dirflags & host::__WASI_LOOKUP_SYMLINK_FOLLOW) != 0 {
match readlinkat(
*dir_stack.last().expect("dir_stack is never empty"),
component,
@@ -226,7 +241,7 @@ pub fn path_get<P: AsRef<OsStr>>(
// append a trailing slash if the component leading to it has one, so
// that we preserve any ENOTDIR that might come from trying to open a
// non-directory
- if component.ends_with(b"/") {
+ if ends_with_slashes {
link_path.push('/' as u8);
}