This repository has been archived by the owner on Nov 9, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Begin sketching out a new high-level
fs
API.
This is a very preliminary sketch of #83. It doesn't even compile yet, but it shows a possible high-level structure of such an API.
- Loading branch information
1 parent
52b69c2
commit fc004bb
Showing
7 changed files
with
310 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
use crate::WasiCtx; | ||
|
||
lazy_static! { | ||
// TODO: Should we allow the context to be passed alternate arguments? | ||
pub(crate) static ref CONTEXT: WasiCtx = | ||
WasiCtx::new(std::env::args()).expect("initializing WASI state"); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
use crate::fs::{ctx, error::wasi_errno_to_io_error, File}; | ||
use crate::{host, hostcalls}; | ||
use std::os::unix::ffi::OsStrExt; | ||
use std::{io, path::Path}; | ||
|
||
/// A reference to an open directory on the filesystem. | ||
pub struct Dir { | ||
fd: host::__wasi_fd_t, | ||
} | ||
|
||
impl Dir { | ||
/// Constructs a new instance of Self from the given raw WASI file descriptor. | ||
pub unsafe fn from_raw_wasi_fd(fd: host::__wasi_fd_t) -> Self { | ||
Self { fd } | ||
} | ||
|
||
/// Attempts to open a file in read-only mode. | ||
fn open_file<P: AsRef<Path>>(&mut self, path: P) -> io::Result<File> { | ||
let path = path.as_ref(); | ||
let mut fd = 0; | ||
wasi_errno_to_io_error(hostcalls::path_open( | ||
&mut ctx::CONTEXT, | ||
self.fd, | ||
host::__WASI_LOOKUP_SYMLINK_FOLLOW, | ||
path.as_os_str().as_bytes(), | ||
path.as_os_str().len(), | ||
0, | ||
!0, | ||
!0, | ||
0, | ||
&mut fd, | ||
))?; | ||
|
||
Ok(File::from_raw_wasi_fd(fd)) | ||
} | ||
|
||
/// Attempts to open a directory. | ||
fn open_dir<P: AsRef<Path>>(&mut self, path: P) -> io::Result<Self> { | ||
let path = path.as_ref(); | ||
let mut fd = 0; | ||
wasi_errno_to_io_error(hostcalls::path_open( | ||
&mut ctx::CONTEXT, | ||
self.fd, | ||
host::__WASI_LOOKUP_SYMLINK_FOLLOW, | ||
path.as_os_str().as_bytes(), | ||
host::__WASI_O_DIRECTORY, | ||
!0, | ||
!0, | ||
0, | ||
&mut fd, | ||
))?; | ||
|
||
Ok(Self::from_raw_wasi_fd(fd)) | ||
} | ||
} | ||
|
||
impl Drop for Dir { | ||
fn drop(&mut self) { | ||
// Note that errors are ignored when closing a file descriptor. The | ||
// reason for this is that if an error occurs we don't actually know if | ||
// the file descriptor was closed or not, and if we retried (for | ||
// something like EINTR), we might close another valid file descriptor | ||
// opened after we closed ours. | ||
let _ = hostcalls::fd_close(&mut ctx::CONTEXT, self.fd); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
use crate::host; | ||
use std::io; | ||
|
||
pub(crate) fn wasi_errno_to_io_error(errno: host::__wasi_errno_t) -> io::Result<()> { | ||
#[cfg(unix)] | ||
let raw_os_error = match errno { | ||
host::__WASI_ESUCCESS => return Ok(()), | ||
host::__WASI_EINVAL => libc::EINVAL, | ||
host::__WASI_EPIPE => libc::EPIPE, | ||
host::__WASI_ENOTCONN => libc::ENOTCONN, | ||
host::__WASI_E2BIG => libc::E2BIG, | ||
host::__WASI_EACCES => libc::EACCES, | ||
host::__WASI_EADDRINUSE => libc::EADDRINUSE, | ||
host::__WASI_EADDRNOTAVAIL => libc::EADDRNOTAVAIL, | ||
host::__WASI_EAFNOSUPPORT => libc::EAFNOSUPPORT, | ||
host::__WASI_EAGAIN => libc::EAGAIN, | ||
host::__WASI_EALREADY => libc::EALREADY, | ||
host::__WASI_EBADF => libc::EBADF, | ||
host::__WASI_EBADMSG => libc::EBADMSG, | ||
host::__WASI_EBUSY => libc::EBUSY, | ||
host::__WASI_ECANCELED => libc::ECANCELED, | ||
host::__WASI_ECHILD => libc::ECHILD, | ||
host::__WASI_ECONNABORTED => libc::ECONNABORTED, | ||
host::__WASI_ECONNREFUSED => libc::ECONNREFUSED, | ||
host::__WASI_ECONNRESET => libc::ECONNRESET, | ||
host::__WASI_EDEADLK => libc::EDEADLK, | ||
host::__WASI_EDESTADDRREQ => libc::EDESTADDRREQ, | ||
host::__WASI_EDOM => libc::EDOM, | ||
host::__WASI_EDQUOT => libc::EDQUOT, | ||
host::__WASI_EEXIST => libc::EEXIST, | ||
host::__WASI_EFAULT => libc::EFAULT, | ||
host::__WASI_EFBIG => libc::EFBIG, | ||
host::__WASI_EHOSTUNREACH => libc::EHOSTUNREACH, | ||
host::__WASI_EIDRM => libc::EIDRM, | ||
host::__WASI_EILSEQ => libc::EILSEQ, | ||
host::__WASI_EINPROGRESS => libc::EINPROGRESS, | ||
host::__WASI_EINTR => libc::EINTR, | ||
host::__WASI_EISCONN => libc::EISCONN, | ||
host::__WASI_EISDIR => libc::EISDIR, | ||
host::__WASI_ELOOP => libc::ELOOP, | ||
host::__WASI_EMFILE => libc::EMFILE, | ||
host::__WASI_EMLINK => libc::EMLINK, | ||
host::__WASI_EMSGSIZE => libc::EMSGSIZE, | ||
host::__WASI_EMULTIHOP => libc::EMULTIHOP, | ||
host::__WASI_ENAMETOOLONG => libc::ENAMETOOLONG, | ||
host::__WASI_ENETDOWN => libc::ENETDOWN, | ||
host::__WASI_ENETRESET => libc::ENETRESET, | ||
host::__WASI_ENETUNREACH => libc::ENETUNREACH, | ||
host::__WASI_ENFILE => libc::ENFILE, | ||
host::__WASI_ENOBUFS => libc::ENOBUFS, | ||
host::__WASI_ENODEV => libc::ENODEV, | ||
host::__WASI_ENOENT => libc::ENOENT, | ||
host::__WASI_ENOEXEC => libc::ENOEXEC, | ||
host::__WASI_ENOLCK => libc::ENOLCK, | ||
host::__WASI_ENOLINK => libc::ENOLINK, | ||
host::__WASI_ENOMEM => libc::ENOMEM, | ||
host::__WASI_ENOMSG => libc::ENOMSG, | ||
host::__WASI_ENOPROTOOPT => libc::ENOPROTOOPT, | ||
host::__WASI_ENOSPC => libc::ENOSPC, | ||
host::__WASI_ENOSYS => libc::ENOSYS, | ||
host::__WASI_ENOTDIR => libc::ENOTDIR, | ||
host::__WASI_ENOTEMPTY => libc::ENOTEMPTY, | ||
host::__WASI_ENOTRECOVERABLE => libc::ENOTRECOVERABLE, | ||
host::__WASI_ENOTSOCK => libc::ENOTSOCK, | ||
host::__WASI_ENOTSUP => libc::ENOTSUP, | ||
host::__WASI_ENOTTY => libc::ENOTTY, | ||
host::__WASI_ENXIO => libc::ENXIO, | ||
host::__WASI_EOVERFLOW => libc::EOVERFLOW, | ||
host::__WASI_EOWNERDEAD => libc::EOWNERDEAD, | ||
host::__WASI_EPROTO => libc::EPROTO, | ||
host::__WASI_EPROTONOSUPPORT => libc::EPROTONOSUPPORT, | ||
host::__WASI_EPROTOTYPE => libc::EPROTOTYPE, | ||
host::__WASI_ERANGE => libc::ERANGE, | ||
host::__WASI_EROFS => libc::EROFS, | ||
host::__WASI_ESPIPE => libc::ESPIPE, | ||
host::__WASI_ESRCH => libc::ESRCH, | ||
host::__WASI_ESTALE => libc::ESTALE, | ||
host::__WASI_ETIMEDOUT => libc::ETIMEDOUT, | ||
host::__WASI_ETXTBSY => libc::ETXTBSY, | ||
host::__WASI_EXDEV => libc::EXDEV, | ||
#[cfg(target_os = "wasi")] | ||
host::__WASI_ENOTCAPABLE => libc::ENOTCAPABLE, | ||
#[cfg(not(target_os = "wasi"))] | ||
host::__WASI_ENOTCAPABLE => libc::EIO, | ||
}; | ||
|
||
#[cfg(windows)] | ||
use winapi::shared::winerror::*; | ||
|
||
#[cfg(windows)] | ||
let raw_os_error = match errno { | ||
host::__WASI_ESUCCESS => return Ok(()), | ||
host::__WASI_EINVAL => WSAEINVAL, | ||
host::__WASI_EPIPE => ERROR_BROKEN_PIPE, | ||
host::__WASI_ENOTCONN => WSAENOTCONN, | ||
host::__WASI_EACCES => ERROR_ACCESS_DENIED, | ||
host::__WASI_EADDRINUSE => WSAEADDRINUSE, | ||
host::__WASI_EADDRNOTAVAIL => WSAEADDRNOTAVAIL, | ||
host::__WASI_EAGAIN => WSAEWOULDBLOCK, | ||
host::__WASI_ECONNABORTED => WSAECONNABORTED, | ||
host::__WASI_ECONNREFUSED => WSAECONNREFUSED, | ||
host::__WASI_ECONNRESET => WSAECONNRESET, | ||
host::__WASI_EEXIST => ERROR_ALREADY_EXISTS, | ||
host::__WASI_ENOENT => ERROR_FILE_NOT_FOUND, | ||
host::__WASI_ETIMEDOUT => WSAETIMEDOUT, | ||
host::__WASI_E2BIG => WSAE2BIG, | ||
host::__WASI_EAFNOSUPPORT => WSAEAFNOSUPPORT, | ||
host::__WASI_EALREADY => WSAEALREADY, | ||
host::__WASI_EBADF => WSAEBADF, | ||
host::__WASI_EBADMSG => WSAEBADMSG, | ||
host::__WASI_EBUSY => WSAEBUSY, | ||
host::__WASI_ECANCELED => WSAECANCELED, | ||
host::__WASI_ECHILD => WSAECHILD, | ||
host::__WASI_EDEADLK => WSAEDEADLK, | ||
host::__WASI_EDESTADDRREQ => WSAEDESTADDRREQ, | ||
host::__WASI_EDOM => WSAEDOM, | ||
host::__WASI_EDQUOT => WSAEDQUOT, | ||
host::__WASI_EFAULT => WSAEFAULT, | ||
host::__WASI_EFBIG => WSAEFBIG, | ||
host::__WASI_EHOSTUNREACH => WSAEHOSTUNREACH, | ||
host::__WASI_EIDRM => WSAEIDRM, | ||
host::__WASI_EILSEQ => WSAEILSEQ, | ||
host::__WASI_EINPROGRESS => WSAEINPROGRESS, | ||
host::__WASI_EINTR => WSAEINTR, | ||
host::__WASI_EISCONN => WSAEISCONN, | ||
host::__WASI_EISDIR => WSAEISDIR, | ||
host::__WASI_ELOOP => WSAELOOP, | ||
host::__WASI_EMFILE => WSAEMFILE, | ||
host::__WASI_EMLINK => WSAEMLINK, | ||
host::__WASI_EMSGSIZE => WSAEMSGSIZE, | ||
host::__WASI_EMULTIHOP => WSAEMULTIHOP, | ||
host::__WASI_ENAMETOOLONG => WSAENAMETOOLONG, | ||
host::__WASI_ENETDOWN => WSAENETDOWN, | ||
host::__WASI_ENETRESET => WSAENETRESET, | ||
host::__WASI_ENETUNREACH => WSAENETUNREACH, | ||
host::__WASI_ENFILE => WSAENFILE, | ||
host::__WASI_ENOBUFS => WSAENOBUFS, | ||
host::__WASI_ENODEV => WSAENODEV, | ||
host::__WASI_ENOEXEC => WSAENOEXEC, | ||
host::__WASI_ENOLCK => WSAENOLCK, | ||
host::__WASI_ENOLINK => WSAENOLINK, | ||
host::__WASI_ENOMEM => WSAENOMEM, | ||
host::__WASI_ENOMSG => WSAENOMSG, | ||
host::__WASI_ENOPROTOOPT => WSAENOPROTOOPT, | ||
host::__WASI_ENOSPC => WSAENOSPC, | ||
host::__WASI_ENOSYS => WSAENOSYS, | ||
host::__WASI_ENOTDIR => WSAENOTDIR, | ||
host::__WASI_ENOTEMPTY => WSAENOTEMPTY, | ||
host::__WASI_ENOTRECOVERABLE => WSAENOTRECOVERABLE, | ||
host::__WASI_ENOTSOCK => WSAENOTSOCK, | ||
host::__WASI_ENOTSUP => WSAENOTSUP, | ||
host::__WASI_ENOTTY => WSAENOTTY, | ||
host::__WASI_ENXIO => WSAENXIO, | ||
host::__WASI_EOVERFLOW => WSAEOVERFLOW, | ||
host::__WASI_EOWNERDEAD => WSAEOWNERDEAD, | ||
host::__WASI_EPROTO => WSAEPROTO, | ||
host::__WASI_EPROTONOSUPPORT => WSAEPROTONOSUPPORT, | ||
host::__WASI_EPROTOTYPE => WSAEPROTOTYPE, | ||
host::__WASI_ERANGE => WSAERANGE, | ||
host::__WASI_EROFS => WSAEROFS, | ||
host::__WASI_ESPIPE => WSAESPIPE, | ||
host::__WASI_ESRCH => WSAESRCH, | ||
host::__WASI_ESTALE => WSAESTALE, | ||
host::__WASI_ETXTBSY => WSAETXTBSY, | ||
host::__WASI_EXDEV => WSAEXDEV, | ||
#[cfg(target_os = "wasi")] | ||
host::__WASI_ENOTCAPABLE => WSAENOTCAPABLE, | ||
#[cfg(not(target_os = "wasi"))] | ||
host::__WASI_ENOTCAPABLE => WSAEIO, | ||
}; | ||
|
||
Err(io::Error::from_raw_os_error(raw_os_error)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
use crate::fs::{ctx, error::wasi_errno_to_io_error}; | ||
use crate::{host, hostcalls}; | ||
use std::io; | ||
|
||
/// A reference to an open file on the filesystem. | ||
pub struct File { | ||
fd: host::__wasi_fd_t, | ||
} | ||
|
||
impl File { | ||
/// Constructs a new instance of Self from the given raw WASI file descriptor. | ||
pub unsafe fn from_raw_wasi_fd(fd: host::__wasi_fd_t) -> Self { | ||
Self { fd } | ||
} | ||
|
||
// TODO: functions to implement: sync_all, sync_data, set_len, metadata | ||
} | ||
|
||
impl Drop for File { | ||
fn drop(&mut self) { | ||
// Note that errors are ignored when closing a file descriptor. The | ||
// reason for this is that if an error occurs we don't actually know if | ||
// the file descriptor was closed or not, and if we retried (for | ||
// something like EINTR), we might close another valid file descriptor | ||
// opened after we closed ours. | ||
let _ = hostcalls::fd_close(&mut ctx::CONTEXT, self.fd); | ||
} | ||
} | ||
|
||
impl io::Read for File { | ||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { | ||
let iov = [host::__wasi_iovec_t { | ||
buf: buf.as_mut_ptr() as *mut core::ffi::c_void, | ||
buf_len: buf.len(), | ||
}]; | ||
let mut nread = 0; | ||
|
||
wasi_errno_to_io_error(hostcalls::fd_read( | ||
&mut ctx::CONTEXT, | ||
self.fd, | ||
&iov, | ||
1, | ||
&mut nread, | ||
))?; | ||
|
||
Ok(nread) | ||
} | ||
} | ||
|
||
// TODO: traits to implement: Write, Seek, FileExt |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
mod ctx; | ||
mod dir; | ||
mod error; | ||
mod file; | ||
|
||
pub use dir::*; | ||
pub use file::*; | ||
|
||
// TODO: Implement more things from std::fs. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters