Virtual file support (#701)

* Add support for virtual files (eg, not backed by an OS file).

Virtual files are implemented through trait objects, with a default
implementation that tries to behave like on-disk files, but entirely
backed by in-memory structures.

Co-authored-by: Dan Gohman <sunfish@mozilla.com>
This commit is contained in:
iximeow
2020-03-06 11:08:13 -08:00
committed by GitHub
parent 7f7196a655
commit 7e0d9decbf
19 changed files with 1568 additions and 188 deletions

View File

@@ -2,36 +2,75 @@ use crate::sys::dev_null;
use crate::sys::fdentry_impl::{
descriptor_as_oshandle, determine_type_and_access_rights, OsHandle,
};
use crate::virtfs::VirtualFile;
use crate::{wasi, Error, Result};
use std::marker::PhantomData;
use std::mem::ManuallyDrop;
use std::ops::{Deref, DerefMut};
use std::path::PathBuf;
use std::{fs, io};
use std::{fmt, fs, io};
#[derive(Debug)]
pub(crate) enum Descriptor {
OsHandle(OsHandle),
VirtualFile(Box<dyn VirtualFile>),
Stdin,
Stdout,
Stderr,
}
impl Descriptor {
/// Return a reference to the `OsHandle` treating it as an actual file/dir, and
/// allowing operations which require an actual file and not just a stream or
/// socket file descriptor.
pub(crate) fn as_file(&self) -> Result<&OsHandle> {
impl From<OsHandle> for Descriptor {
fn from(handle: OsHandle) -> Self {
Descriptor::OsHandle(handle)
}
}
impl From<Box<dyn VirtualFile>> for Descriptor {
fn from(virt: Box<dyn VirtualFile>) -> Self {
Descriptor::VirtualFile(virt)
}
}
impl fmt::Debug for Descriptor {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::OsHandle(file) => Ok(file),
Descriptor::OsHandle(handle) => write!(f, "{:?}", handle),
Descriptor::VirtualFile(_) => write!(f, "VirtualFile"),
Descriptor::Stdin => write!(f, "Stdin"),
Descriptor::Stdout => write!(f, "Stdout"),
Descriptor::Stderr => write!(f, "Stderr"),
}
}
}
impl Descriptor {
pub(crate) fn try_clone(&self) -> io::Result<Descriptor> {
match self {
Descriptor::OsHandle(file) => file.try_clone().map(|f| OsHandle::from(f).into()),
Descriptor::VirtualFile(virt) => virt.try_clone().map(Descriptor::VirtualFile),
Descriptor::Stdin => Ok(Descriptor::Stdin),
Descriptor::Stdout => Ok(Descriptor::Stdout),
Descriptor::Stderr => Ok(Descriptor::Stderr),
}
}
/// Return a reference to the `OsHandle` or `VirtualFile` treating it as an
/// actual file/dir, and allowing operations which require an actual file and
/// not just a stream or socket file descriptor.
pub(crate) fn as_file<'descriptor>(&'descriptor self) -> Result<&'descriptor Descriptor> {
match self {
Self::OsHandle(_) => Ok(self),
Self::VirtualFile(_) => Ok(self),
_ => Err(Error::EBADF),
}
}
/// Like `as_file`, but return a mutable reference.
pub(crate) fn as_file_mut(&mut self) -> Result<&mut OsHandle> {
pub(crate) fn as_file_mut<'descriptor>(
&'descriptor mut self,
) -> Result<&'descriptor mut Descriptor> {
match self {
Self::OsHandle(file) => Ok(file),
Self::OsHandle(_) => Ok(self),
Self::VirtualFile(_) => Ok(self),
_ => Err(Error::EBADF),
}
}
@@ -61,16 +100,33 @@ pub(crate) struct FdEntry {
}
impl FdEntry {
pub(crate) fn from(file: fs::File) -> Result<Self> {
unsafe { determine_type_and_access_rights(&file) }.map(
|(file_type, rights_base, rights_inheriting)| Self {
file_type,
descriptor: Descriptor::OsHandle(OsHandle::from(file)),
rights_base,
rights_inheriting,
preopen_path: None,
},
)
pub(crate) fn from(file: Descriptor) -> Result<Self> {
match file {
Descriptor::OsHandle(handle) => unsafe { determine_type_and_access_rights(&handle) }
.map(|(file_type, rights_base, rights_inheriting)| Self {
file_type,
descriptor: handle.into(),
rights_base,
rights_inheriting,
preopen_path: None,
}),
Descriptor::VirtualFile(virt) => {
let file_type = virt.get_file_type();
let rights_base = virt.get_rights_base();
let rights_inheriting = virt.get_rights_inheriting();
Ok(Self {
file_type,
descriptor: virt.into(),
rights_base,
rights_inheriting,
preopen_path: None,
})
}
Descriptor::Stdin | Descriptor::Stdout | Descriptor::Stderr => {
panic!("implementation error, stdin/stdout/stderr FdEntry must not be constructed from FdEntry::from");
}
}
}
pub(crate) fn duplicate_stdin() -> Result<Self> {
@@ -110,7 +166,7 @@ impl FdEntry {
}
pub(crate) fn null() -> Result<Self> {
Self::from(dev_null()?)
Self::from(OsHandle::from(dev_null()?).into())
}
/// Convert this `FdEntry` into a host `Descriptor` object provided the specified