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:
Dan Gohman
2019-10-29 14:14:39 -07:00
committed by Jakub Konka
parent f3a5186230
commit 0302f1a164
2 changed files with 54 additions and 51 deletions

View File

@@ -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);

View File

@@ -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