Skip to content

Commit

Permalink
Auto merge of #59619 - alexcrichton:wasi-fs, r=fitzgen
Browse files Browse the repository at this point in the history
wasi: Implement more of the standard library

This commit fills out more of the `wasm32-unknown-wasi` target's standard library, notably the `std::fs` module and all of its internals. A few tweaks were made along the way to non-`fs` modules, but the last commit contains the bulk of the work which is to wire up all APIs to their equivalent on WASI targets instead of unconditionally returning "unsupported". After this some basic filesystem operations and such should all be working in WASI!
  • Loading branch information
bors committed Apr 4, 2019
2 parents e43f99c + 61b487c commit 2d06571
Show file tree
Hide file tree
Showing 16 changed files with 1,189 additions and 304 deletions.
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(|_| {
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

0 comments on commit 2d06571

Please sign in to comment.