Skip to content

Commit 61b487c

Browse files
committed
wasi: Fill out std::fs module for WASI
This commit fills out the `std::fs` module and implementation for WASI. Not all APIs are implemented, such as permissions-related ones and `canonicalize`, but all others APIs have been implemented and very lightly tested so far. We'll eventually want to run a more exhaustive test suite! For now the highlights of this commit are: * The `std::fs::File` type is now backed by `WasiFd`, a raw WASI file descriptor. * All APIs in `std::fs` (except permissions/canonicalize) have implementations for the WASI target. * A suite of unstable extension traits were added to `std::os::wasi::fs`. These traits expose the raw filesystem functionality of WASI, namely `*at` syscalls (opening a file relative to an already opened one, for example). Additionally metadata only available on wasi is exposed through these traits. Perhaps one of the most notable parts is the implementation of path-taking APIs. WASI actually has no fundamental API that just takes a path, but rather everything is relative to a previously opened file descriptor. To allow existing APIs to work (that only take a path) WASI has a few syscalls to learn about "pre opened" file descriptors by the runtime. We use these to build a map of existing directory names to file descriptors, and then when using a path we try to anchor it at an already-opened file. This support is very rudimentary though and is intended to be shared with C since it's likely to be so tricky. For now though the C library doesn't expose quite an API for us to use, so we implement it for now and will swap it out as soon as one is available.
1 parent 32a7684 commit 61b487c

File tree

13 files changed

+1141
-262
lines changed

13 files changed

+1141
-262
lines changed

src/libstd/fs.rs

+8
Original file line numberDiff line numberDiff line change
@@ -881,6 +881,10 @@ impl OpenOptions {
881881
}
882882
}
883883

884+
impl AsInner<fs_imp::OpenOptions> for OpenOptions {
885+
fn as_inner(&self) -> &fs_imp::OpenOptions { &self.0 }
886+
}
887+
884888
impl AsInnerMut<fs_imp::OpenOptions> for OpenOptions {
885889
fn as_inner_mut(&mut self) -> &mut fs_imp::OpenOptions { &mut self.0 }
886890
}
@@ -1104,6 +1108,10 @@ impl AsInner<fs_imp::FileAttr> for Metadata {
11041108
fn as_inner(&self) -> &fs_imp::FileAttr { &self.0 }
11051109
}
11061110

1111+
impl FromInner<fs_imp::FileAttr> for Metadata {
1112+
fn from_inner(attr: fs_imp::FileAttr) -> Metadata { Metadata(attr) }
1113+
}
1114+
11071115
impl Permissions {
11081116
/// Returns `true` if these permissions describe a readonly (unwritable) file.
11091117
///

src/libstd/sys/redox/fs.rs

+4-38
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,17 @@ use crate::os::unix::prelude::*;
22

33
use crate::ffi::{OsString, OsStr};
44
use crate::fmt;
5-
use crate::io::{self, Error, ErrorKind, SeekFrom};
5+
use crate::io::{self, Error, SeekFrom};
66
use crate::path::{Path, PathBuf};
77
use crate::sync::Arc;
88
use crate::sys::fd::FileDesc;
99
use crate::sys::time::SystemTime;
1010
use crate::sys::{cvt, syscall};
1111
use crate::sys_common::{AsInner, FromInner};
1212

13+
pub use crate::sys_common::fs::copy;
14+
pub use crate::sys_common::fs::remove_dir_all;
15+
1316
pub struct File(FileDesc);
1417

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

395-
pub fn remove_dir_all(path: &Path) -> io::Result<()> {
396-
let filetype = lstat(path)?.file_type();
397-
if filetype.is_symlink() {
398-
unlink(path)
399-
} else {
400-
remove_dir_all_recursive(path)
401-
}
402-
}
403-
404-
fn remove_dir_all_recursive(path: &Path) -> io::Result<()> {
405-
for child in readdir(path)? {
406-
let child = child?;
407-
if child.file_type()?.is_dir() {
408-
remove_dir_all_recursive(&child.path())?;
409-
} else {
410-
unlink(&child.path())?;
411-
}
412-
}
413-
rmdir(path)
414-
}
415-
416398
pub fn readlink(p: &Path) -> io::Result<PathBuf> {
417399
let fd = cvt(syscall::open(p.to_str().unwrap(),
418400
syscall::O_CLOEXEC | syscall::O_SYMLINK | syscall::O_RDONLY))?;
@@ -455,19 +437,3 @@ pub fn canonicalize(p: &Path) -> io::Result<PathBuf> {
455437
let file = File(FileDesc::new(fd));
456438
file.path()
457439
}
458-
459-
pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
460-
use crate::fs::{File, set_permissions};
461-
if !from.is_file() {
462-
return Err(Error::new(ErrorKind::InvalidInput,
463-
"the source path is not an existing regular file"))
464-
}
465-
466-
let mut reader = File::open(from)?;
467-
let mut writer = File::create(to)?;
468-
let perm = reader.metadata()?.permissions();
469-
470-
let ret = io::copy(&mut reader, &mut writer)?;
471-
set_permissions(to, perm)?;
472-
Ok(ret)
473-
}

src/libstd/sys/unix/fs.rs

+2-21
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ use libc::{stat as stat64, fstat as fstat64, lstat as lstat64, off_t as off64_t,
3636
target_os = "fuchsia")))]
3737
use libc::{readdir_r as readdir64_r};
3838

39+
pub use crate::sys_common::fs::remove_dir_all;
40+
3941
pub struct File(FileDesc);
4042

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

737-
pub fn remove_dir_all(path: &Path) -> io::Result<()> {
738-
let filetype = lstat(path)?.file_type();
739-
if filetype.is_symlink() {
740-
unlink(path)
741-
} else {
742-
remove_dir_all_recursive(path)
743-
}
744-
}
745-
746-
fn remove_dir_all_recursive(path: &Path) -> io::Result<()> {
747-
for child in readdir(path)? {
748-
let child = child?;
749-
if child.file_type()?.is_dir() {
750-
remove_dir_all_recursive(&child.path())?;
751-
} else {
752-
unlink(&child.path())?;
753-
}
754-
}
755-
rmdir(path)
756-
}
757-
758739
pub fn readlink(p: &Path) -> io::Result<PathBuf> {
759740
let c_path = cstr(p)?;
760741
let p = c_path.as_ptr();

src/libstd/sys/wasi/ext/ffi.rs

+1-56
Original file line numberDiff line numberDiff line change
@@ -2,60 +2,5 @@
22
33
#![stable(feature = "rust1", since = "1.0.0")]
44

5-
use crate::ffi::{OsStr, OsString};
6-
use crate::mem;
7-
use crate::sys::os_str::Buf;
8-
use crate::sys_common::{FromInner, IntoInner, AsInner};
9-
10-
/// WASI-specific extensions to [`OsString`].
11-
///
12-
/// [`OsString`]: ../../../../std/ffi/struct.OsString.html
13-
#[stable(feature = "rust1", since = "1.0.0")]
14-
pub trait OsStringExt {
15-
/// Creates an `OsString` from a byte vector.
16-
#[stable(feature = "rust1", since = "1.0.0")]
17-
fn from_vec(vec: Vec<u8>) -> Self;
18-
19-
/// Yields the underlying byte vector of this `OsString`.
20-
#[stable(feature = "rust1", since = "1.0.0")]
21-
fn into_vec(self) -> Vec<u8>;
22-
}
23-
24-
#[stable(feature = "rust1", since = "1.0.0")]
25-
impl OsStringExt for OsString {
26-
fn from_vec(vec: Vec<u8>) -> OsString {
27-
FromInner::from_inner(Buf { inner: vec })
28-
}
29-
fn into_vec(self) -> Vec<u8> {
30-
self.into_inner().inner
31-
}
32-
}
33-
34-
/// WASI-specific extensions to [`OsStr`].
35-
///
36-
/// [`OsStr`]: ../../../../std/ffi/struct.OsStr.html
375
#[stable(feature = "rust1", since = "1.0.0")]
38-
pub trait OsStrExt {
39-
#[stable(feature = "rust1", since = "1.0.0")]
40-
/// Creates an [`OsStr`] from a byte slice.
41-
///
42-
/// [`OsStr`]: ../../../ffi/struct.OsStr.html
43-
fn from_bytes(slice: &[u8]) -> &Self;
44-
45-
/// Gets the underlying byte view of the [`OsStr`] slice.
46-
///
47-
/// [`OsStr`]: ../../../ffi/struct.OsStr.html
48-
#[stable(feature = "rust1", since = "1.0.0")]
49-
fn as_bytes(&self) -> &[u8];
50-
}
51-
52-
#[stable(feature = "rust1", since = "1.0.0")]
53-
impl OsStrExt for OsStr {
54-
fn from_bytes(slice: &[u8]) -> &OsStr {
55-
unsafe { mem::transmute(slice) }
56-
}
57-
fn as_bytes(&self) -> &[u8] {
58-
&self.as_inner().inner
59-
}
60-
}
61-
6+
pub use crate::sys_common::os_str_bytes::*;

0 commit comments

Comments
 (0)