Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wasi: Implement more of the standard library #59619

Merged
merged 4 commits into from
Apr 4, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/libstd/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -881,6 +881,10 @@ impl OpenOptions {
}
}

impl AsInner<fs_imp::OpenOptions> for OpenOptions {
fn as_inner(&self) -> &fs_imp::OpenOptions { &self.0 }
}

impl AsInnerMut<fs_imp::OpenOptions> for OpenOptions {
fn as_inner_mut(&mut self) -> &mut fs_imp::OpenOptions { &mut self.0 }
}
Expand Down Expand Up @@ -1104,6 +1108,10 @@ impl AsInner<fs_imp::FileAttr> for Metadata {
fn as_inner(&self) -> &fs_imp::FileAttr { &self.0 }
}

impl FromInner<fs_imp::FileAttr> for Metadata {
fn from_inner(attr: fs_imp::FileAttr) -> Metadata { Metadata(attr) }
}

impl Permissions {
/// Returns `true` if these permissions describe a readonly (unwritable) file.
///
Expand Down
42 changes: 4 additions & 38 deletions src/libstd/sys/redox/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@ use crate::os::unix::prelude::*;

use crate::ffi::{OsString, OsStr};
use crate::fmt;
use crate::io::{self, Error, ErrorKind, SeekFrom};
use crate::io::{self, Error, SeekFrom};
use crate::path::{Path, PathBuf};
use crate::sync::Arc;
use crate::sys::fd::FileDesc;
use crate::sys::time::SystemTime;
use crate::sys::{cvt, syscall};
use crate::sys_common::{AsInner, FromInner};

pub use crate::sys_common::fs::copy;
pub use crate::sys_common::fs::remove_dir_all;

pub struct File(FileDesc);

#[derive(Clone)]
Expand Down Expand Up @@ -392,27 +395,6 @@ pub fn rmdir(p: &Path) -> io::Result<()> {
Ok(())
}

pub fn remove_dir_all(path: &Path) -> io::Result<()> {
let filetype = lstat(path)?.file_type();
if filetype.is_symlink() {
unlink(path)
} else {
remove_dir_all_recursive(path)
}
}

fn remove_dir_all_recursive(path: &Path) -> io::Result<()> {
for child in readdir(path)? {
let child = child?;
if child.file_type()?.is_dir() {
remove_dir_all_recursive(&child.path())?;
} else {
unlink(&child.path())?;
}
}
rmdir(path)
}

pub fn readlink(p: &Path) -> io::Result<PathBuf> {
let fd = cvt(syscall::open(p.to_str().unwrap(),
syscall::O_CLOEXEC | syscall::O_SYMLINK | syscall::O_RDONLY))?;
Expand Down Expand Up @@ -455,19 +437,3 @@ pub fn canonicalize(p: &Path) -> io::Result<PathBuf> {
let file = File(FileDesc::new(fd));
file.path()
}

pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
use crate::fs::{File, set_permissions};
if !from.is_file() {
return Err(Error::new(ErrorKind::InvalidInput,
"the source path is not an existing regular file"))
}

let mut reader = File::open(from)?;
let mut writer = File::create(to)?;
let perm = reader.metadata()?.permissions();

let ret = io::copy(&mut reader, &mut writer)?;
set_permissions(to, perm)?;
Ok(ret)
}
23 changes: 2 additions & 21 deletions src/libstd/sys/unix/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ use libc::{stat as stat64, fstat as fstat64, lstat as lstat64, off_t as off64_t,
target_os = "fuchsia")))]
use libc::{readdir_r as readdir64_r};

pub use crate::sys_common::fs::remove_dir_all;

pub struct File(FileDesc);

#[derive(Clone)]
Expand Down Expand Up @@ -734,27 +736,6 @@ pub fn rmdir(p: &Path) -> io::Result<()> {
Ok(())
}

pub fn remove_dir_all(path: &Path) -> io::Result<()> {
let filetype = lstat(path)?.file_type();
if filetype.is_symlink() {
unlink(path)
} else {
remove_dir_all_recursive(path)
}
}

fn remove_dir_all_recursive(path: &Path) -> io::Result<()> {
for child in readdir(path)? {
let child = child?;
if child.file_type()?.is_dir() {
remove_dir_all_recursive(&child.path())?;
} else {
unlink(&child.path())?;
}
}
rmdir(path)
}

pub fn readlink(p: &Path) -> io::Result<PathBuf> {
let c_path = cstr(p)?;
let p = c_path.as_ptr();
Expand Down
50 changes: 24 additions & 26 deletions src/libstd/sys/wasi/args.rs
Original file line number Diff line number Diff line change
@@ -1,30 +1,15 @@
use crate::any::Any;
use crate::ffi::CStr;
use crate::io;
use crate::sys::cvt_wasi;
use crate::ffi::OsString;
use crate::marker::PhantomData;
use crate::os::wasi::ffi::OsStringExt;
use crate::ptr;
use crate::vec;

static mut ARGC: isize = 0;
static mut ARGV: *const *const u8 = ptr::null();

#[cfg(not(target_feature = "atomics"))]
pub unsafe fn args_lock() -> impl Any {
// No need for a lock if we're single-threaded, but this function will need
// to get implemented for multi-threaded scenarios
}

pub unsafe fn init(argc: isize, argv: *const *const u8) {
let _guard = args_lock();
ARGC = argc;
ARGV = argv;
pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
}

pub unsafe fn cleanup() {
let _guard = args_lock();
ARGC = 0;
ARGV = ptr::null();
}

pub struct Args {
Expand All @@ -34,18 +19,31 @@ pub struct Args {

/// Returns the command line arguments
pub fn args() -> Args {
maybe_args().unwrap_or_else(|_| {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the reasoning behind getting the args from the host every time args() is called? Wouldn't it make sense to get it once at program startup and store it?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh sure yeah, the thinking is that this reduces our dependency on a C library somewhat, but it also removes the need for global state and locks. This way if you don't actually use the arguments we never reserve space or allocate memory for them.

In general I don't think acquiring the arguments isn't too performance critical, so I wanted to make sure that the binary and memory impact would be as small as possible. This also matches what we do on OSX I believe, for example.

Args {
iter: Vec::new().into_iter(),
_dont_send_or_sync_me: PhantomData
}
})
}

fn maybe_args() -> io::Result<Args> {
unsafe {
let _guard = args_lock();
let args = (0..ARGC)
.map(|i| {
let cstr = CStr::from_ptr(*ARGV.offset(i) as *const libc::c_char);
OsStringExt::from_vec(cstr.to_bytes().to_vec())
})
let (mut argc, mut argv_buf_size) = (0, 0);
cvt_wasi(libc::__wasi_args_sizes_get(&mut argc, &mut argv_buf_size))?;

let mut argc = vec![0 as *mut libc::c_char; argc];
let mut argv_buf = vec![0; argv_buf_size];
cvt_wasi(libc::__wasi_args_get(argc.as_mut_ptr(), argv_buf.as_mut_ptr()))?;

let args = argc.into_iter()
.map(|ptr| CStr::from_ptr(ptr).to_bytes().to_vec())
.map(|bytes| OsString::from_vec(bytes))
.collect::<Vec<_>>();
Args {
Ok(Args {
iter: args.into_iter(),
_dont_send_or_sync_me: PhantomData,
}
})
}
}

Expand Down
57 changes: 1 addition & 56 deletions src/libstd/sys/wasi/ext/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,60 +2,5 @@
#![stable(feature = "rust1", since = "1.0.0")]

use crate::ffi::{OsStr, OsString};
use crate::mem;
use crate::sys::os_str::Buf;
use crate::sys_common::{FromInner, IntoInner, AsInner};

/// WASI-specific extensions to [`OsString`].
///
/// [`OsString`]: ../../../../std/ffi/struct.OsString.html
#[stable(feature = "rust1", since = "1.0.0")]
pub trait OsStringExt {
/// Creates an `OsString` from a byte vector.
#[stable(feature = "rust1", since = "1.0.0")]
fn from_vec(vec: Vec<u8>) -> Self;

/// Yields the underlying byte vector of this `OsString`.
#[stable(feature = "rust1", since = "1.0.0")]
fn into_vec(self) -> Vec<u8>;
}

#[stable(feature = "rust1", since = "1.0.0")]
impl OsStringExt for OsString {
fn from_vec(vec: Vec<u8>) -> OsString {
FromInner::from_inner(Buf { inner: vec })
}
fn into_vec(self) -> Vec<u8> {
self.into_inner().inner
}
}

/// WASI-specific extensions to [`OsStr`].
///
/// [`OsStr`]: ../../../../std/ffi/struct.OsStr.html
#[stable(feature = "rust1", since = "1.0.0")]
pub trait OsStrExt {
#[stable(feature = "rust1", since = "1.0.0")]
/// Creates an [`OsStr`] from a byte slice.
///
/// [`OsStr`]: ../../../ffi/struct.OsStr.html
fn from_bytes(slice: &[u8]) -> &Self;

/// Gets the underlying byte view of the [`OsStr`] slice.
///
/// [`OsStr`]: ../../../ffi/struct.OsStr.html
#[stable(feature = "rust1", since = "1.0.0")]
fn as_bytes(&self) -> &[u8];
}

#[stable(feature = "rust1", since = "1.0.0")]
impl OsStrExt for OsStr {
fn from_bytes(slice: &[u8]) -> &OsStr {
unsafe { mem::transmute(slice) }
}
fn as_bytes(&self) -> &[u8] {
&self.as_inner().inner
}
}

pub use crate::sys_common::os_str_bytes::*;
Loading