Files
wasmer/lib/runtime-abi/src/vfs/vfs.rs

170 lines
6.0 KiB
Rust
Raw Normal View History

2019-03-21 08:55:23 -07:00
use crate::vfs::file_like::FileLike;
2019-03-14 13:32:47 -07:00
use crate::vfs::vfs_header::{header_from_bytes, ArchiveType, CompressionType};
2019-03-25 19:43:52 -07:00
use hashbrown::HashMap;
use std::cell::RefCell;
2019-03-13 14:22:32 -07:00
use std::io;
2019-03-13 14:27:00 -07:00
use std::io::Read;
use std::path::{Path, PathBuf};
2019-03-21 08:55:23 -07:00
use std::rc::Rc;
use tar::EntryType;
2019-03-13 14:27:00 -07:00
use zbox::{init_env, OpenOptions, Repo, RepoOpener};
2019-03-13 14:22:32 -07:00
pub struct Vfs {
2019-03-21 08:55:23 -07:00
repo: Repo,
2019-03-25 19:43:52 -07:00
device_files: HashMap<PathBuf, Rc<RefCell<dyn FileLike>>>,
}
2019-03-13 14:22:32 -07:00
impl Vfs {
/// Like `VfsBacking::from_tar_bytes` except it also decompresses from the zstd format.
pub fn from_tar_zstd_bytes<Reader: Read>(tar_bytes: Reader) -> Result<Self, failure::Error> {
let result = zstd::decode_all(tar_bytes);
let decompressed_data = result.unwrap();
2019-03-25 19:43:52 -07:00
Self::from_tar_bytes(&decompressed_data[..])
}
2019-03-21 08:55:23 -07:00
/// Match on the type of the compressed-archive and select the correct unpack method
2019-03-14 13:32:47 -07:00
pub fn from_compressed_bytes(compressed_data_slice: &[u8]) -> Result<Self, failure::Error> {
let data_bytes = &compressed_data_slice[4..];
match header_from_bytes(compressed_data_slice)? {
2019-03-25 19:43:52 -07:00
(_, CompressionType::ZSTD, ArchiveType::TAR) => Self::from_tar_zstd_bytes(data_bytes),
(_, CompressionType::NONE, ArchiveType::TAR) => Self::from_tar_bytes(data_bytes),
2019-03-14 13:32:47 -07:00
}
}
/// Create a vfs from raw bytes in tar format
pub fn from_tar_bytes<Reader: Read>(tar_bytes: Reader) -> Result<Self, failure::Error> {
2019-03-13 14:22:32 -07:00
init_env();
2019-03-13 14:27:00 -07:00
let mut repo = RepoOpener::new()
.create(true)
.open("mem://wasmer_fs", "")
.unwrap();
let _errors = tar::Archive::new(tar_bytes)
2019-03-21 08:55:23 -07:00
.entries()?
.map(|entry| {
let mut entry: tar::Entry<Reader> = entry?;
let path = entry.path()?;
let path = convert_to_absolute_path(path);
let _result = match (entry.header().entry_type(), path.parent()) {
2019-03-21 08:55:23 -07:00
(EntryType::Regular, Some(parent)) => {
if let Err(e) = repo.create_dir_all(parent) {
if e == zbox::Error::AlreadyExists || e == zbox::Error::IsRoot {
} else {
return Err(VfsAggregateError::ZboxError(e));
}
} else {
}
let mut file = repo.create_file(&path)?;
if entry.header().size().unwrap_or(0) > 0 {
io::copy(&mut entry, &mut file)?;
file.finish()?;
}
}
(EntryType::Directory, _) => {
if let Err(e) = repo.create_dir_all(path) {
if e == zbox::Error::AlreadyExists || e == zbox::Error::IsRoot {
} else {
return Err(VfsAggregateError::ZboxError(e));
}
} else {
}
}
_ => return Err(VfsAggregateError::UnsupportedFileType),
};
Ok(())
})
.collect::<Vec<Result<(), VfsAggregateError>>>();
// let import_errors = errors.iter().filter_map(|e| e.err()).collect::<Vec<_>>();
2019-03-25 19:43:52 -07:00
let vfs = Self {
2019-03-13 14:22:32 -07:00
repo,
2019-03-25 19:43:52 -07:00
device_files: HashMap::new(),
// import_errors: vec![],
};
Ok(vfs)
}
2019-03-13 14:22:32 -07:00
2019-03-25 19:43:52 -07:00
pub fn new() -> Result<(Self, Vec<VfsError>), failure::Error> {
init_env();
let repo = RepoOpener::new()
.create(true)
.open("mem://wasmer_fs", "")
.unwrap();
Ok((
Vfs {
repo,
device_files: HashMap::new(),
},
vec![],
))
2019-03-13 14:22:32 -07:00
}
2019-03-25 19:43:52 -07:00
pub fn open_file<P: AsRef<Path>>(&mut self, path: P) -> Option<Rc<RefCell<dyn FileLike>>> {
init_env();
2019-03-13 14:22:32 -07:00
let path = convert_to_absolute_path(path);
2019-03-25 19:43:52 -07:00
if let Ok(file) = OpenOptions::new().write(true).open(&mut self.repo, &path) {
Some(Rc::new(RefCell::new(file)))
} else if let Some(dev_file) = self.device_files.get(&path) {
Some(dev_file.clone())
2019-03-13 14:27:00 -07:00
} else {
2019-03-25 19:43:52 -07:00
None
2019-03-21 08:55:23 -07:00
}
}
2019-03-25 19:43:52 -07:00
pub fn make_dir<P: AsRef<Path>>(&mut self, path: P) {
self.repo.create_dir_all(path).unwrap();
2019-03-21 08:55:23 -07:00
}
2019-03-25 19:43:52 -07:00
pub fn create_device_file<P: AsRef<Path>>(&mut self, path: P, file: Rc<RefCell<dyn FileLike>>) {
self.device_files.insert(path.as_ref().to_path_buf(), file);
2019-03-21 08:55:23 -07:00
}
2019-03-25 19:43:52 -07:00
}
2019-03-21 08:55:23 -07:00
2019-03-25 19:43:52 -07:00
fn convert_to_absolute_path<P: AsRef<Path>>(path: P) -> PathBuf {
let path = path.as_ref();
if path.is_relative() {
std::path::PathBuf::from("/").join(path)
} else {
path.to_path_buf()
2019-03-13 14:22:32 -07:00
}
}
2019-03-25 19:43:52 -07:00
pub type Handle = i32;
#[derive(Debug, Fail)]
2019-03-13 14:22:32 -07:00
pub enum VfsError {
2019-03-21 08:55:23 -07:00
#[fail(display = "File with file descriptor \"{}\" does not exist.", _0)]
2019-03-25 19:43:52 -07:00
FileWithFileDescriptorNotExist(Handle),
#[fail(display = "File descriptor does not exist.")]
2019-03-25 19:43:52 -07:00
FileDescriptorNotExist(Handle),
2019-03-21 08:55:23 -07:00
#[fail(display = "Source file descriptor does not exist.")]
SourceFileDescriptorDoesNotExist,
#[fail(display = "Target file descriptor already exists.")]
TargetFileDescriptorAlreadyExists,
#[fail(display = "Could not get a mutable reference to the file because it is in use.")]
CouldNotGetMutableReferenceToFile,
}
#[derive(Debug, Fail)]
pub enum VfsAggregateError {
#[fail(display = "Entry error.")]
EntryError(std::io::Error),
#[fail(display = "IO error.")]
IoError(std::io::Error),
#[fail(display = "Zbox error.")]
ZboxError(zbox::Error),
#[fail(display = "Unsupported file type.")]
UnsupportedFileType,
}
impl std::convert::From<std::io::Error> for VfsAggregateError {
fn from(error: std::io::Error) -> VfsAggregateError {
VfsAggregateError::EntryError(error)
}
}
impl std::convert::From<zbox::Error> for VfsAggregateError {
fn from(error: zbox::Error) -> VfsAggregateError {
VfsAggregateError::ZboxError(error)
}
}