Make path_get return ENOTDIR when the base isn't a directory.
Return `ENOTDIR` instead of `ENOTCAPABLE` when `*at` functions are given a non-directory as their base. This is in accordance with POSIX: https://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html Currently wasi-libc contains some code to detect such cases and rewrite `ENOTCAPABLE` to `ENOTDIR`, however it's better for WASI implementations to just do the right thing in the first place.
This commit is contained in:
@@ -468,10 +468,8 @@ pub(crate) unsafe fn path_create_directory(
|
||||
trace!(" | (path_ptr,path_len)='{}'", path);
|
||||
|
||||
let rights = host::__WASI_RIGHT_PATH_OPEN | host::__WASI_RIGHT_PATH_CREATE_DIRECTORY;
|
||||
let dirfd = wasi_ctx
|
||||
.get_fd_entry(dirfd, rights, 0)
|
||||
.and_then(|fe| fe.fd_object.descriptor.as_file())?;
|
||||
let resolved = path_get(dirfd, 0, path, false)?;
|
||||
let fo = &wasi_ctx.get_fd_entry(dirfd, rights, 0)?.fd_object;
|
||||
let resolved = path_get(fo, 0, path, false)?;
|
||||
|
||||
hostcalls_impl::path_create_directory(resolved)
|
||||
}
|
||||
@@ -508,14 +506,14 @@ pub(crate) unsafe fn path_link(
|
||||
trace!(" | (old_path_ptr,old_path_len)='{}'", old_path);
|
||||
trace!(" | (new_path_ptr,new_path_len)='{}'", new_path);
|
||||
|
||||
let old_dirfd = wasi_ctx
|
||||
.get_fd_entry(old_dirfd, host::__WASI_RIGHT_PATH_LINK_SOURCE, 0)
|
||||
.and_then(|fe| fe.fd_object.descriptor.as_file())?;
|
||||
let new_dirfd = wasi_ctx
|
||||
.get_fd_entry(new_dirfd, host::__WASI_RIGHT_PATH_LINK_TARGET, 0)
|
||||
.and_then(|fe| fe.fd_object.descriptor.as_file())?;
|
||||
let resolved_old = path_get(old_dirfd, 0, old_path, false)?;
|
||||
let resolved_new = path_get(new_dirfd, 0, new_path, false)?;
|
||||
let old_fo = &wasi_ctx
|
||||
.get_fd_entry(old_dirfd, host::__WASI_RIGHT_PATH_LINK_SOURCE, 0)?
|
||||
.fd_object;
|
||||
let new_fo = &wasi_ctx
|
||||
.get_fd_entry(new_dirfd, host::__WASI_RIGHT_PATH_LINK_TARGET, 0)?
|
||||
.fd_object;
|
||||
let resolved_old = path_get(old_fo, 0, old_path, false)?;
|
||||
let resolved_new = path_get(new_fo, 0, new_path, false)?;
|
||||
|
||||
hostcalls_impl::path_link(resolved_old, resolved_new)
|
||||
}
|
||||
@@ -562,10 +560,10 @@ pub(crate) unsafe fn path_open(
|
||||
|
||||
let (needed_base, needed_inheriting) =
|
||||
path_open_rights(fs_rights_base, fs_rights_inheriting, oflags, fs_flags);
|
||||
let dirfd = wasi_ctx
|
||||
.get_fd_entry(dirfd, needed_base, needed_inheriting)
|
||||
.and_then(|fe| fe.fd_object.descriptor.as_file())?;
|
||||
let resolved = path_get(dirfd, dirflags, path, oflags & host::__WASI_O_CREAT != 0)?;
|
||||
let fo = &wasi_ctx
|
||||
.get_fd_entry(dirfd, needed_base, needed_inheriting)?
|
||||
.fd_object;
|
||||
let resolved = path_get(fo, dirflags, path, oflags & host::__WASI_O_CREAT != 0)?;
|
||||
|
||||
// which open mode do we need?
|
||||
let read = fs_rights_base & (host::__WASI_RIGHT_FD_READ | host::__WASI_RIGHT_FD_READDIR) != 0;
|
||||
@@ -654,10 +652,10 @@ pub(crate) unsafe fn path_readlink(
|
||||
|
||||
trace!(" | (path_ptr,path_len)='{}'", &path);
|
||||
|
||||
let dirfd = wasi_ctx
|
||||
.get_fd_entry(dirfd, host::__WASI_RIGHT_PATH_READLINK, 0)
|
||||
.and_then(|fe| fe.fd_object.descriptor.as_file())?;
|
||||
let resolved = path_get(dirfd, 0, &path, false)?;
|
||||
let fo = &wasi_ctx
|
||||
.get_fd_entry(dirfd, host::__WASI_RIGHT_PATH_READLINK, 0)?
|
||||
.fd_object;
|
||||
let resolved = path_get(fo, 0, &path, false)?;
|
||||
|
||||
let mut buf = dec_slice_of_mut::<u8>(memory, buf_ptr, buf_len)?;
|
||||
|
||||
@@ -699,14 +697,14 @@ pub(crate) unsafe fn path_rename(
|
||||
trace!(" | (old_path_ptr,old_path_len)='{}'", old_path);
|
||||
trace!(" | (new_path_ptr,new_path_len)='{}'", new_path);
|
||||
|
||||
let old_dirfd = wasi_ctx
|
||||
.get_fd_entry(old_dirfd, host::__WASI_RIGHT_PATH_RENAME_SOURCE, 0)
|
||||
.and_then(|fe| fe.fd_object.descriptor.as_file())?;
|
||||
let new_dirfd = wasi_ctx
|
||||
.get_fd_entry(new_dirfd, host::__WASI_RIGHT_PATH_RENAME_TARGET, 0)
|
||||
.and_then(|fe| fe.fd_object.descriptor.as_file())?;
|
||||
let resolved_old = path_get(old_dirfd, 0, old_path, true)?;
|
||||
let resolved_new = path_get(new_dirfd, 0, new_path, true)?;
|
||||
let old_fo = &wasi_ctx
|
||||
.get_fd_entry(old_dirfd, host::__WASI_RIGHT_PATH_RENAME_SOURCE, 0)?
|
||||
.fd_object;
|
||||
let new_fo = &wasi_ctx
|
||||
.get_fd_entry(new_dirfd, host::__WASI_RIGHT_PATH_RENAME_TARGET, 0)?
|
||||
.fd_object;
|
||||
let resolved_old = path_get(old_fo, 0, old_path, true)?;
|
||||
let resolved_new = path_get(new_fo, 0, new_path, true)?;
|
||||
|
||||
log::debug!("path_rename resolved_old={:?}", resolved_old);
|
||||
log::debug!("path_rename resolved_new={:?}", resolved_new);
|
||||
@@ -845,10 +843,10 @@ pub(crate) unsafe fn path_filestat_get(
|
||||
|
||||
trace!(" | (path_ptr,path_len)='{}'", path);
|
||||
|
||||
let dirfd = wasi_ctx
|
||||
.get_fd_entry(dirfd, host::__WASI_RIGHT_PATH_FILESTAT_GET, 0)
|
||||
.and_then(|fe| fe.fd_object.descriptor.as_file())?;
|
||||
let resolved = path_get(dirfd, dirflags, path, false)?;
|
||||
let fo = &wasi_ctx
|
||||
.get_fd_entry(dirfd, host::__WASI_RIGHT_PATH_FILESTAT_GET, 0)?
|
||||
.fd_object;
|
||||
let resolved = path_get(fo, dirflags, path, false)?;
|
||||
let host_filestat = hostcalls_impl::path_filestat_get(resolved, dirflags)?;
|
||||
|
||||
trace!(" | *filestat_ptr={:?}", host_filestat);
|
||||
@@ -887,10 +885,10 @@ pub(crate) unsafe fn path_filestat_set_times(
|
||||
let st_mtim = dec_timestamp(st_mtim);
|
||||
let fst_flags = dec_fstflags(fst_flags);
|
||||
|
||||
let dirfd = wasi_ctx
|
||||
.get_fd_entry(dirfd, host::__WASI_RIGHT_PATH_FILESTAT_SET_TIMES, 0)
|
||||
.and_then(|fe| fe.fd_object.descriptor.as_file())?;
|
||||
let resolved = path_get(dirfd, dirflags, path, false)?;
|
||||
let fo = &wasi_ctx
|
||||
.get_fd_entry(dirfd, host::__WASI_RIGHT_PATH_FILESTAT_SET_TIMES, 0)?
|
||||
.fd_object;
|
||||
let resolved = path_get(fo, dirflags, path, false)?;
|
||||
|
||||
hostcalls_impl::path_filestat_set_times(resolved, dirflags, st_atim, st_mtim, fst_flags)
|
||||
}
|
||||
@@ -922,10 +920,10 @@ pub(crate) unsafe fn path_symlink(
|
||||
trace!(" | (old_path_ptr,old_path_len)='{}'", old_path);
|
||||
trace!(" | (new_path_ptr,new_path_len)='{}'", new_path);
|
||||
|
||||
let dirfd = wasi_ctx
|
||||
.get_fd_entry(dirfd, host::__WASI_RIGHT_PATH_SYMLINK, 0)
|
||||
.and_then(|fe| fe.fd_object.descriptor.as_file())?;
|
||||
let resolved_new = path_get(dirfd, 0, new_path, true)?;
|
||||
let fo = &wasi_ctx
|
||||
.get_fd_entry(dirfd, host::__WASI_RIGHT_PATH_SYMLINK, 0)?
|
||||
.fd_object;
|
||||
let resolved_new = path_get(fo, 0, new_path, true)?;
|
||||
|
||||
hostcalls_impl::path_symlink(old_path, resolved_new)
|
||||
}
|
||||
@@ -949,10 +947,10 @@ pub(crate) unsafe fn path_unlink_file(
|
||||
|
||||
trace!(" | (path_ptr,path_len)='{}'", path);
|
||||
|
||||
let dirfd = wasi_ctx
|
||||
.get_fd_entry(dirfd, host::__WASI_RIGHT_PATH_UNLINK_FILE, 0)
|
||||
.and_then(|fe| fe.fd_object.descriptor.as_file())?;
|
||||
let resolved = path_get(dirfd, 0, path, false)?;
|
||||
let fo = &wasi_ctx
|
||||
.get_fd_entry(dirfd, host::__WASI_RIGHT_PATH_UNLINK_FILE, 0)?
|
||||
.fd_object;
|
||||
let resolved = path_get(fo, 0, path, false)?;
|
||||
|
||||
hostcalls_impl::path_unlink_file(resolved)
|
||||
}
|
||||
@@ -976,10 +974,10 @@ pub(crate) unsafe fn path_remove_directory(
|
||||
|
||||
trace!(" | (path_ptr,path_len)='{}'", path);
|
||||
|
||||
let dirfd = wasi_ctx
|
||||
.get_fd_entry(dirfd, host::__WASI_RIGHT_PATH_REMOVE_DIRECTORY, 0)
|
||||
.and_then(|fe| fe.fd_object.descriptor.as_file())?;
|
||||
let resolved = path_get(dirfd, 0, path, true)?;
|
||||
let fo = &wasi_ctx
|
||||
.get_fd_entry(dirfd, host::__WASI_RIGHT_PATH_REMOVE_DIRECTORY, 0)?
|
||||
.fd_object;
|
||||
let resolved = path_get(fo, 0, path, true)?;
|
||||
|
||||
log::debug!("path_remove_directory resolved={:?}", resolved);
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
use crate::helpers::str_to_cstring;
|
||||
use crate::sys::host_impl;
|
||||
use crate::sys::hostcalls_impl::fs_helpers::*;
|
||||
use crate::{host, Error, Result};
|
||||
use crate::{fdentry::FdObject, host, Error, Result};
|
||||
use std::ffi::CString;
|
||||
use std::fs::File;
|
||||
use std::path::{Component, Path};
|
||||
@@ -31,7 +31,7 @@ impl PathGet {
|
||||
///
|
||||
/// This is a workaround for not having Capsicum support in the OS.
|
||||
pub(crate) fn path_get(
|
||||
dirfd: &File,
|
||||
fo: &FdObject,
|
||||
dirflags: host::__wasi_lookupflags_t,
|
||||
path: &str,
|
||||
needs_final_component: bool,
|
||||
@@ -43,7 +43,12 @@ pub(crate) fn path_get(
|
||||
return Err(Error::EILSEQ);
|
||||
}
|
||||
|
||||
let dirfd = dirfd.try_clone()?;
|
||||
if fo.file_type != host::__WASI_FILETYPE_DIRECTORY {
|
||||
// if `dirfd` doesn't refer to a directory, return `ENOTDIR`.
|
||||
return Err(Error::ENOTDIR);
|
||||
}
|
||||
|
||||
let dirfd = fo.descriptor.as_file()?.try_clone()?;
|
||||
|
||||
// Stack of directory file descriptors. Index 0 always corresponds with the directory provided
|
||||
// to this function. Entering a directory causes a file descriptor to be pushed, while handling
|
||||
|
||||
Reference in New Issue
Block a user