Initial reorg.
This is largely the same as #305, but updated for the current tree.
This commit is contained in:
216
crates/wasi-common/src/fs/dir.rs
Normal file
216
crates/wasi-common/src/fs/dir.rs
Normal file
@@ -0,0 +1,216 @@
|
||||
use crate::fs::{error::wasi_errno_to_io_error, File, OpenOptions, ReadDir};
|
||||
use crate::{host, hostcalls, wasi, WasiCtx};
|
||||
#[cfg(unix)]
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
use std::{io, path::Path};
|
||||
|
||||
/// A reference to an open directory on the filesystem.
|
||||
///
|
||||
/// TODO: Implement `Dir`-using versions of `std::fs`'s free functions:
|
||||
/// `copy`, `create_dir`, `create_dir_all`, `hard_link`, `metadata`,
|
||||
/// `read_link`, `read_to_string`, `remove_dir`, `remove_dir_all`,
|
||||
/// `remove_file`, `rename`, `set_permissions`, `symlink_metadata`, and
|
||||
/// `write`.
|
||||
///
|
||||
/// Unlike `std::fs`, this API has no `canonicalize`, because absolute paths
|
||||
/// don't interoperate well with the capability-oriented security model.
|
||||
pub struct Dir<'ctx> {
|
||||
ctx: &'ctx mut WasiCtx,
|
||||
fd: wasi::__wasi_fd_t,
|
||||
}
|
||||
|
||||
impl<'ctx> Dir<'ctx> {
|
||||
/// Constructs a new instance of `Self` from the given raw WASI file descriptor.
|
||||
pub unsafe fn from_raw_wasi_fd(ctx: &'ctx mut WasiCtx, fd: wasi::__wasi_fd_t) -> Self {
|
||||
Self { ctx, fd }
|
||||
}
|
||||
|
||||
/// Attempts to open a file in read-only mode.
|
||||
///
|
||||
/// This corresponds to [`std::fs::File::open`], but only accesses paths
|
||||
/// relative to and within `self`.
|
||||
///
|
||||
/// TODO: Not yet implemented. Refactor the hostcalls functions to split out the
|
||||
/// encoding/decoding parts from the underlying functionality, so that we can call
|
||||
/// into the underlying functionality directly.
|
||||
///
|
||||
/// [`std::fs::File::open`]: https://doc.rust-lang.org/std/fs/struct.File.html#method.open
|
||||
pub fn open_file<P: AsRef<Path>>(&mut self, path: P) -> io::Result<File> {
|
||||
let path = path.as_ref();
|
||||
let mut fd = 0;
|
||||
|
||||
// TODO: Refactor the hostcalls functions to split out the encoding/decoding
|
||||
// parts from the underlying functionality, so that we can call into the
|
||||
// underlying functionality directly.
|
||||
//
|
||||
// TODO: Set the requested rights to be readonly.
|
||||
//
|
||||
// TODO: Handle paths for non-Unix platforms which don't have `as_bytes()`
|
||||
// on `OsStrExt`.
|
||||
unimplemented!("Dir::open_file");
|
||||
/*
|
||||
wasi_errno_to_io_error(hostcalls::path_open(
|
||||
self.ctx,
|
||||
self.fd,
|
||||
wasi::__WASI_LOOKUP_SYMLINK_FOLLOW,
|
||||
path.as_os_str().as_bytes(),
|
||||
path.as_os_str().len(),
|
||||
0,
|
||||
!0,
|
||||
!0,
|
||||
0,
|
||||
&mut fd,
|
||||
))?;
|
||||
*/
|
||||
|
||||
let ctx = self.ctx;
|
||||
Ok(unsafe { File::from_raw_wasi_fd(ctx, fd) })
|
||||
}
|
||||
|
||||
/// Opens a file at `path` with the options specified by `self`.
|
||||
///
|
||||
/// This corresponds to [`std::fs::OpenOptions::open`].
|
||||
///
|
||||
/// Instead of being a method on `OpenOptions`, this is a method on `Dir`,
|
||||
/// and it only accesses functions relative to and within `self`.
|
||||
///
|
||||
/// TODO: Not yet implemented.
|
||||
///
|
||||
/// [`std::fs::OpenOptions::open`]: https://doc.rust-lang.org/std/fs/struct.OpenOptions.html#method.open
|
||||
pub fn open_file_with<P: AsRef<Path>>(
|
||||
&mut self,
|
||||
path: P,
|
||||
options: &OpenOptions,
|
||||
) -> io::Result<File> {
|
||||
unimplemented!("Dir::open_file_with");
|
||||
}
|
||||
|
||||
/// Attempts to open a directory.
|
||||
///
|
||||
/// TODO: Not yet implemented. See the comment in `open_file`.
|
||||
pub fn open_dir<P: AsRef<Path>>(&mut self, path: P) -> io::Result<Self> {
|
||||
let path = path.as_ref();
|
||||
let mut fd = 0;
|
||||
|
||||
// TODO: See the comment in `open_file`.
|
||||
unimplemented!("Dir::open_dir");
|
||||
/*
|
||||
wasi_errno_to_io_error(hostcalls::path_open(
|
||||
self.ctx,
|
||||
self.fd,
|
||||
wasi::__WASI_LOOKUP_SYMLINK_FOLLOW,
|
||||
path.as_os_str().as_bytes(),
|
||||
wasi::__WASI_O_DIRECTORY,
|
||||
!0,
|
||||
!0,
|
||||
0,
|
||||
&mut fd,
|
||||
))?;
|
||||
*/
|
||||
|
||||
let ctx = self.ctx;
|
||||
Ok(unsafe { Dir::from_raw_wasi_fd(ctx, fd) })
|
||||
}
|
||||
|
||||
/// Opens a file in write-only mode.
|
||||
///
|
||||
/// This corresponds to [`std::fs::File::create`], but only accesses paths
|
||||
/// relative to and within `self`.
|
||||
///
|
||||
/// TODO: Not yet implemented. See the comment in `open_file`.
|
||||
///
|
||||
/// [`std::fs::File::create`]: https://doc.rust-lang.org/std/fs/struct.File.html#method.create
|
||||
pub fn create_file<P: AsRef<Path>>(&mut self, path: P) -> io::Result<File> {
|
||||
let path = path.as_ref();
|
||||
let mut fd = 0;
|
||||
|
||||
// TODO: See the comments in `open_file`.
|
||||
//
|
||||
// TODO: Set the requested rights to be read+write.
|
||||
unimplemented!("Dir::create_file");
|
||||
/*
|
||||
wasi_errno_to_io_error(hostcalls::path_open(
|
||||
self.ctx,
|
||||
self.fd,
|
||||
wasi::__WASI_LOOKUP_SYMLINK_FOLLOW,
|
||||
path.as_os_str().as_bytes(),
|
||||
path.as_os_str().len(),
|
||||
wasi::__WASI_O_CREAT | wasi::__WASI_O_TRUNC,
|
||||
!0,
|
||||
!0,
|
||||
0,
|
||||
&mut fd,
|
||||
))?;
|
||||
*/
|
||||
|
||||
let ctx = self.ctx;
|
||||
Ok(unsafe { File::from_raw_wasi_fd(ctx, fd) })
|
||||
}
|
||||
|
||||
/// Returns an iterator over the entries within a directory.
|
||||
///
|
||||
/// This corresponds to [`std::fs::read_dir`], but reads the directory
|
||||
/// represented by `self`.
|
||||
///
|
||||
/// TODO: Not yet implemented. We may need to wait until we have the ability
|
||||
/// to duplicate file descriptors before we can implement read safely. For
|
||||
/// now, use `into_read` instead.
|
||||
///
|
||||
/// [`std::fs::read_dir`]: https://doc.rust-lang.org/std/fs/fn.read_dir.html
|
||||
pub fn read(&mut self) -> io::Result<ReadDir> {
|
||||
unimplemented!("Dir::read")
|
||||
}
|
||||
|
||||
/// Consumes self and returns an iterator over the entries within a directory
|
||||
/// in the manner of `read`.
|
||||
pub fn into_read(self) -> ReadDir {
|
||||
unsafe { ReadDir::from_raw_wasi_fd(self.fd) }
|
||||
}
|
||||
|
||||
/// Read the entire contents of a file into a bytes vector.
|
||||
///
|
||||
/// This corresponds to [`std::fs::read`], but only accesses paths
|
||||
/// relative to and within `self`.
|
||||
///
|
||||
/// [`std::fs::read`]: https://doc.rust-lang.org/std/fs/fn.read.html
|
||||
pub fn read_file<P: AsRef<Path>>(&mut self, path: P) -> io::Result<Vec<u8>> {
|
||||
use io::Read;
|
||||
let mut file = self.open_file(path)?;
|
||||
let mut bytes = Vec::with_capacity(initial_buffer_size(&file));
|
||||
file.read_to_end(&mut bytes)?;
|
||||
Ok(bytes)
|
||||
}
|
||||
|
||||
/// Returns an iterator over the entries within a directory.
|
||||
///
|
||||
/// This corresponds to [`std::fs::read_dir`], but only accesses paths
|
||||
/// relative to and within `self`.
|
||||
///
|
||||
/// [`std::fs::read_dir`]: https://doc.rust-lang.org/std/fs/fn.read_dir.html
|
||||
pub fn read_dir<P: AsRef<Path>>(&mut self, path: P) -> io::Result<ReadDir> {
|
||||
self.open_dir(path)?.read()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ctx> Drop for Dir<'ctx> {
|
||||
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 _ = unsafe { hostcalls::fd_close(self.ctx, self.fd) };
|
||||
}
|
||||
}
|
||||
|
||||
/// Indicates how large a buffer to pre-allocate before reading the entire file.
|
||||
///
|
||||
/// Derived from the function of the same name in libstd.
|
||||
fn initial_buffer_size(file: &File) -> usize {
|
||||
// Allocate one extra byte so the buffer doesn't need to grow before the
|
||||
// final `read` call at the end of the file. Don't worry about `usize`
|
||||
// overflow because reading will fail regardless in that case.
|
||||
file.metadata().map(|m| m.len() as usize + 1).unwrap_or(0)
|
||||
}
|
||||
|
||||
// TODO: impl Debug for Dir
|
||||
49
crates/wasi-common/src/fs/dir_builder.rs
Normal file
49
crates/wasi-common/src/fs/dir_builder.rs
Normal file
@@ -0,0 +1,49 @@
|
||||
use std::{io, path::Path};
|
||||
|
||||
/// A builder used to create directories in various manners.
|
||||
///
|
||||
/// This corresponds to [`std::fs::DirBuilder`].
|
||||
///
|
||||
/// TODO: Not yet implemented.
|
||||
///
|
||||
/// [`std::fs::DirBuilder`]: https://doc.rust-lang.org/std/fs/struct.DirBuilder.html
|
||||
pub struct DirBuilder {}
|
||||
|
||||
impl DirBuilder {
|
||||
/// Creates a new set of options with default mode/security settings for all platforms and also non-recursive.
|
||||
///
|
||||
/// This corresponds to [`std::fs::DirBuilder::new`].
|
||||
///
|
||||
/// TODO: Not yet implemented.
|
||||
///
|
||||
/// [`std::fs::DirBuilder::new`]: https://doc.rust-lang.org/std/fs/struct.DirBuilder.html#method.new
|
||||
pub fn new() -> Self {
|
||||
unimplemented!("DirBuilder::new");
|
||||
}
|
||||
|
||||
/// Indicates that directories should be created recursively, creating all parent directories.
|
||||
///
|
||||
/// This corresponds to [`std::fs::DirBuilder::recursive`].
|
||||
///
|
||||
/// TODO: Not yet implemented.
|
||||
///
|
||||
/// [`std::fs::DirBuilder::recursive`]: https://doc.rust-lang.org/std/fs/struct.DirBuilder.html#method.recursive
|
||||
pub fn recursive(&mut self, recursive: bool) -> &mut Self {
|
||||
unimplemented!("DirBuilder::recursive");
|
||||
}
|
||||
|
||||
/// Creates the specified directory with the options configured in this builder.
|
||||
///
|
||||
/// This corresponds to [`std::fs::DirBuilder::create`].
|
||||
///
|
||||
/// TODO: Not yet implemented.
|
||||
///
|
||||
/// [`std::fs::DirBuilder::create`]: https://doc.rust-lang.org/std/fs/struct.DirBuilder.html#method.create
|
||||
pub fn create<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
|
||||
unimplemented!("DirBuilder::create");
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: functions from DirBuilderExt?
|
||||
|
||||
// TODO: impl Debug for DirBuilder
|
||||
53
crates/wasi-common/src/fs/dir_entry.rs
Normal file
53
crates/wasi-common/src/fs/dir_entry.rs
Normal file
@@ -0,0 +1,53 @@
|
||||
use crate::fs::{FileType, Metadata};
|
||||
use std::{ffi, io};
|
||||
|
||||
/// Entries returned by the ReadDir iterator.
|
||||
///
|
||||
/// This corresponds to [`std::fs::DirEntry`].
|
||||
///
|
||||
/// Unlike `std::fs::DirEntry`, this API has no `DirEntry::path`, because
|
||||
/// absolute paths don't interoperate well with the capability-oriented
|
||||
/// security model.
|
||||
///
|
||||
/// TODO: Not yet implemented.
|
||||
///
|
||||
/// [`std::fs::DirEntry`]: https://doc.rust-lang.org/std/fs/struct.DirEntry.html
|
||||
pub struct DirEntry {}
|
||||
|
||||
impl DirEntry {
|
||||
/// Returns the metadata for the file that this entry points at.
|
||||
///
|
||||
/// This corresponds to [`std::fs::DirEntry::metadata`].
|
||||
///
|
||||
/// TODO: Not yet implemented.
|
||||
///
|
||||
/// [`std::fs::DirEntry::metadata`]: https://doc.rust-lang.org/std/fs/struct.DirEntry.html#method.metadata
|
||||
pub fn metadata(&self) -> io::Result<Metadata> {
|
||||
unimplemented!("DirEntry::metadata");
|
||||
}
|
||||
|
||||
/// Returns the file type for the file that this entry points at.
|
||||
///
|
||||
/// This to [`std::fs::DirEntry::file_type`].
|
||||
///
|
||||
/// TODO: Not yet implemented.
|
||||
///
|
||||
/// [`std::fs::DirEntry::file_type`]: https://doc.rust-lang.org/std/fs/struct.DirEntry.html#method.file_type
|
||||
pub fn file_type(&self) -> io::Result<FileType> {
|
||||
unimplemented!("DirEntry::file_type");
|
||||
}
|
||||
|
||||
/// Returns the bare file name of this directory entry without any other leading path component.
|
||||
///
|
||||
/// This corresponds to [`std::fs::DirEntry::file_name`], though it returns
|
||||
/// `String` rather than `OsString`.
|
||||
///
|
||||
/// TODO: Not yet implemented.
|
||||
///
|
||||
/// [`std::fs::DirEntry::file_name`]: https://doc.rust-lang.org/std/fs/struct.DirEntry.html#method.file_name
|
||||
pub fn file_name(&self) -> String {
|
||||
unimplemented!("DirEntry::file_name");
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: impl Debug for DirEntry
|
||||
265
crates/wasi-common/src/fs/error.rs
Normal file
265
crates/wasi-common/src/fs/error.rs
Normal file
@@ -0,0 +1,265 @@
|
||||
use crate::wasi;
|
||||
use std::io;
|
||||
|
||||
/// Translate a WASI errno code into an `io::Result<()>`.
|
||||
///
|
||||
/// TODO: Would it be better to have our own version of `io::Error` (and
|
||||
/// `io::Result`), rather than trying to shoehorn WASI errors into the
|
||||
/// libstd version?
|
||||
pub(crate) fn wasi_errno_to_io_error(errno: wasi::__wasi_errno_t) -> io::Result<()> {
|
||||
#[cfg(unix)]
|
||||
let raw_os_error = match errno {
|
||||
wasi::__WASI_ESUCCESS => return Ok(()),
|
||||
wasi::__WASI_EIO => libc::EIO,
|
||||
wasi::__WASI_EPERM => libc::EPERM,
|
||||
wasi::__WASI_EINVAL => libc::EINVAL,
|
||||
wasi::__WASI_EPIPE => libc::EPIPE,
|
||||
wasi::__WASI_ENOTCONN => libc::ENOTCONN,
|
||||
wasi::__WASI_E2BIG => libc::E2BIG,
|
||||
wasi::__WASI_EACCES => libc::EACCES,
|
||||
wasi::__WASI_EADDRINUSE => libc::EADDRINUSE,
|
||||
wasi::__WASI_EADDRNOTAVAIL => libc::EADDRNOTAVAIL,
|
||||
wasi::__WASI_EAFNOSUPPORT => libc::EAFNOSUPPORT,
|
||||
wasi::__WASI_EAGAIN => libc::EAGAIN,
|
||||
wasi::__WASI_EALREADY => libc::EALREADY,
|
||||
wasi::__WASI_EBADF => libc::EBADF,
|
||||
wasi::__WASI_EBADMSG => libc::EBADMSG,
|
||||
wasi::__WASI_EBUSY => libc::EBUSY,
|
||||
wasi::__WASI_ECANCELED => libc::ECANCELED,
|
||||
wasi::__WASI_ECHILD => libc::ECHILD,
|
||||
wasi::__WASI_ECONNABORTED => libc::ECONNABORTED,
|
||||
wasi::__WASI_ECONNREFUSED => libc::ECONNREFUSED,
|
||||
wasi::__WASI_ECONNRESET => libc::ECONNRESET,
|
||||
wasi::__WASI_EDEADLK => libc::EDEADLK,
|
||||
wasi::__WASI_EDESTADDRREQ => libc::EDESTADDRREQ,
|
||||
wasi::__WASI_EDOM => libc::EDOM,
|
||||
wasi::__WASI_EDQUOT => libc::EDQUOT,
|
||||
wasi::__WASI_EEXIST => libc::EEXIST,
|
||||
wasi::__WASI_EFAULT => libc::EFAULT,
|
||||
wasi::__WASI_EFBIG => libc::EFBIG,
|
||||
wasi::__WASI_EHOSTUNREACH => libc::EHOSTUNREACH,
|
||||
wasi::__WASI_EIDRM => libc::EIDRM,
|
||||
wasi::__WASI_EILSEQ => libc::EILSEQ,
|
||||
wasi::__WASI_EINPROGRESS => libc::EINPROGRESS,
|
||||
wasi::__WASI_EINTR => libc::EINTR,
|
||||
wasi::__WASI_EISCONN => libc::EISCONN,
|
||||
wasi::__WASI_EISDIR => libc::EISDIR,
|
||||
wasi::__WASI_ELOOP => libc::ELOOP,
|
||||
wasi::__WASI_EMFILE => libc::EMFILE,
|
||||
wasi::__WASI_EMLINK => libc::EMLINK,
|
||||
wasi::__WASI_EMSGSIZE => libc::EMSGSIZE,
|
||||
wasi::__WASI_EMULTIHOP => libc::EMULTIHOP,
|
||||
wasi::__WASI_ENAMETOOLONG => libc::ENAMETOOLONG,
|
||||
wasi::__WASI_ENETDOWN => libc::ENETDOWN,
|
||||
wasi::__WASI_ENETRESET => libc::ENETRESET,
|
||||
wasi::__WASI_ENETUNREACH => libc::ENETUNREACH,
|
||||
wasi::__WASI_ENFILE => libc::ENFILE,
|
||||
wasi::__WASI_ENOBUFS => libc::ENOBUFS,
|
||||
wasi::__WASI_ENODEV => libc::ENODEV,
|
||||
wasi::__WASI_ENOENT => libc::ENOENT,
|
||||
wasi::__WASI_ENOEXEC => libc::ENOEXEC,
|
||||
wasi::__WASI_ENOLCK => libc::ENOLCK,
|
||||
wasi::__WASI_ENOLINK => libc::ENOLINK,
|
||||
wasi::__WASI_ENOMEM => libc::ENOMEM,
|
||||
wasi::__WASI_ENOMSG => libc::ENOMSG,
|
||||
wasi::__WASI_ENOPROTOOPT => libc::ENOPROTOOPT,
|
||||
wasi::__WASI_ENOSPC => libc::ENOSPC,
|
||||
wasi::__WASI_ENOSYS => libc::ENOSYS,
|
||||
wasi::__WASI_ENOTDIR => libc::ENOTDIR,
|
||||
wasi::__WASI_ENOTEMPTY => libc::ENOTEMPTY,
|
||||
wasi::__WASI_ENOTRECOVERABLE => libc::ENOTRECOVERABLE,
|
||||
wasi::__WASI_ENOTSOCK => libc::ENOTSOCK,
|
||||
wasi::__WASI_ENOTSUP => libc::ENOTSUP,
|
||||
wasi::__WASI_ENOTTY => libc::ENOTTY,
|
||||
wasi::__WASI_ENXIO => libc::ENXIO,
|
||||
wasi::__WASI_EOVERFLOW => libc::EOVERFLOW,
|
||||
wasi::__WASI_EOWNERDEAD => libc::EOWNERDEAD,
|
||||
wasi::__WASI_EPROTO => libc::EPROTO,
|
||||
wasi::__WASI_EPROTONOSUPPORT => libc::EPROTONOSUPPORT,
|
||||
wasi::__WASI_EPROTOTYPE => libc::EPROTOTYPE,
|
||||
wasi::__WASI_ERANGE => libc::ERANGE,
|
||||
wasi::__WASI_EROFS => libc::EROFS,
|
||||
wasi::__WASI_ESPIPE => libc::ESPIPE,
|
||||
wasi::__WASI_ESRCH => libc::ESRCH,
|
||||
wasi::__WASI_ESTALE => libc::ESTALE,
|
||||
wasi::__WASI_ETIMEDOUT => libc::ETIMEDOUT,
|
||||
wasi::__WASI_ETXTBSY => libc::ETXTBSY,
|
||||
wasi::__WASI_EXDEV => libc::EXDEV,
|
||||
#[cfg(target_os = "wasi")]
|
||||
wasi::__WASI_ENOTCAPABLE => libc::ENOTCAPABLE,
|
||||
#[cfg(not(target_os = "wasi"))]
|
||||
wasi::__WASI_ENOTCAPABLE => libc::EIO,
|
||||
_ => panic!("unexpected wasi errno value"),
|
||||
};
|
||||
|
||||
#[cfg(windows)]
|
||||
use winapi::shared::winerror::*;
|
||||
|
||||
#[cfg(windows)]
|
||||
let raw_os_error = match errno {
|
||||
wasi::__WASI_ESUCCESS => return Ok(()),
|
||||
wasi::__WASI_EINVAL => WSAEINVAL,
|
||||
wasi::__WASI_EPIPE => ERROR_BROKEN_PIPE,
|
||||
wasi::__WASI_ENOTCONN => WSAENOTCONN,
|
||||
wasi::__WASI_EPERM | wasi::__WASI_EACCES => ERROR_ACCESS_DENIED,
|
||||
wasi::__WASI_EADDRINUSE => WSAEADDRINUSE,
|
||||
wasi::__WASI_EADDRNOTAVAIL => WSAEADDRNOTAVAIL,
|
||||
wasi::__WASI_EAGAIN => WSAEWOULDBLOCK,
|
||||
wasi::__WASI_ECONNABORTED => WSAECONNABORTED,
|
||||
wasi::__WASI_ECONNREFUSED => WSAECONNREFUSED,
|
||||
wasi::__WASI_ECONNRESET => WSAECONNRESET,
|
||||
wasi::__WASI_EEXIST => ERROR_ALREADY_EXISTS,
|
||||
wasi::__WASI_ENOENT => ERROR_FILE_NOT_FOUND,
|
||||
wasi::__WASI_ETIMEDOUT => WSAETIMEDOUT,
|
||||
wasi::__WASI_EAFNOSUPPORT => WSAEAFNOSUPPORT,
|
||||
wasi::__WASI_EALREADY => WSAEALREADY,
|
||||
wasi::__WASI_EBADF => WSAEBADF,
|
||||
wasi::__WASI_EDESTADDRREQ => WSAEDESTADDRREQ,
|
||||
wasi::__WASI_EDQUOT => WSAEDQUOT,
|
||||
wasi::__WASI_EFAULT => WSAEFAULT,
|
||||
wasi::__WASI_EHOSTUNREACH => WSAEHOSTUNREACH,
|
||||
wasi::__WASI_EINPROGRESS => WSAEINPROGRESS,
|
||||
wasi::__WASI_EINTR => WSAEINTR,
|
||||
wasi::__WASI_EISCONN => WSAEISCONN,
|
||||
wasi::__WASI_ELOOP => WSAELOOP,
|
||||
wasi::__WASI_EMFILE => WSAEMFILE,
|
||||
wasi::__WASI_EMSGSIZE => WSAEMSGSIZE,
|
||||
wasi::__WASI_ENAMETOOLONG => WSAENAMETOOLONG,
|
||||
wasi::__WASI_ENETDOWN => WSAENETDOWN,
|
||||
wasi::__WASI_ENETRESET => WSAENETRESET,
|
||||
wasi::__WASI_ENETUNREACH => WSAENETUNREACH,
|
||||
wasi::__WASI_ENOBUFS => WSAENOBUFS,
|
||||
wasi::__WASI_ENOPROTOOPT => WSAENOPROTOOPT,
|
||||
wasi::__WASI_ENOTEMPTY => WSAENOTEMPTY,
|
||||
wasi::__WASI_ENOTSOCK => WSAENOTSOCK,
|
||||
wasi::__WASI_EPROTONOSUPPORT => WSAEPROTONOSUPPORT,
|
||||
wasi::__WASI_EPROTOTYPE => WSAEPROTOTYPE,
|
||||
wasi::__WASI_ESTALE => WSAESTALE,
|
||||
wasi::__WASI_EIO
|
||||
| wasi::__WASI_EISDIR
|
||||
| wasi::__WASI_E2BIG
|
||||
| wasi::__WASI_EBADMSG
|
||||
| wasi::__WASI_EBUSY
|
||||
| wasi::__WASI_ECANCELED
|
||||
| wasi::__WASI_ECHILD
|
||||
| wasi::__WASI_EDEADLK
|
||||
| wasi::__WASI_EDOM
|
||||
| wasi::__WASI_EFBIG
|
||||
| wasi::__WASI_EIDRM
|
||||
| wasi::__WASI_EILSEQ
|
||||
| wasi::__WASI_EMLINK
|
||||
| wasi::__WASI_EMULTIHOP
|
||||
| wasi::__WASI_ENFILE
|
||||
| wasi::__WASI_ENODEV
|
||||
| wasi::__WASI_ENOEXEC
|
||||
| wasi::__WASI_ENOLCK
|
||||
| wasi::__WASI_ENOLINK
|
||||
| wasi::__WASI_ENOMEM
|
||||
| wasi::__WASI_ENOMSG
|
||||
| wasi::__WASI_ENOSPC
|
||||
| wasi::__WASI_ENOSYS
|
||||
| wasi::__WASI_ENOTDIR
|
||||
| wasi::__WASI_ENOTRECOVERABLE
|
||||
| wasi::__WASI_ENOTSUP
|
||||
| wasi::__WASI_ENOTTY
|
||||
| wasi::__WASI_ENXIO
|
||||
| wasi::__WASI_EOVERFLOW
|
||||
| wasi::__WASI_EOWNERDEAD
|
||||
| wasi::__WASI_EPROTO
|
||||
| wasi::__WASI_ERANGE
|
||||
| wasi::__WASI_EROFS
|
||||
| wasi::__WASI_ESPIPE
|
||||
| wasi::__WASI_ESRCH
|
||||
| wasi::__WASI_ETXTBSY
|
||||
| wasi::__WASI_EXDEV
|
||||
| wasi::__WASI_ENOTCAPABLE => {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, error_str(errno)))
|
||||
}
|
||||
_ => panic!("unrecognized WASI errno value"),
|
||||
} as i32;
|
||||
|
||||
Err(io::Error::from_raw_os_error(raw_os_error))
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn error_str(errno: wasi::__wasi_errno_t) -> &'static str {
|
||||
match errno {
|
||||
wasi::__WASI_E2BIG => "Argument list too long",
|
||||
wasi::__WASI_EACCES => "Permission denied",
|
||||
wasi::__WASI_EADDRINUSE => "Address in use",
|
||||
wasi::__WASI_EADDRNOTAVAIL => "Address not available",
|
||||
wasi::__WASI_EAFNOSUPPORT => "Address family not supported by protocol",
|
||||
wasi::__WASI_EAGAIN => "Resource temporarily unavailable",
|
||||
wasi::__WASI_EALREADY => "Operation already in progress",
|
||||
wasi::__WASI_EBADF => "Bad file descriptor",
|
||||
wasi::__WASI_EBADMSG => "Bad message",
|
||||
wasi::__WASI_EBUSY => "Resource busy",
|
||||
wasi::__WASI_ECANCELED => "Operation canceled",
|
||||
wasi::__WASI_ECHILD => "No child process",
|
||||
wasi::__WASI_ECONNABORTED => "Connection aborted",
|
||||
wasi::__WASI_ECONNREFUSED => "Connection refused",
|
||||
wasi::__WASI_ECONNRESET => "Connection reset by peer",
|
||||
wasi::__WASI_EDEADLK => "Resource deadlock would occur",
|
||||
wasi::__WASI_EDESTADDRREQ => "Destination address required",
|
||||
wasi::__WASI_EDOM => "Domain error",
|
||||
wasi::__WASI_EDQUOT => "Quota exceeded",
|
||||
wasi::__WASI_EEXIST => "File exists",
|
||||
wasi::__WASI_EFAULT => "Bad address",
|
||||
wasi::__WASI_EFBIG => "File too large",
|
||||
wasi::__WASI_EHOSTUNREACH => "Host is unreachable",
|
||||
wasi::__WASI_EIDRM => "Identifier removed",
|
||||
wasi::__WASI_EILSEQ => "Illegal byte sequence",
|
||||
wasi::__WASI_EINPROGRESS => "Operation in progress",
|
||||
wasi::__WASI_EINTR => "Interrupted system call",
|
||||
wasi::__WASI_EINVAL => "Invalid argument",
|
||||
wasi::__WASI_EIO => "Remote I/O error",
|
||||
wasi::__WASI_EISCONN => "Socket is connected",
|
||||
wasi::__WASI_EISDIR => "Is a directory",
|
||||
wasi::__WASI_ELOOP => "Symbolic link loop",
|
||||
wasi::__WASI_EMFILE => "No file descriptors available",
|
||||
wasi::__WASI_EMLINK => "Too many links",
|
||||
wasi::__WASI_EMSGSIZE => "Message too large",
|
||||
wasi::__WASI_EMULTIHOP => "Multihop attempted",
|
||||
wasi::__WASI_ENAMETOOLONG => "Filename too long",
|
||||
wasi::__WASI_ENETDOWN => "Network is down",
|
||||
wasi::__WASI_ENETRESET => "Connection reset by network",
|
||||
wasi::__WASI_ENETUNREACH => "Network unreachable",
|
||||
wasi::__WASI_ENFILE => "Too many open files in system",
|
||||
wasi::__WASI_ENOBUFS => "No buffer space available",
|
||||
wasi::__WASI_ENODEV => "No such device",
|
||||
wasi::__WASI_ENOENT => "No such file or directory",
|
||||
wasi::__WASI_ENOEXEC => "Exec format error",
|
||||
wasi::__WASI_ENOLCK => "No locks available",
|
||||
wasi::__WASI_ENOLINK => "Link has been severed",
|
||||
wasi::__WASI_ENOMEM => "Out of memory",
|
||||
wasi::__WASI_ENOMSG => "No message of desired type",
|
||||
wasi::__WASI_ENOPROTOOPT => "Protocol not available",
|
||||
wasi::__WASI_ENOSPC => "No space left on device",
|
||||
wasi::__WASI_ENOSYS => "Function not implemented",
|
||||
wasi::__WASI_ENOTCONN => "Socket not connected",
|
||||
wasi::__WASI_ENOTDIR => "Not a directory",
|
||||
wasi::__WASI_ENOTEMPTY => "Directory not empty",
|
||||
wasi::__WASI_ENOTRECOVERABLE => "State not recoverable",
|
||||
wasi::__WASI_ENOTSOCK => "Not a socket",
|
||||
wasi::__WASI_ENOTSUP => "Not supported",
|
||||
wasi::__WASI_ENOTTY => "Not a tty",
|
||||
wasi::__WASI_ENXIO => "No such device or address",
|
||||
wasi::__WASI_EOVERFLOW => "Value too large for data type",
|
||||
wasi::__WASI_EOWNERDEAD => "Previous owner died",
|
||||
wasi::__WASI_EPERM => "Operation not permitted",
|
||||
wasi::__WASI_EPIPE => "Broken pipe",
|
||||
wasi::__WASI_EPROTO => "Protocol error",
|
||||
wasi::__WASI_EPROTONOSUPPORT => "Protocol not supported",
|
||||
wasi::__WASI_EPROTOTYPE => "Protocol wrong type for socket",
|
||||
wasi::__WASI_ERANGE => "Result not representable",
|
||||
wasi::__WASI_EROFS => "Read-only file system",
|
||||
wasi::__WASI_ESPIPE => "Invalid seek",
|
||||
wasi::__WASI_ESRCH => "No such process",
|
||||
wasi::__WASI_ESTALE => "Stale file handle",
|
||||
wasi::__WASI_ETIMEDOUT => "Operation timed out",
|
||||
wasi::__WASI_ETXTBSY => "Text file busy",
|
||||
wasi::__WASI_EXDEV => "Cross-device link",
|
||||
wasi::__WASI_ENOTCAPABLE => "Capabilities insufficient",
|
||||
_ => panic!("unrecognized WASI errno value"),
|
||||
}
|
||||
}
|
||||
107
crates/wasi-common/src/fs/file.rs
Normal file
107
crates/wasi-common/src/fs/file.rs
Normal file
@@ -0,0 +1,107 @@
|
||||
use crate::fs::{error::wasi_errno_to_io_error, Metadata};
|
||||
use crate::{host, hostcalls, wasi, WasiCtx};
|
||||
use std::io;
|
||||
|
||||
/// A reference to an open file on the filesystem.
|
||||
///
|
||||
/// This corresponds to [`std::fs::File`].
|
||||
///
|
||||
/// Note that this `File` has no `open` or `create` methods. To open or create
|
||||
/// a file, you must first obtain a [`Dir`] containing the file, and then call
|
||||
/// [`Dir::open_file`] or [`Dir::create_file`].
|
||||
///
|
||||
/// [`std::fs::File`]: https://doc.rust-lang.org/std/fs/struct.File.html
|
||||
/// [`Dir`]: struct.Dir.html
|
||||
/// [`Dir::open_file`]: struct.Dir.html#method.open_file
|
||||
/// [`Dir::create_file`]: struct.Dir.html#method.create_file
|
||||
pub struct File<'ctx> {
|
||||
ctx: &'ctx mut WasiCtx,
|
||||
fd: wasi::__wasi_fd_t,
|
||||
}
|
||||
|
||||
impl<'ctx> File<'ctx> {
|
||||
/// Constructs a new instance of `Self` from the given raw WASI file descriptor.
|
||||
///
|
||||
/// This corresponds to [`std::fs::File::from_raw_fd`].
|
||||
///
|
||||
/// [`std::fs::File::from_raw_fd`]: https://doc.rust-lang.org/std/fs/struct.File.html#method.from_raw_fd
|
||||
pub unsafe fn from_raw_wasi_fd(ctx: &'ctx mut WasiCtx, fd: wasi::__wasi_fd_t) -> Self {
|
||||
Self { ctx, fd }
|
||||
}
|
||||
|
||||
/// Attempts to sync all OS-internal metadata to disk.
|
||||
///
|
||||
/// This corresponds to [`std::fs::File::sync_all`].
|
||||
///
|
||||
/// [`std::fs::File::sync_all`]: https://doc.rust-lang.org/std/fs/struct.File.html#method.sync_all
|
||||
pub fn sync_all(&self) -> io::Result<()> {
|
||||
wasi_errno_to_io_error(unsafe { hostcalls::fd_sync(self.ctx, self.fd) })
|
||||
}
|
||||
|
||||
/// This function is similar to `sync_all`, except that it may not synchronize
|
||||
/// file metadata to the filesystem.
|
||||
///
|
||||
/// This corresponds to [`std::fs::File::sync_data`].
|
||||
///
|
||||
/// [`std::fs::File::sync_data`]: https://doc.rust-lang.org/std/fs/struct.File.html#method.sync_data
|
||||
pub fn sync_data(&self) -> io::Result<()> {
|
||||
wasi_errno_to_io_error(unsafe { hostcalls::fd_datasync(self.ctx, self.fd) })
|
||||
}
|
||||
|
||||
/// Truncates or extends the underlying file, updating the size of this file
|
||||
/// to become size.
|
||||
///
|
||||
/// This corresponds to [`std::fs::File::set_len`].
|
||||
///
|
||||
/// [`std::fs::File::set_len`]: https://doc.rust-lang.org/std/fs/struct.File.html#method.set_len
|
||||
pub fn set_len(&self, size: u64) -> io::Result<()> {
|
||||
wasi_errno_to_io_error(unsafe { hostcalls::fd_filestat_set_size(self.ctx, self.fd, size) })
|
||||
}
|
||||
|
||||
/// Queries metadata about the underlying file.
|
||||
///
|
||||
/// This corresponds to [`std::fs::File::metadata`].
|
||||
///
|
||||
/// [`std::fs::File::metadata`]: https://doc.rust-lang.org/std/fs/struct.File.html#method.metadata
|
||||
pub fn metadata(&self) -> io::Result<Metadata> {
|
||||
Ok(Metadata {})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ctx> Drop for File<'ctx> {
|
||||
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 _ = unsafe { hostcalls::fd_close(self.ctx, self.fd) };
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ctx> io::Read for File<'ctx> {
|
||||
/// TODO: Not yet implemented. See the comment in `Dir::open_file`.
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
let iov = [host::__wasi_iovec_t {
|
||||
buf: buf.as_mut_ptr() as *mut u8,
|
||||
buf_len: buf.len(),
|
||||
}];
|
||||
let mut nread = 0;
|
||||
|
||||
// TODO: See the comment in `Dir::open_file`.
|
||||
unimplemented!("File::read");
|
||||
/*
|
||||
wasi_errno_to_io_error(unsafe {
|
||||
hostcalls::fd_read(self.ctx, self.fd, &iov, 1, &mut nread)
|
||||
})?;
|
||||
*/
|
||||
|
||||
Ok(nread)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: traits to implement: Write, Seek
|
||||
|
||||
// TODO: functions from FileExt?
|
||||
|
||||
// TODO: impl Debug for File
|
||||
49
crates/wasi-common/src/fs/file_type.rs
Normal file
49
crates/wasi-common/src/fs/file_type.rs
Normal file
@@ -0,0 +1,49 @@
|
||||
/// A structure representing a type of file with accessors for each file type.
|
||||
/// It is returned by `Metadata::file_type` method.
|
||||
///
|
||||
/// This corresponds to [`std::fs::FileType`].
|
||||
///
|
||||
/// TODO: Not yet implemented.
|
||||
///
|
||||
/// [`std::fs::FileType`]: https://doc.rust-lang.org/std/fs/struct.FileType.html
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub struct FileType {}
|
||||
|
||||
impl FileType {
|
||||
/// Tests whether this file type represents a directory.
|
||||
///
|
||||
/// This corresponds to [`std::fs::FileType::is_dir`].
|
||||
///
|
||||
/// TODO: Not yet implemented.
|
||||
///
|
||||
/// [`std::fs::FileType::is_dir`]: https://doc.rust-lang.org/std/fs/struct.FileType.html#method.is_dir
|
||||
pub fn is_dir(&self) -> bool {
|
||||
unimplemented!("FileType::is_dir");
|
||||
}
|
||||
|
||||
/// Tests whether this file type represents a regular file.
|
||||
///
|
||||
/// This corresponds to [`std::fs::FileType::is_file`].
|
||||
///
|
||||
/// TODO: Not yet implemented.
|
||||
///
|
||||
/// [`std::fs::FileType::is_file`]: https://doc.rust-lang.org/std/fs/struct.FileType.html#method.is_file
|
||||
pub fn is_file(&self) -> bool {
|
||||
unimplemented!("FileType::is_file");
|
||||
}
|
||||
|
||||
/// Tests whether this file type represents a symbolic link.
|
||||
///
|
||||
/// This corresponds to [`std::fs::FileType::is_symlink`].
|
||||
///
|
||||
/// TODO: Not yet implemented.
|
||||
///
|
||||
/// [`std::fs::FileType::is_symlink`]: https://doc.rust-lang.org/std/fs/struct.FileType.html#method.is_symlink
|
||||
pub fn is_symlink(&self) -> bool {
|
||||
unimplemented!("FileType::is_symlink");
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: functions from FileTypeExt?
|
||||
|
||||
// TODO: impl Debug for FileType
|
||||
106
crates/wasi-common/src/fs/metadata.rs
Normal file
106
crates/wasi-common/src/fs/metadata.rs
Normal file
@@ -0,0 +1,106 @@
|
||||
use crate::fs::{FileType, Permissions};
|
||||
use std::{io, time::SystemTime};
|
||||
|
||||
/// Metadata information about a file.
|
||||
///
|
||||
/// This corresponds to [`std::fs::Metadata`].
|
||||
///
|
||||
/// TODO: Not yet implemented.
|
||||
///
|
||||
/// [`std::fs::Metadata`]: https://doc.rust-lang.org/std/fs/struct.Metadata.html
|
||||
#[derive(Clone)]
|
||||
pub struct Metadata {}
|
||||
|
||||
impl Metadata {
|
||||
/// Returns the file type for this metadata.
|
||||
///
|
||||
/// This corresponds to [`std::fs::Metadata::file_type`].
|
||||
///
|
||||
/// TODO: Not yet implemented.
|
||||
///
|
||||
/// [`std::fs::Metadata::file_type`]: https://doc.rust-lang.org/std/fs/struct.Metadata.html#method.file_type
|
||||
pub fn file_type(&self) -> FileType {
|
||||
unimplemented!("Metadata::file_type");
|
||||
}
|
||||
|
||||
/// Returns true if this metadata is for a directory.
|
||||
///
|
||||
/// This corresponds to [`std::fs::Metadata::is_dir`].
|
||||
///
|
||||
/// TODO: Not yet implemented.
|
||||
///
|
||||
/// [`std::fs::Metadata::is_dir`]: https://doc.rust-lang.org/std/fs/struct.Metadata.html#method.is_dir
|
||||
pub fn is_dir(&self) -> bool {
|
||||
unimplemented!("Metadata::is_dir");
|
||||
}
|
||||
|
||||
/// Returns true if this metadata is for a regular file.
|
||||
///
|
||||
/// This corresponds to [`std::fs::Metadata::is_file`].
|
||||
///
|
||||
/// TODO: Not yet implemented.
|
||||
///
|
||||
/// [`std::fs::Metadata::is_file`]: https://doc.rust-lang.org/std/fs/struct.Metadata.html#method.is_file
|
||||
pub fn is_file(&self) -> bool {
|
||||
unimplemented!("Metadata::is_file");
|
||||
}
|
||||
|
||||
/// Returns the size of the file, in bytes, this metadata is for.
|
||||
///
|
||||
/// This corresponds to [`std::fs::Metadata::len`].
|
||||
///
|
||||
/// TODO: Not yet implemented.
|
||||
///
|
||||
/// [`std::fs::Metadata::len`]: https://doc.rust-lang.org/std/fs/struct.Metadata.html#method.len
|
||||
pub fn len(&self) -> u64 {
|
||||
unimplemented!("Metadata::len");
|
||||
}
|
||||
|
||||
/// Returns the permissions of the file this metadata is for.
|
||||
///
|
||||
/// This corresponds to [`std::fs::Metadata::permissions`].
|
||||
///
|
||||
/// TODO: Not yet implemented.
|
||||
///
|
||||
/// [`std::fs::Metadata::permissions`]: https://doc.rust-lang.org/std/fs/struct.Metadata.html#method.permissions
|
||||
pub fn permissions(&self) -> Permissions {
|
||||
unimplemented!("Metadata::permissions");
|
||||
}
|
||||
|
||||
/// Returns the last modification time listed in this metadata.
|
||||
///
|
||||
/// This corresponds to [`std::fs::Metadata::modified`].
|
||||
///
|
||||
/// TODO: Not yet implemented.
|
||||
///
|
||||
/// [`std::fs::Metadata::modified`]: https://doc.rust-lang.org/std/fs/struct.Metadata.html#method.modified
|
||||
pub fn modified(&self) -> io::Result<SystemTime> {
|
||||
unimplemented!("Metadata::modified");
|
||||
}
|
||||
|
||||
/// Returns the last access time of this metadata.
|
||||
///
|
||||
/// This corresponds to [`std::fs::Metadata::accessed`].
|
||||
///
|
||||
/// TODO: Not yet implemented.
|
||||
///
|
||||
/// [`std::fs::Metadata::accessed`]: https://doc.rust-lang.org/std/fs/struct.Metadata.html#method.accessed
|
||||
pub fn accessed(&self) -> io::Result<SystemTime> {
|
||||
unimplemented!("Metadata::accessed");
|
||||
}
|
||||
|
||||
/// Returns the creation time listed in this metadata.
|
||||
///
|
||||
/// This corresponds to [`std::fs::Metadata::created`].
|
||||
///
|
||||
/// TODO: Not yet implemented.
|
||||
///
|
||||
/// [`std::fs::Metadata::created`]: https://doc.rust-lang.org/std/fs/struct.Metadata.html#method.created
|
||||
pub fn created(&self) -> io::Result<SystemTime> {
|
||||
unimplemented!("Metadata::created");
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Functions from MetadataExt?
|
||||
|
||||
// TODO: impl Debug for Metadata
|
||||
51
crates/wasi-common/src/fs/mod.rs
Normal file
51
crates/wasi-common/src/fs/mod.rs
Normal file
@@ -0,0 +1,51 @@
|
||||
//! A very experimental module modeled providing a high-level and safe
|
||||
//! filesystem interface, modeled after `std::fs`, implemented on top of
|
||||
//! WASI functions.
|
||||
//!
|
||||
//! Most functions in this API are not yet implemented!
|
||||
//!
|
||||
//! This corresponds to [`std::fs`].
|
||||
//!
|
||||
//! Instead of [`std::fs`'s free functions] which operate on paths, this
|
||||
//! crate has methods on [`Dir`] which operate on paths which must be
|
||||
//! relative to and within the directory.
|
||||
//!
|
||||
//! Since all functions which expose raw file descriptors are `unsafe`,
|
||||
//! I/O handles in this API are unforgeable (unsafe code notwithstanding).
|
||||
//! This combined with WASI's lack of absolute paths provides a natural
|
||||
//! capability-oriented interface.
|
||||
//!
|
||||
//! [`std::fs`]: https://doc.rust-lang.org/std/fs/index.html
|
||||
//! [`std::fs`'s free functions]: https://doc.rust-lang.org/std/fs/index.html#functions
|
||||
//! [`DIR`]: struct.Dir.html
|
||||
|
||||
// TODO: When more things are implemented, remove these.
|
||||
#![allow(
|
||||
unused_imports,
|
||||
unreachable_code,
|
||||
unused_variables,
|
||||
unused_mut,
|
||||
unused_unsafe,
|
||||
dead_code
|
||||
)]
|
||||
|
||||
mod dir;
|
||||
mod dir_builder;
|
||||
mod dir_entry;
|
||||
mod error;
|
||||
mod file;
|
||||
mod file_type;
|
||||
mod metadata;
|
||||
mod open_options;
|
||||
mod permissions;
|
||||
mod readdir;
|
||||
|
||||
pub use dir::*;
|
||||
pub use dir_builder::*;
|
||||
pub use dir_entry::*;
|
||||
pub use file::*;
|
||||
pub use file_type::*;
|
||||
pub use metadata::*;
|
||||
pub use open_options::*;
|
||||
pub use permissions::*;
|
||||
pub use readdir::*;
|
||||
99
crates/wasi-common/src/fs/open_options.rs
Normal file
99
crates/wasi-common/src/fs/open_options.rs
Normal file
@@ -0,0 +1,99 @@
|
||||
/// Options and flags which can be used to configure how a file is opened.
|
||||
///
|
||||
/// This corresponds to [`std::fs::OpenOptions`].
|
||||
///
|
||||
/// Note that this `OpenOptions` has no `open` method. To open a file with
|
||||
/// an `OptionOptions`, you must first obtain a [`Dir`] containing the file, and
|
||||
/// then call [`Dir::open_file_with`].
|
||||
///
|
||||
/// [`std::fs::OpenOptions`]: https://doc.rust-lang.org/std/fs/struct.OpenOptions.html
|
||||
/// [`Dir`]: struct.Dir.html
|
||||
/// [`Dir::open_file_with`]: struct.Dir.html#method.open_file_with
|
||||
pub struct OpenOptions {
|
||||
pub(crate) read: bool,
|
||||
pub(crate) write: bool,
|
||||
pub(crate) append: bool,
|
||||
pub(crate) truncate: bool,
|
||||
pub(crate) create: bool,
|
||||
pub(crate) create_new: bool,
|
||||
}
|
||||
|
||||
impl OpenOptions {
|
||||
/// Creates a blank new set of options ready for configuration.
|
||||
///
|
||||
/// This corresponds to [`std::fs::OpenOptions::new`].
|
||||
///
|
||||
/// [`std::fs::OpenOptions::new`]: https://doc.rust-lang.org/std/fs/struct.OpenOptions.html#method.new
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
read: false,
|
||||
write: false,
|
||||
append: false,
|
||||
truncate: false,
|
||||
create: false,
|
||||
create_new: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the option for read access.
|
||||
///
|
||||
/// This corresponds to [`std::fs::OpenOptions::read`].
|
||||
///
|
||||
/// [`std::fs::OpenOptions::read`]: https://doc.rust-lang.org/std/fs/struct.OpenOptions.html#method.read
|
||||
pub fn read(&mut self, read: bool) -> &mut Self {
|
||||
self.read = read;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the option for write access.
|
||||
///
|
||||
/// This corresponds to [`std::fs::OpenOptions::write`].
|
||||
///
|
||||
/// [`std::fs::OpenOptions::write`]: https://doc.rust-lang.org/std/fs/struct.OpenOptions.html#method.write
|
||||
pub fn write(&mut self, write: bool) -> &mut Self {
|
||||
self.write = write;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the option for the append mode.
|
||||
///
|
||||
/// This corresponds to [`std::fs::OpenOptions::append`].
|
||||
///
|
||||
/// [`std::fs::OpenOptions::append`]: https://doc.rust-lang.org/std/fs/struct.OpenOptions.html#method.append
|
||||
pub fn append(&mut self, append: bool) -> &mut Self {
|
||||
self.append = append;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the option for truncating a previous file.
|
||||
///
|
||||
/// This corresponds to [`std::fs::OpenOptions::truncate`].
|
||||
///
|
||||
/// [`std::fs::OpenOptions::truncate`]: https://doc.rust-lang.org/std/fs/struct.OpenOptions.html#method.truncate
|
||||
pub fn truncate(&mut self, truncate: bool) -> &mut Self {
|
||||
self.truncate = truncate;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the option to create a new file.
|
||||
///
|
||||
/// This corresponds to [`std::fs::OpenOptions::create`].
|
||||
///
|
||||
/// [`std::fs::OpenOptions::create`]: https://doc.rust-lang.org/std/fs/struct.OpenOptions.html#method.create
|
||||
pub fn create(&mut self, create: bool) -> &mut Self {
|
||||
self.create = create;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the option to always create a new file.
|
||||
///
|
||||
/// This corresponds to [`std::fs::OpenOptions::create_new`].
|
||||
///
|
||||
/// [`std::fs::OpenOptions::create_new`]: https://doc.rust-lang.org/std/fs/struct.OpenOptions.html#method.create_new
|
||||
pub fn create_new(&mut self, create_new: bool) -> &mut Self {
|
||||
self.create_new = create_new;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Functions from OpenOptionsExt?
|
||||
37
crates/wasi-common/src/fs/permissions.rs
Normal file
37
crates/wasi-common/src/fs/permissions.rs
Normal file
@@ -0,0 +1,37 @@
|
||||
/// Representation of the various permissions on a file.
|
||||
///
|
||||
/// This corresponds to [`std::fs::Permissions`].
|
||||
///
|
||||
/// TODO: Not yet implemented.
|
||||
///
|
||||
/// [`std::fs::Permissions`]: https://doc.rust-lang.org/std/fs/struct.Permissions.html
|
||||
#[derive(Eq, PartialEq, Clone)]
|
||||
pub struct Permissions {}
|
||||
|
||||
impl Permissions {
|
||||
/// Returns true if these permissions describe a readonly (unwritable) file.
|
||||
///
|
||||
/// This corresponds to [`std::fs::Permissions::readonly`].
|
||||
///
|
||||
/// TODO: Not yet implemented.
|
||||
///
|
||||
/// [`std::fs::Permissions::readonly`]: https://doc.rust-lang.org/std/fs/struct.Permissions.html#method.readonly
|
||||
pub fn readonly(&self) -> bool {
|
||||
unimplemented!("Permissions::readonly");
|
||||
}
|
||||
|
||||
/// Modifies the readonly flag for this set of permissions.
|
||||
///
|
||||
/// This corresponds to [`std::fs::Permissions::set_readonly`].
|
||||
///
|
||||
/// TODO: Not yet implemented.
|
||||
///
|
||||
/// [`std::fs::Permissions::set_readonly`]: https://doc.rust-lang.org/std/fs/struct.Permissions.html#method.set_readonly
|
||||
pub fn set_readonly(&mut self, readonly: bool) {
|
||||
unimplemented!("Permissions::set_readonly");
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: functions from PermissionsExt?
|
||||
|
||||
// TODO: impl Debug for Permissions
|
||||
32
crates/wasi-common/src/fs/readdir.rs
Normal file
32
crates/wasi-common/src/fs/readdir.rs
Normal file
@@ -0,0 +1,32 @@
|
||||
use crate::fs::DirEntry;
|
||||
use crate::{hostcalls, wasi};
|
||||
|
||||
/// Iterator over the entries in a directory.
|
||||
///
|
||||
/// This corresponds to [`std::fs::ReadDir`].
|
||||
///
|
||||
/// TODO: Not yet implemented.
|
||||
///
|
||||
/// [`std::fs::ReadDir`]: https://doc.rust-lang.org/std/fs/struct.ReadDir.html
|
||||
pub struct ReadDir {
|
||||
fd: wasi::__wasi_fd_t,
|
||||
}
|
||||
|
||||
impl ReadDir {
|
||||
/// Constructs a new instance of `Self` from the given raw WASI file descriptor.
|
||||
pub unsafe fn from_raw_wasi_fd(fd: wasi::__wasi_fd_t) -> Self {
|
||||
Self { fd }
|
||||
}
|
||||
}
|
||||
|
||||
/// TODO: Not yet implemented.
|
||||
impl Iterator for ReadDir {
|
||||
type Item = DirEntry;
|
||||
|
||||
/// TODO: Not yet implemented.
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
unimplemented!("ReadDir::next");
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: impl Debug for ReadDir
|
||||
Reference in New Issue
Block a user