Fix path_readlink: with a 0-sized buffer should succeed
This commit is contained in:
@@ -580,13 +580,17 @@ pub fn path_readlink(
|
||||
Ok(slice) => host_impl::path_from_raw(slice).to_owned(),
|
||||
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) {
|
||||
Ok(slice) => slice,
|
||||
Err(e) => return enc_errno(e),
|
||||
};
|
||||
let host_bufused =
|
||||
match hostcalls_impl::path_readlink(wasi_ctx, dirfd, path.as_os_str(), rights, &mut buf) {
|
||||
let host_bufused = match hostcalls_impl::path_readlink(
|
||||
wasi_ctx,
|
||||
dirfd,
|
||||
path.as_os_str(),
|
||||
host::__WASI_RIGHT_PATH_READLINK,
|
||||
&mut buf,
|
||||
) {
|
||||
Ok(host_bufused) => host_bufused,
|
||||
Err(e) => return enc_errno(e),
|
||||
};
|
||||
|
||||
@@ -516,18 +516,43 @@ pub(crate) fn path_readlink(
|
||||
rights: host::__wasi_rights_t,
|
||||
buf: &mut [u8],
|
||||
) -> 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) {
|
||||
Ok((dir, path)) => (dir, path),
|
||||
Err(e) => return Err(e),
|
||||
};
|
||||
|
||||
let target_path = match readlinkat(dir, path.as_os_str(), buf) {
|
||||
Err(e) => return Err(host_impl::errno_from_nix(e.as_errno().unwrap())),
|
||||
Ok(target_path) => target_path,
|
||||
let path_cstr = match std::ffi::CString::new(path.as_bytes()) {
|
||||
Ok(path_cstr) => path_cstr,
|
||||
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(
|
||||
|
||||
Reference in New Issue
Block a user