Fix path_readlink: with a 0-sized buffer should succeed

This commit is contained in:
Jakub Konka
2019-06-13 22:46:46 +02:00
committed by Dan Gohman
parent 7fef91c1e4
commit dc05d89a08
2 changed files with 40 additions and 11 deletions

View File

@@ -580,13 +580,17 @@ pub fn path_readlink(
Ok(slice) => host_impl::path_from_raw(slice).to_owned(), Ok(slice) => host_impl::path_from_raw(slice).to_owned(),
Err(e) => return enc_errno(e), Err(e) => return enc_errno(e),
}; };
let rights = host::__WASI_RIGHT_PATH_READLINK;
let mut buf = match dec_slice_of_mut::<u8>(memory, buf_ptr, buf_len) { let mut buf = match dec_slice_of_mut::<u8>(memory, buf_ptr, buf_len) {
Ok(slice) => slice, Ok(slice) => slice,
Err(e) => return enc_errno(e), Err(e) => return enc_errno(e),
}; };
let host_bufused = let host_bufused = match hostcalls_impl::path_readlink(
match hostcalls_impl::path_readlink(wasi_ctx, dirfd, path.as_os_str(), rights, &mut buf) { wasi_ctx,
dirfd,
path.as_os_str(),
host::__WASI_RIGHT_PATH_READLINK,
&mut buf,
) {
Ok(host_bufused) => host_bufused, Ok(host_bufused) => host_bufused,
Err(e) => return enc_errno(e), Err(e) => return enc_errno(e),
}; };

View File

@@ -516,18 +516,43 @@ pub(crate) fn path_readlink(
rights: host::__wasi_rights_t, rights: host::__wasi_rights_t,
buf: &mut [u8], buf: &mut [u8],
) -> Result<usize, host::__wasi_errno_t> { ) -> Result<usize, host::__wasi_errno_t> {
use nix::fcntl::readlinkat; use nix::errno::Errno;
let (dir, path) = match path_get(wasi_ctx, dirfd, 0, path, rights, 0, false) { let (dir, path) = match path_get(wasi_ctx, dirfd, 0, path, rights, 0, false) {
Ok((dir, path)) => (dir, path), Ok((dir, path)) => (dir, path),
Err(e) => return Err(e), Err(e) => return Err(e),
}; };
let target_path = match readlinkat(dir, path.as_os_str(), buf) { let path_cstr = match std::ffi::CString::new(path.as_bytes()) {
Err(e) => return Err(host_impl::errno_from_nix(e.as_errno().unwrap())), Ok(path_cstr) => path_cstr,
Ok(target_path) => target_path, Err(_) => return Err(host::__WASI_EINVAL),
}; };
Ok(target_path.len())
// Linux requires that the buffer size is positive, whereas POSIX does not.
// Use a fake buffer to store the results if the size is zero.
// TODO: instead of using raw libc::readlinkat call here, this should really
// be fixed in `nix` crate
let fakebuf: &mut [u8] = &mut [0];
let buf_len = buf.len();
let len = unsafe {
libc::readlinkat(
dir,
path_cstr.as_ptr() as *const libc::c_char,
if buf_len == 0 {
fakebuf.as_mut_ptr()
} else {
buf.as_mut_ptr()
} as *mut libc::c_char,
if buf_len == 0 { fakebuf.len() } else { buf_len },
)
};
if len < 0 {
Err(host_impl::errno_from_nix(Errno::last()))
} else {
let len = len as usize;
Ok(if len < buf_len { len } else { buf_len })
}
} }
pub(crate) fn path_rename( pub(crate) fn path_rename(