From 05659b7e5c2064a223680c536471efdeaf48634a Mon Sep 17 00:00:00 2001 From: newpavlov Date: Fri, 13 Sep 2019 19:05:07 +0300 Subject: [PATCH 1/5] pure-Rust implementation of WASI's open_parent --- src/libstd/sys/wasi/fs.rs | 77 +++++++++++++++++++++++++-------------- 1 file changed, 49 insertions(+), 28 deletions(-) diff --git a/src/libstd/sys/wasi/fs.rs b/src/libstd/sys/wasi/fs.rs index 4113f6a2e09c0..d2ade704e8e03 100644 --- a/src/libstd/sys/wasi/fs.rs +++ b/src/libstd/sys/wasi/fs.rs @@ -1,4 +1,4 @@ -use crate::ffi::{CStr, CString, OsStr, OsString}; +use crate::ffi::{OsStr, OsString}; use crate::fmt; use crate::io::{self, IoSlice, IoSliceMut, SeekFrom}; use crate::iter; @@ -616,14 +616,37 @@ fn open_at(fd: &WasiFd, path: &Path, opts: &OpenOptions) -> io::Result { Ok(File { fd }) } +/// Get pre-opened file descriptors and their paths. +fn get_paths() -> Result, wasi::Error> { + use crate::sys::os_str::Buf; + + let mut paths = Vec::new(); + for fd in 3.. { + match wasi::fd_prestat_get(fd) { + Ok(wasi::Prestat { pr_type: wasi::PREOPENTYPE_DIR, u }) => unsafe { + let name_len = u.dir.pr_name_len; + let mut buf = vec![0; name_len]; + wasi::fd_prestat_dir_name(fd, &mut buf)?; + let buf = Buf { inner: buf }; + let path = PathBuf::from(OsString { inner: buf ); + paths.push((path, WasiFd::from_raw(fd))); + }, + Ok(_) => (), + Err(wasi::EBADF) => break, + Err(err) => return Err(err), + } + } + paths.shrink_to_fit(); + Ok(paths) +} + /// Attempts to open a bare path `p`. /// /// WASI has no fundamental capability to do this. All syscalls and operations -/// are relative to already-open file descriptors. The C library, however, -/// manages a map of preopened file descriptors to their path, and then the C -/// library provides an API to look at this. In other words, when you want to -/// open a path `p`, you have to find a previously opened file descriptor in a -/// global table and then see if `p` is relative to that file descriptor. +/// are relative to already-open file descriptors. However, we manage a list +/// of preopened file descriptors and their path. In other words, when you want +/// to open a path `p`, you have to find a previously opened file descriptor in +/// this list and then see if `p` is relative to that file descriptor. /// /// This function, if successful, will return two items: /// @@ -642,32 +665,30 @@ fn open_at(fd: &WasiFd, path: &Path, opts: &OpenOptions) -> io::Result { /// appropriate rights for performing `rights` actions. /// /// Note that this can fail if `p` doesn't look like it can be opened relative -/// to any preopened file descriptor. +/// to any preopened file descriptor or we have failed to build the list of +/// pre-opened file descriptors. fn open_parent( p: &Path, rights: wasi::Rights, -) -> io::Result<(ManuallyDrop, PathBuf)> { - let p = CString::new(p.as_os_str().as_bytes())?; - unsafe { - let mut ret = ptr::null(); - let fd = libc::__wasilibc_find_relpath(p.as_ptr(), rights, 0, &mut ret); - if fd == -1 { - let msg = format!( - "failed to find a preopened file descriptor \ - through which {:?} could be opened", - p - ); - return Err(io::Error::new(io::ErrorKind::Other, msg)); - } - let path = Path::new(OsStr::from_bytes(CStr::from_ptr(ret).to_bytes())); +) -> io::Result<(ManuallyDrop, &Path)> { + use crate::sync::Once; - // 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(); + static mut PATHS: Result, wasi::Error> = unsafe { + Err(wasi::Error::new_unchecked(1)) + }; + static PATHS_INIT: Once = Once::new(); + PATHS_INIT.call_once(|| unsafe { PATHS = get_paths(); }); - return Ok((ManuallyDrop::new(WasiFd::from_raw(fd as u32)), path)); + for (path, fd) in PATHS.as_ref().map_err(|&e| super::err2io(e))?.iter() { + if let Ok(path) = p.strip_prefix(path) { + return Ok((ManuallyDrop::new(*fd), path)) + } } + + let msg = format!( + "failed to find a preopened file descriptor \ + through which {:?} could be opened", + p + ); + Err(io::Error::new(io::ErrorKind::Other, msg)) } From 804bbb2787f98fd264e82cf4868f82b6c244cc16 Mon Sep 17 00:00:00 2001 From: newpavlov Date: Fri, 13 Sep 2019 19:23:23 +0300 Subject: [PATCH 2/5] fix --- src/libstd/sys/wasi/fs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/sys/wasi/fs.rs b/src/libstd/sys/wasi/fs.rs index d2ade704e8e03..86f559bda9733 100644 --- a/src/libstd/sys/wasi/fs.rs +++ b/src/libstd/sys/wasi/fs.rs @@ -628,7 +628,7 @@ fn get_paths() -> Result, wasi::Error> { let mut buf = vec![0; name_len]; wasi::fd_prestat_dir_name(fd, &mut buf)?; let buf = Buf { inner: buf }; - let path = PathBuf::from(OsString { inner: buf ); + let path = PathBuf::from(OsString { inner: buf }); paths.push((path, WasiFd::from_raw(fd))); }, Ok(_) => (), From 4d7e887db96ae1dd15570b9163b4d20a44f27b9a Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Sun, 15 Sep 2019 00:09:57 +0000 Subject: [PATCH 3/5] use boxed slice --- src/libstd/sys/wasi/fs.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/libstd/sys/wasi/fs.rs b/src/libstd/sys/wasi/fs.rs index 86f559bda9733..fc7c4b15c6183 100644 --- a/src/libstd/sys/wasi/fs.rs +++ b/src/libstd/sys/wasi/fs.rs @@ -617,7 +617,7 @@ fn open_at(fd: &WasiFd, path: &Path, opts: &OpenOptions) -> io::Result { } /// Get pre-opened file descriptors and their paths. -fn get_paths() -> Result, wasi::Error> { +fn get_paths() -> Result, wasi::Error> { use crate::sys::os_str::Buf; let mut paths = Vec::new(); @@ -636,8 +636,7 @@ fn get_paths() -> Result, wasi::Error> { Err(err) => return Err(err), } } - paths.shrink_to_fit(); - Ok(paths) + Ok(paths.into_boxed_slice()) } /// Attempts to open a bare path `p`. @@ -673,7 +672,7 @@ fn open_parent( ) -> io::Result<(ManuallyDrop, &Path)> { use crate::sync::Once; - static mut PATHS: Result, wasi::Error> = unsafe { + static mut PATHS: Result, wasi::Error> = unsafe { Err(wasi::Error::new_unchecked(1)) }; static PATHS_INIT: Once = Once::new(); From c73d6ce348f0258feeb92758e8bf44d8a4e74850 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Sun, 15 Sep 2019 16:49:33 +0000 Subject: [PATCH 4/5] use OsString::from_vec --- src/libstd/sys/wasi/fs.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/libstd/sys/wasi/fs.rs b/src/libstd/sys/wasi/fs.rs index fc7c4b15c6183..a8a8f5bbadfd6 100644 --- a/src/libstd/sys/wasi/fs.rs +++ b/src/libstd/sys/wasi/fs.rs @@ -627,8 +627,7 @@ fn get_paths() -> Result, wasi::Error> { let name_len = u.dir.pr_name_len; let mut buf = vec![0; name_len]; wasi::fd_prestat_dir_name(fd, &mut buf)?; - let buf = Buf { inner: buf }; - let path = PathBuf::from(OsString { inner: buf }); + let path = PathBuf::from(OsString::from_vec(buf)); paths.push((path, WasiFd::from_raw(fd))); }, Ok(_) => (), From d47053cfe941f0711521ddfaf97ba0dd55d4f762 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Mon, 16 Sep 2019 12:32:46 +0000 Subject: [PATCH 5/5] remove unused import --- src/libstd/sys/wasi/fs.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/libstd/sys/wasi/fs.rs b/src/libstd/sys/wasi/fs.rs index a8a8f5bbadfd6..1936c64e0ff30 100644 --- a/src/libstd/sys/wasi/fs.rs +++ b/src/libstd/sys/wasi/fs.rs @@ -618,8 +618,6 @@ fn open_at(fd: &WasiFd, path: &Path, opts: &OpenOptions) -> io::Result { /// Get pre-opened file descriptors and their paths. fn get_paths() -> Result, wasi::Error> { - use crate::sys::os_str::Buf; - let mut paths = Vec::new(); for fd in 3.. { match wasi::fd_prestat_get(fd) {