* Introduce WasiCtxBuilderError error type `WasiCtxBuilderError` is the `wasi-common` client-facing error type which is exclusively thrown when building a new `WasiCtx` instance. As such, building such an instance should not require the client to understand different WASI errno values as was assumed until now. This commit is a first step at streamlining error handling in `wasi-common` and makes way for the `wiggle` crate. When adding the `WasiCtxBuilderError`, I've had to do two things of notable importance: 1. I've removed a couple of `ok_or` calls in `WasiCtxBuilder::build` and replaced them with `unwrap`s, following the same pattern in different builder methods above. This is fine since we _always_ operate on non-empty `Option`s in `WasiCtxBuilder` thus `unwrap`ing will never fail. On the other hand, this might be a good opportunity to rethink the structure of our builder, and how we good remove the said `Option`s especially since we always populate them with empty containers to begin with. I understand this is to make chaining of builder methods easier which take and return `&mut self` and the same applies to `WasiCtxBuilder::build(&mut self)` method, but perhaps it would more cleanly signal the intentions if we simply moved `WasiCtxBuilder` instance around. Food for thought! 2. Methods specific to determining rights of passed around `std::fs::File` objects when populating `WasiCtx` `FdEntry` entities now return `io::Error` directly so that we can reuse them in `WasiCtxBuilder` methods (returning `WasiCtxBuilderError` error type), and in syscalls (returning WASI errno). * Return WasiError directly in syscalls Also, removes `error::Error` type altogether. Now, `io::Error` and related are automatically converted to their corresponding WASI errno value encapsulated as `WasiError`. While here, it made sense to me to move `WasiError` to `wasi` module which will align itself well with the upcoming changes introduced by `wiggle`. To different standard `Result` from WASI specific, I've created a helper alias `WasiResult` also residing in `wasi` module. * Update wig * Add from ffi::NulError and pass context to NotADirectory * Add dummy commit to test CI
118 lines
3.9 KiB
Rust
118 lines
3.9 KiB
Rust
use crate::fs::Metadata;
|
|
use crate::wasi::{self, WasiResult};
|
|
use crate::{host, hostcalls, hostcalls_impl, 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) -> WasiResult<()> {
|
|
unsafe {
|
|
hostcalls_impl::fd_sync(self.ctx, &mut [], self.fd)?;
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
/// 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) -> WasiResult<()> {
|
|
unsafe {
|
|
hostcalls_impl::fd_datasync(self.ctx, &mut [], self.fd)?;
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
/// 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) -> WasiResult<()> {
|
|
unsafe {
|
|
hostcalls_impl::fd_filestat_set_size(self.ctx, &mut [], self.fd, size)?;
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
/// 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) -> WasiResult<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, &mut [], 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
|