add simple HostFS, mount it at /host
This commit is contained in:
parent
29278db8f4
commit
7f229cef50
283
src/libos/src/fs/hostfs.rs
Normal file
283
src/libos/src/fs/hostfs.rs
Normal file
@ -0,0 +1,283 @@
|
|||||||
|
use alloc::string::String;
|
||||||
|
use alloc::sync::{Arc, Weak};
|
||||||
|
use core::any::Any;
|
||||||
|
use rcore_fs::vfs::*;
|
||||||
|
use std::io::{Read, Seek, SeekFrom, Write};
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
use std::sync::{SgxMutex as Mutex, SgxMutexGuard as MutexGuard};
|
||||||
|
use std::untrusted::fs;
|
||||||
|
use std::untrusted::path::PathEx;
|
||||||
|
|
||||||
|
/// Untrusted file system at host
|
||||||
|
pub struct HostFS {
|
||||||
|
path: PathBuf,
|
||||||
|
self_ref: Weak<HostFS>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// INode for `HostFS`
|
||||||
|
pub struct HNode {
|
||||||
|
path: PathBuf,
|
||||||
|
file: Mutex<Option<fs::File>>,
|
||||||
|
fs: Arc<HostFS>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FileSystem for HostFS {
|
||||||
|
fn sync(&self) -> Result<()> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn root_inode(&self) -> Arc<INode> {
|
||||||
|
Arc::new(HNode {
|
||||||
|
path: self.path.clone(),
|
||||||
|
file: Mutex::new(None),
|
||||||
|
fs: self.self_ref.upgrade().unwrap(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn info(&self) -> FsInfo {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HostFS {
|
||||||
|
/// Create a new `HostFS` from host `path`
|
||||||
|
pub fn new(path: impl AsRef<Path>) -> Arc<HostFS> {
|
||||||
|
HostFS {
|
||||||
|
path: path.as_ref().to_path_buf(),
|
||||||
|
self_ref: Weak::default(),
|
||||||
|
}
|
||||||
|
.wrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wrap pure `HostFS` with Arc
|
||||||
|
/// Used in constructors
|
||||||
|
fn wrap(self) -> Arc<Self> {
|
||||||
|
// Create an Arc, make a Weak from it, then put it into the struct.
|
||||||
|
// It's a little tricky.
|
||||||
|
let fs = Arc::new(self);
|
||||||
|
let weak = Arc::downgrade(&fs);
|
||||||
|
let ptr = Arc::into_raw(fs) as *mut Self;
|
||||||
|
unsafe {
|
||||||
|
(*ptr).self_ref = weak;
|
||||||
|
}
|
||||||
|
unsafe { Arc::from_raw(ptr) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// workaround for unable to `impl From<std::io::Error> for FsError`
|
||||||
|
macro_rules! try_std {
|
||||||
|
($ret: expr) => {
|
||||||
|
$ret.map_err(|e| e.into_fs_error())?
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl INode for HNode {
|
||||||
|
fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
|
||||||
|
let mut guard = self.open_file()?;
|
||||||
|
let file = guard.as_mut().unwrap();
|
||||||
|
try_std!(file.seek(SeekFrom::Start(offset as u64)));
|
||||||
|
let len = try_std!(file.read(buf));
|
||||||
|
Ok(len)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
|
||||||
|
let mut guard = self.open_file()?;
|
||||||
|
let file = guard.as_mut().unwrap();
|
||||||
|
try_std!(file.seek(SeekFrom::Start(offset as u64)));
|
||||||
|
let len = try_std!(file.write(buf));
|
||||||
|
Ok(len)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn poll(&self) -> Result<PollStatus> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn metadata(&self) -> Result<Metadata> {
|
||||||
|
let metadata = try_std!(self.path.metadata());
|
||||||
|
Ok(metadata.into_fs_metadata())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_metadata(&self, metadata: &Metadata) -> Result<()> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sync_all(&self) -> Result<()> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sync_data(&self) -> Result<()> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resize(&self, len: usize) -> Result<()> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create(&self, name: &str, type_: FileType, mode: u32) -> Result<Arc<dyn INode>> {
|
||||||
|
let new_path = self.path.join(name);
|
||||||
|
if new_path.exists() {
|
||||||
|
return Err(FsError::EntryExist);
|
||||||
|
}
|
||||||
|
match type_ {
|
||||||
|
FileType::File => {
|
||||||
|
try_std!(fs::File::create(&new_path));
|
||||||
|
}
|
||||||
|
_ => unimplemented!("only support creating files in HostFS"),
|
||||||
|
}
|
||||||
|
Ok(Arc::new(HNode {
|
||||||
|
path: new_path,
|
||||||
|
file: Mutex::new(None),
|
||||||
|
fs: self.fs.clone(),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn link(&self, name: &str, other: &Arc<INode>) -> Result<()> {
|
||||||
|
let other = other.downcast_ref::<Self>().ok_or(FsError::NotSameFs)?;
|
||||||
|
try_std!(fs::hard_link(&other.path, &self.path.join(name)));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unlink(&self, name: &str) -> Result<()> {
|
||||||
|
let new_path = self.path.join(name);
|
||||||
|
if new_path.is_file() {
|
||||||
|
try_std!(fs::remove_file(new_path));
|
||||||
|
} else if new_path.is_dir() {
|
||||||
|
unimplemented!("no remove_dir in sgx_std?")
|
||||||
|
// fs::remove_dir(new_path)?;
|
||||||
|
} else {
|
||||||
|
return Err(FsError::EntryNotFound);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn move_(&self, old_name: &str, target: &Arc<INode>, new_name: &str) -> Result<()> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find(&self, name: &str) -> Result<Arc<INode>> {
|
||||||
|
let new_path = self.path.join(name);
|
||||||
|
if !new_path.exists() {
|
||||||
|
return Err(FsError::EntryNotFound);
|
||||||
|
}
|
||||||
|
Ok(Arc::new(HNode {
|
||||||
|
path: new_path,
|
||||||
|
file: Mutex::new(None),
|
||||||
|
fs: self.fs.clone(),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_entry(&self, id: usize) -> Result<String> {
|
||||||
|
if !self.path.is_dir() {
|
||||||
|
return Err(FsError::NotDir);
|
||||||
|
}
|
||||||
|
unimplemented!("no read_dir in sgx_std?")
|
||||||
|
// FIXME: read_dir
|
||||||
|
|
||||||
|
// self.path
|
||||||
|
// .read_dir()
|
||||||
|
// .map_err(|_| FsError::NotDir)?
|
||||||
|
// .nth(id)
|
||||||
|
// .map_err(|_| FsError::EntryNotFound)?
|
||||||
|
// .file_name()
|
||||||
|
// .into_string()
|
||||||
|
// .map_err(|_| FsError::InvalidParam)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn io_control(&self, cmd: u32, data: usize) -> Result<()> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fs(&self) -> Arc<FileSystem> {
|
||||||
|
self.fs.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any_ref(&self) -> &Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HNode {
|
||||||
|
/// Ensure to open the file and store a `File` into `self.file`,
|
||||||
|
/// return the `MutexGuard`.
|
||||||
|
/// If the type of `self.path` is not file, then return Err
|
||||||
|
fn open_file(&self) -> Result<MutexGuard<Option<fs::File>>> {
|
||||||
|
if !self.path.exists() {
|
||||||
|
return Err(FsError::EntryNotFound);
|
||||||
|
}
|
||||||
|
if !self.path.is_file() {
|
||||||
|
return Err(FsError::NotFile);
|
||||||
|
}
|
||||||
|
let mut maybe_file = self.file.lock().unwrap();
|
||||||
|
if maybe_file.is_none() {
|
||||||
|
let file = try_std!(fs::OpenOptions::new()
|
||||||
|
.read(true)
|
||||||
|
.write(true)
|
||||||
|
.create(true)
|
||||||
|
.open(&self.path));
|
||||||
|
*maybe_file = Some(file);
|
||||||
|
}
|
||||||
|
Ok(maybe_file)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait IntoFsError {
|
||||||
|
fn into_fs_error(self) -> FsError;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoFsError for std::io::Error {
|
||||||
|
fn into_fs_error(self) -> FsError {
|
||||||
|
use std::io::ErrorKind;
|
||||||
|
match self.kind() {
|
||||||
|
ErrorKind::NotFound => FsError::EntryNotFound,
|
||||||
|
ErrorKind::AlreadyExists => FsError::EntryExist,
|
||||||
|
ErrorKind::WouldBlock => FsError::Again,
|
||||||
|
ErrorKind::InvalidInput => FsError::InvalidParam,
|
||||||
|
ErrorKind::InvalidData => FsError::InvalidParam,
|
||||||
|
_ => FsError::NotSupported,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait IntoFsMetadata {
|
||||||
|
fn into_fs_metadata(self) -> Metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoFsMetadata for fs::Metadata {
|
||||||
|
fn into_fs_metadata(self) -> Metadata {
|
||||||
|
use libc;
|
||||||
|
use std::os::fs::MetadataExt;
|
||||||
|
Metadata {
|
||||||
|
dev: self.st_dev() as usize,
|
||||||
|
inode: self.st_ino() as usize,
|
||||||
|
size: self.st_size() as usize,
|
||||||
|
blk_size: self.st_blksize() as usize,
|
||||||
|
blocks: self.st_blocks() as usize,
|
||||||
|
atime: Timespec {
|
||||||
|
sec: self.st_atime(),
|
||||||
|
nsec: self.st_atime_nsec() as i32,
|
||||||
|
},
|
||||||
|
mtime: Timespec {
|
||||||
|
sec: self.st_mtime(),
|
||||||
|
nsec: self.st_mtime_nsec() as i32,
|
||||||
|
},
|
||||||
|
ctime: Timespec {
|
||||||
|
sec: self.st_ctime(),
|
||||||
|
nsec: self.st_ctime_nsec() as i32,
|
||||||
|
},
|
||||||
|
type_: match self.st_mode() & 0xf000 {
|
||||||
|
libc::S_IFCHR => FileType::CharDevice,
|
||||||
|
libc::S_IFBLK => FileType::BlockDevice,
|
||||||
|
libc::S_IFDIR => FileType::Dir,
|
||||||
|
libc::S_IFREG => FileType::File,
|
||||||
|
libc::S_IFLNK => FileType::SymLink,
|
||||||
|
libc::S_IFSOCK => FileType::Socket,
|
||||||
|
_ => unimplemented!("unknown file type"),
|
||||||
|
},
|
||||||
|
mode: self.st_mode() as u16 & 0o777,
|
||||||
|
nlinks: self.st_nlink() as usize,
|
||||||
|
uid: self.st_uid() as usize,
|
||||||
|
gid: self.st_gid() as usize,
|
||||||
|
rdev: self.st_rdev() as usize,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,9 +1,10 @@
|
|||||||
use rcore_fs::vfs::{FileSystem, FsError, INode};
|
use rcore_fs::vfs::{FileSystem, FsError, INode};
|
||||||
use rcore_fs_sefs::SEFS;
|
|
||||||
use rcore_fs_ramfs::RamFS;
|
|
||||||
use rcore_fs_mountfs::MountFS;
|
use rcore_fs_mountfs::MountFS;
|
||||||
|
use rcore_fs_ramfs::RamFS;
|
||||||
|
use rcore_fs_sefs::SEFS;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
use super::hostfs::HostFS;
|
||||||
use super::sgx_impl::SgxStorage;
|
use super::sgx_impl::SgxStorage;
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
@ -13,8 +14,6 @@ lazy_static! {
|
|||||||
// ramfs as rootfs
|
// ramfs as rootfs
|
||||||
let rootfs = MountFS::new(RamFS::new());
|
let rootfs = MountFS::new(RamFS::new());
|
||||||
let root = rootfs.root_inode();
|
let root = rootfs.root_inode();
|
||||||
let bin = root.create("test", FileType::Dir, 0o777)
|
|
||||||
.expect("failed to mkdir: /test");
|
|
||||||
|
|
||||||
// sefs
|
// sefs
|
||||||
let device = Box::new(SgxStorage::new("sefs"));
|
let device = Box::new(SgxStorage::new("sefs"));
|
||||||
@ -22,9 +21,20 @@ lazy_static! {
|
|||||||
.expect("failed to open SEFS");
|
.expect("failed to open SEFS");
|
||||||
|
|
||||||
// mount sefs at /test
|
// mount sefs at /test
|
||||||
|
let bin = root.create("test", FileType::Dir, 0o777)
|
||||||
|
.expect("failed to mkdir: /test");
|
||||||
bin.mount(sefs)
|
bin.mount(sefs)
|
||||||
.expect("failed to mount SEFS");
|
.expect("failed to mount SEFS");
|
||||||
|
|
||||||
|
// HostFS
|
||||||
|
let hostfs = HostFS::new(".");
|
||||||
|
|
||||||
|
// mount HostFS at /host
|
||||||
|
let host = root.create("host", FileType::Dir, 0o777)
|
||||||
|
.expect("failed to mkdir: /host");
|
||||||
|
host.mount(hostfs)
|
||||||
|
.expect("failed to mount HostFS");
|
||||||
|
|
||||||
root
|
root
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ use std::mem::uninitialized;
|
|||||||
mod access;
|
mod access;
|
||||||
mod file;
|
mod file;
|
||||||
mod file_table;
|
mod file_table;
|
||||||
|
mod hostfs;
|
||||||
mod inode_file;
|
mod inode_file;
|
||||||
mod io_multiplexing;
|
mod io_multiplexing;
|
||||||
mod null;
|
mod null;
|
||||||
|
@ -4,7 +4,7 @@ PROJECT_DIR := $(realpath $(CUR_DIR)/../)
|
|||||||
# Dependencies: need to be compiled but not to run by any Makefile target
|
# Dependencies: need to be compiled but not to run by any Makefile target
|
||||||
TEST_DEPS := dev_null
|
TEST_DEPS := dev_null
|
||||||
# Tests: need to be compiled and run by test-% target
|
# Tests: need to be compiled and run by test-% target
|
||||||
TESTS := empty argv hello_world malloc mmap file getpid spawn pipe time truncate readdir mkdir link tls pthread uname rlimit client server server_epoll unix_socket cout cpuid rdtsc
|
TESTS := empty argv hello_world malloc mmap file getpid spawn pipe time truncate readdir mkdir link tls pthread uname rlimit client server server_epoll unix_socket cout hostfs cpuid rdtsc
|
||||||
# Benchmarks: need to be compiled and run by bench-% target
|
# Benchmarks: need to be compiled and run by bench-% target
|
||||||
BENCHES := spawn_and_exit_latency pipe_throughput unix_socket_throughput
|
BENCHES := spawn_and_exit_latency pipe_throughput unix_socket_throughput
|
||||||
|
|
||||||
|
5
test/hostfs/Makefile
Normal file
5
test/hostfs/Makefile
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
include ../test_common.mk
|
||||||
|
|
||||||
|
EXTRA_C_FLAGS :=
|
||||||
|
EXTRA_LINK_FLAGS :=
|
||||||
|
BIN_ARGS :=
|
43
test/hostfs/main.c
Normal file
43
test/hostfs/main.c
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/uio.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int main(int argc, const char* argv[]) {
|
||||||
|
int fd, len;
|
||||||
|
char read_buf[128] = {0};
|
||||||
|
|
||||||
|
// read
|
||||||
|
if ((fd = open("/host/hostfs/sample.txt", O_RDONLY)) < 0) {
|
||||||
|
printf("ERROR: failed to open a file for read\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if ((len = read(fd, read_buf, sizeof(read_buf) - 1)) <= 0) {
|
||||||
|
printf("ERROR: failed to read from the file\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
if (strcmp("HostFS works!", read_buf) != 0) {
|
||||||
|
printf("ERROR: the message read from the file is not expected\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
printf("Read file from hostfs successfully!\n");
|
||||||
|
|
||||||
|
// write
|
||||||
|
if ((fd = open("/host/hostfs/test_write.txt", O_WRONLY | O_CREAT)) < 0) {
|
||||||
|
printf("ERROR: failed to open a file for write\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
const char WRITE_STR[] = "Write to hostfs successfully!";
|
||||||
|
if ((len = write(fd, WRITE_STR, sizeof(WRITE_STR))) <= 0) {
|
||||||
|
printf("ERROR: failed to write to the file\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
printf("Write file to hostfs finished. Please check its content.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
1
test/hostfs/sample.txt
Normal file
1
test/hostfs/sample.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
HostFS works!
|
Loading…
Reference in New Issue
Block a user