diff --git a/library/std/src/sys/wasi/fs.rs b/library/std/src/sys/wasi/fs.rs index 120b9f59f1e..4134ef67671 100644 --- a/library/std/src/sys/wasi/fs.rs +++ b/library/std/src/sys/wasi/fs.rs @@ -627,33 +627,50 @@ fn open_at(fd: &WasiFd, path: &Path, opts: &OpenOptions) -> io::Result { /// to any pre-opened file descriptor. fn open_parent(p: &Path) -> io::Result<(ManuallyDrop, PathBuf)> { let p = CString::new(p.as_os_str().as_bytes())?; - unsafe { - let mut ret = ptr::null(); - let fd = __wasilibc_find_relpath(p.as_ptr(), &mut ret); - if fd == -1 { - let msg = format!( - "failed to find a pre-opened file descriptor \ - through which {:?} could be opened", - p + let mut buf = Vec::::with_capacity(512); + loop { + unsafe { + let mut relative_path = buf.as_ptr().cast(); + let mut abs_prefix = ptr::null(); + let fd = __wasilibc_find_relpath( + p.as_ptr(), + &mut abs_prefix, + &mut relative_path, + buf.capacity(), ); - return Err(io::Error::new(io::ErrorKind::Other, msg)); + if fd == -1 { + if io::Error::last_os_error().raw_os_error() == Some(libc::ENOMEM) { + // Trigger the internal buffer resizing logic of `Vec` by requiring + // more space than the current capacity. + let cap = buf.capacity(); + buf.set_len(cap); + buf.reserve(1); + continue; + } + let msg = format!( + "failed to find a pre-opened file descriptor \ + through which {:?} could be opened", + p + ); + return Err(io::Error::new(io::ErrorKind::Other, msg)); + } + let len = CStr::from_ptr(buf.as_ptr().cast()).to_bytes().len(); + buf.set_len(len); + buf.shrink_to_fit(); + + return Ok(( + ManuallyDrop::new(WasiFd::from_raw(fd as u32)), + PathBuf::from(OsString::from_vec(buf)), + )); } - let path = Path::new(OsStr::from_bytes(CStr::from_ptr(ret).to_bytes())); - - // FIXME: right now `path` is a pointer into `p`, the `CString` above. - // When we return `p` is deallocated and we can't use it, so we need to - // currently separately allocate `path`. If this becomes an issue though - // we should probably turn this into a closure-taking interface or take - // `&CString` and then pass off `&Path` tied to the same lifetime. - let path = path.to_path_buf(); - - return Ok((ManuallyDrop::new(WasiFd::from_raw(fd as u32)), path)); } extern "C" { pub fn __wasilibc_find_relpath( path: *const libc::c_char, + abs_prefix: *mut *const libc::c_char, relative_path: *mut *const libc::c_char, + relative_path_len: libc::size_t, ) -> libc::c_int; } } diff --git a/library/std/src/sys/wasi/os.rs b/library/std/src/sys/wasi/os.rs index 33c796ae941..185d6109cb9 100644 --- a/library/std/src/sys/wasi/os.rs +++ b/library/std/src/sys/wasi/os.rs @@ -13,6 +13,16 @@ use crate::sys::memchr; use crate::sys::{unsupported, Void}; use crate::vec; +// Add a few symbols not in upstream `libc` just yet. +mod libc { + pub use libc::*; + + extern "C" { + pub fn getcwd(buf: *mut c_char, size: size_t) -> *mut c_char; + pub fn chdir(dir: *const c_char) -> c_int; + } +} + #[cfg(not(target_feature = "atomics"))] pub unsafe fn env_lock() -> impl Any { // No need for a lock if we're single-threaded, but this function will need @@ -41,11 +51,40 @@ pub fn error_string(errno: i32) -> String { } pub fn getcwd() -> io::Result { - unsupported() + let mut buf = Vec::with_capacity(512); + loop { + unsafe { + let ptr = buf.as_mut_ptr() as *mut libc::c_char; + if !libc::getcwd(ptr, buf.capacity()).is_null() { + let len = CStr::from_ptr(buf.as_ptr() as *const libc::c_char).to_bytes().len(); + buf.set_len(len); + buf.shrink_to_fit(); + return Ok(PathBuf::from(OsString::from_vec(buf))); + } else { + let error = io::Error::last_os_error(); + if error.raw_os_error() != Some(libc::ERANGE) { + return Err(error); + } + } + + // Trigger the internal buffer resizing logic of `Vec` by requiring + // more space than the current capacity. + let cap = buf.capacity(); + buf.set_len(cap); + buf.reserve(1); + } + } } -pub fn chdir(_: &path::Path) -> io::Result<()> { - unsupported() +pub fn chdir(p: &path::Path) -> io::Result<()> { + let p: &OsStr = p.as_ref(); + let p = CString::new(p.as_bytes())?; + unsafe { + match libc::chdir(p.as_ptr()) == (0 as libc::c_int) { + true => Ok(()), + false => Err(io::Error::last_os_error()), + } + } } pub struct SplitPaths<'a>(&'a Void); diff --git a/src/ci/docker/host-x86_64/dist-various-2/build-wasi-toolchain.sh b/src/ci/docker/host-x86_64/dist-various-2/build-wasi-toolchain.sh index c6db200f866..82d0f7dc471 100755 --- a/src/ci/docker/host-x86_64/dist-various-2/build-wasi-toolchain.sh +++ b/src/ci/docker/host-x86_64/dist-various-2/build-wasi-toolchain.sh @@ -1,18 +1,16 @@ #!/bin/sh -# -# ignore-tidy-linelength set -ex -# Originally from https://github.com/llvm/llvm-project/releases/download/llvmorg-10.0.0/clang+llvm-10.0.0-x86_64-linux-gnu-ubuntu-18.04.tar.xz -curl https://ci-mirrors.rust-lang.org/rustc/clang%2Bllvm-10.0.0-x86_64-linux-gnu-ubuntu-18.04.tar.xz | \ +# Originally from https://github.com/llvm/llvm-project/releases/download/llvmorg-11.0.0/clang+llvm-11.0.0-x86_64-linux-gnu-ubuntu-16.04.tar.xz +curl https://ci-mirrors.rust-lang.org/rustc/2021-01-14-clang%2Bllvm-11.0.1-x86_64-linux-gnu-ubuntu-16.04.tar.xz | \ tar xJf - -export PATH=`pwd`/clang+llvm-10.0.0-x86_64-linux-gnu-ubuntu-18.04/bin:$PATH +export PATH=`pwd`/clang+llvm-11.0.1-x86_64-linux-gnu-ubuntu-16.04/bin:$PATH git clone https://github.com/WebAssembly/wasi-libc cd wasi-libc -git reset --hard 215adc8ac9f91eb055311acc72683fd2eb1ae15a +git reset --hard 58795582905e08fa7748846c1971b4ab911d1e16 make -j$(nproc) INSTALL_DIR=/wasm32-wasi install cd ..